Android 音乐APP(二)启动白屏优化、定位当前播放歌曲

简介: Android 音乐APP(二)启动白屏优化、定位当前播放歌曲

效果图

20201015100955815.gif


Android 音乐APP 启动优化



前言


Android应用冷启动时,又会短暂的黑屏或者白屏,然后才会进入主页面,黑屏是在Android版本低的时候才会出现,比如Android4.4、5.0。而现在的Android版本出现的就是白屏。这个虽然不应用功能的使用,但是对用户来说体验感并不好。那么怎么解决这个问题呢?我相信很多的博客都有这个方面的讲解,但是真正有良好体验的比较少,下面的这种也是参考了网易云音乐的启动方式。


正文


  为了形成对比,先来看一下网易云的启动。

image.gif


可以看到当点击桌面的图标时,马上进入启动页,没有卡顿没有白屏,那么你再运行一下Good Music。


image.gif


可以看到打开速度也是很快的,但是你注意到这个白屏了吗?这样就不是很好的用户体验。那么网易云音乐是怎么处理这个白屏的呢?下面就来告诉你要怎么做。


① 新建启动页

 

每个APP都会有启动页,启动页有什么用呢?体现APP的功能定位、初始化基础的数据、网络或者本地数据的存储、商务广告展示等一些操作。当然现在我们没有那么多的要求,只要能够去掉这个白屏就万事大吉了。那么要新建一个Empty Activity。取名为SplashActivity。


然后进入AndroidManifest.xml。将MainActivity下的intent-filter放到SplashActivity下,作为打开应用进入的第一个页面。


20201015094417366.png


② 新建样式


然后新建一个样式给SplashActivity使用。


在drawable下新建一个splash_bg.xml,里面代码如下:


<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@android:color/black"></item>
    <item>
        <bitmap
            android:gravity="center"
            android:src="@drawable/icon_logo" />
    </item>
</layer-list>

20201015094701314.png


icon_logo是一个图标,如果你的图标需要高像素的话,你就在res下新建一个drawable-xhdpi / drawable-xxhdpi。我是新建了一个drawable-xhdpi,至于这个图标你可以自己决定,没有的话就到我的源码里面去拿。下面进入到styles.xml中,在里面增加如下的代码:


  <!--启动页主题样式-->
    <style name="SplashTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowFullscreen">true</item>
        <item name="android:windowBackground">@drawable/splash_bg</item>
    </style>


下面再到AndroidMainfest.xml中设置样式。


20201015095359247.png


到这一步,你再运行就不会有白屏了。启动后会一直停留在SplashActivity这里。


③ 增加动画


那么现在启动页和白屏就搞定了,我也不想让我的启动页这么枯燥,所以我要加一个动画的效果进去。首先进入activity_splash.xml。里面的代码如下:


<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical"
        tools:context=".ui.SplashActivity">
        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/dp_160">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Good Music"
                android:textColor="@color/white"
                android:textSize="@dimen/sp_24" />
            <TextView
                android:id="@+id/tv_translate"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@color/black"
                android:text="Good Music"
                android:textColor="@color/black"
                android:textSize="@dimen/sp_24" />
        </RelativeLayout>
    </LinearLayout>
</layout>


如果不出意外的话,你看到的应该是只有黑色背景和一个图标。


那么进入到SplashActivity。

20201015100130106.png


里面定义了一个位移动画,在onCreate中调用initView方法。

那么这个方法就是最重要的。

  /**
     * 初始化
     */
    private void initView() {
        ActivitySplashBinding binding = DataBindingUtil.setContentView(SplashActivity.this, R.layout.activity_splash);
        TextView tvTranslate = binding.tvTranslate;
        tvTranslate.post(new Runnable() {
            @Override
            public void run() {
                //通过post拿到的tvTranslate.getWidth()不会为0。
                translateAnimation = new TranslateAnimation(0, tvTranslate.getWidth(), 0, 0);
                translateAnimation.setDuration(1000);
                translateAnimation.setFillAfter(true);
                tvTranslate.startAnimation(translateAnimation);
                //动画监听
                translateAnimation.setAnimationListener(new Animation.AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {
                    }
                    @Override
                    public void onAnimationEnd(Animation animation) {
                        //动画结束时跳转到主页面
                        startActivity(new Intent(SplashActivity.this,MainActivity.class));
                    }
                    @Override
                    public void onAnimationRepeat(Animation animation) {
                    }
                });
            }
        });
    }


首先通过databinding拿到控件,然后通过.post新起一个线程,这个时候就能获取到TextView的实际宽度,而不再是0。为什么要获取宽度呢。因为我在布局中放了一个相对布局,里面有两个TextView,第二个盖住了第一个。第二个是黑色背景黑色文字,但是它的宽高和第一个TextView是一样的。而我要做的效果是文字逐渐出现,从左至右,所以只要将第二个TextView向右位移TextView的宽度即可。移动时间为1s,然后监听这个动画,当动画结束时,进入MainActivity,水道渠成。那么现在运行一下:


20201015100955815.gif


GIF放上来可能有点卡帧,但是在手机上效果是相当的nice。

④ 定位当前播放歌曲


常规的我们播放音乐列表里面点击一首歌进行播放,然后这个时候会上下滑动列表,然后就会显现一个定位按钮,点击之后定位到当前播放的这首歌的位置。这在实际中是很常用的,不是吗!下面来操作起来。首先进入activity_local_music.xml,然后给之前扫描音乐的按钮增加一个id并修改点击按钮所触发的方法。


20201015103809562.png


然后在创建一个location_music.xml。里面的代码如下:


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="@dimen/dp_20"
    android:height="@dimen/dp_20"
    android:tint="#000000"
    android:viewportWidth="24.0"
    android:viewportHeight="24.0">
    <path
        android:fillColor="@android:color/white"
        android:pathData="M12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM20.94,11c-0.46,-4.17 -3.77,-7.48 -7.94,-7.94L13,1h-2v2.06C6.83,3.52 3.52,6.83 3.06,11L1,11v2h2.06c0.46,4.17 3.77,7.48 7.94,7.94L11,23h2v-2.06c4.17,-0.46 7.48,-3.77 7.94,-7.94L23,13v-2h-2.06zM12,19c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7z" />
</vector>


这是一个定位图标。


回到activity_local_music.xml

20201015104020687.png


      <!--定位当前播放音乐按钮-->
            <com.google.android.material.button.MaterialButton
                android:id="@+id/btn_location_play_music"
                style="@style/Widget.MaterialComponents.Button.UnelevatedButton"
                android:layout_width="@dimen/dp_28"
                android:layout_height="@dimen/dp_28"
                android:layout_alignParentRight="true"
                android:layout_alignParentBottom="true"
                android:layout_margin="@dimen/dp_36"
                android:insetLeft="@dimen/dp_0"
                android:insetTop="@dimen/dp_0"
                android:insetRight="@dimen/dp_0"
                android:insetBottom="@dimen/dp_0"
                android:onClick="onClick"
                android:textSize="@dimen/sp_14"
                android:theme="@style/Theme.MaterialComponents.Light.NoActionBar"
                android:visibility="gone"
                app:backgroundTint="@color/white"
                app:cornerRadius="@dimen/dp_20"
                app:icon="@drawable/music_location"
                app:iconGravity="textStart"
                app:iconPadding="0dp"
                app:iconTint="@color/black" />


这里我用了MaterialButton,如果不知道这个是什么,可以看一下这一篇文章Material UI控件之MaterialButton,进入LocalMusicActivity,修改scanLocalMusic方法为onClick。


/**
     * 页面点击事件
     * @param view 控件
     */
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_scan_local_music:
                //扫描本地音乐
                permissionsRequest();
                break;
            case R.id.btn_location_play_music:
                //定位当前播放歌曲
                break;
            default:
                break;
        }
    }


通过这个方法来管理当前页面所有按钮的点击事件。下面在initView方法中增加对RecyclerView的滚动监听。

rvMusic.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    //暂停
                    showLocationMusic(false);
                } else if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
                    //滑动
                    showLocationMusic(true);
                }
            }
        });


一共有两种状态,滑动和暂停,同时调用一个showLocationMusic方法。


  /**
     * 显示定位当前音乐图标
     */
    private void showLocationMusic(boolean isScroll) {
        //先判断是否存在播放音乐
        if (oldPosition != -1) {
            if (isScroll) {
                //滑动
                btnLocationPlayMusic.setVisibility(View.VISIBLE);
            } else {
                //延时隐藏  Android 11(即API 30:Android R)弃用了Handler默认的无参构造方法,所以传入了Looper.myLooper()
                new Handler(Looper.myLooper()).postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        btnLocationPlayMusic.setVisibility(View.GONE);
                    }
                }, 2000);
            }
        }
    }


相信你应该已经懂了。当页面有歌曲播放时,滑动列表会显示定位按钮,停止2s后会隐藏定位按钮,下面就是要在点击定位按钮时,定位到当前播放歌曲,虽然目前还没有播放过歌曲。只是一个选中位置。通过下面两行代码就可以实现:


LinearLayoutManager linearLayoutManager = (LinearLayoutManager) rvMusic.getLayoutManager();
linearLayoutManager.scrollToPositionWithOffset(oldPosition, 0);

2020101510505311.png


下面运行一下:


20201015105339755.gif


结语


OK,这边文章虽然不长,但是讲述的东西还是有用的,开发是一个精益求精的过程,并不是写的越快就越好,感谢你的阅读。



相关文章
|
6月前
|
缓存 移动开发 JavaScript
如何优化UniApp开发的App的启动速度?
如何优化UniApp开发的App的启动速度?
1054 139
|
6月前
|
移动开发 JavaScript 应用服务中间件
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
784 5
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
7月前
|
存储 消息中间件 人工智能
【08】AI辅助编程完整的安卓二次商业实战-修改消息聊天框背景色-触发聊天让程序异常终止bug牵涉更多聊天消息发送优化处理-优雅草卓伊凡
【08】AI辅助编程完整的安卓二次商业实战-修改消息聊天框背景色-触发聊天让程序异常终止bug牵涉更多聊天消息发送优化处理-优雅草卓伊凡
496 10
【08】AI辅助编程完整的安卓二次商业实战-修改消息聊天框背景色-触发聊天让程序异常终止bug牵涉更多聊天消息发送优化处理-优雅草卓伊凡
|
JavaScript 前端开发 Android开发
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
482 13
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
|
11月前
|
Android开发 数据安全/隐私保护 开发者
Android自定义view之模仿登录界面文本输入框(华为云APP)
本文介绍了一款自定义输入框的实现,包含静态效果、hint值浮动动画及功能扩展。通过组合多个控件完成界面布局,使用TranslateAnimation与AlphaAnimation实现hint文字上下浮动效果,支持密码加密解密显示、去除键盘回车空格输入、光标定位等功能。代码基于Android平台,提供完整源码与attrs配置,方便复用与定制。希望对开发者有所帮助。
210 0
|
7月前
|
存储 前端开发 安全
实现“永久登录”:针对蜻蜓Q系统的用户体验优化方案(前端uni-app+后端Laravel详解)-优雅草卓伊凡
实现“永久登录”:针对蜻蜓Q系统的用户体验优化方案(前端uni-app+后端Laravel详解)-优雅草卓伊凡
300 5
|
10月前
|
存储
《仿盒马》app开发技术分享--未完成订单列表展示逻辑优化(61)
上一节我们实现订单与优惠券的联合提交时,我去到订单列表页面查看生成的订单信息,发现现在的订单从信息展示到价格计算全都是有问题的。所以紧急的把对应的问题修改一下。
277 70
|
JavaScript Linux 网络安全
Termux安卓终端美化与开发实战:从下载到插件优化,小白也能玩转Linux
Termux是一款安卓平台上的开源终端模拟器,支持apt包管理、SSH连接及Python/Node.js/C++开发环境搭建,被誉为“手机上的Linux系统”。其特点包括零ROOT权限、跨平台开发和强大扩展性。本文详细介绍其安装准备、基础与高级环境配置、必备插件推荐、常见问题解决方法以及延伸学习资源,帮助用户充分利用Termux进行开发与学习。适用于Android 7+设备,原创内容转载请注明来源。
3610 77
|
10月前
|
数据库
《仿盒马》app开发技术分享-- 优惠券逻辑优化(58)
我们已经实现了优惠券的领取和展示,现在已经趋近于一个完整的电商应用了,但是这时候问题又来了,我们领取完优惠券之后,我们的新用户优惠券模块依然存在,他并没有消失,既然我们是从云数据库中查询的数据,那么我们需要找到一个字段跟他对应起来,来实现新用户领券后关闭这个模块的展示,同时我们在未登录的时候他也要保持隐藏,登录后能实现优惠券的领取。然后在结算的时候得出有几张符合的券能用
142 9
|
11月前
|
缓存 编解码 Android开发
Android内存优化之图片优化
本文主要探讨Android开发中的图片优化问题,包括图片优化的重要性、OOM错误的成因及解决方法、Android支持的图片格式及其特点。同时介绍了图片储存优化的三种方式:尺寸优化、质量压缩和内存重用,并详细讲解了相关的实现方法与属性。此外,还分析了图片加载优化策略,如异步加载、缓存机制、懒加载等,并结合多级缓存流程提升性能。最后对比了几大主流图片加载框架(Universal ImageLoader、Picasso、Glide、Fresco)的特点与适用场景,重点推荐Fresco在处理大图、动图时的优异表现。这些内容为开发者提供了全面的图片优化解决方案。
420 1