App 性能优化

RecyclerView

1、onBindViewHolder 运行在 UI 线程,不宜进行逻辑等耗时操作,只适合把数据填入视图;

2、使用 support 包下面的 DiffUtil 局部刷新处理,DiffUtil(内部也是调用局部刷新方法)可以对比数据的差异,是否更改;

DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffCallBack(oldDatas, newDatas), true);
diffResult.dispatchUpdatesTo(mAdapter);

计算在主线程,如果数据量大需要放在线程中,通过 Handler 更新。

局部中的部分刷新

需要通过重写 onBindViewHolder 中带有 payloads 集合参数的方法,如果 payloads 集合不为空,就可以直接进行值更新,否则就调用原本的 onBindViewHolder 方法;

payloads 集合中的值在调用刷新方法时传入,notifyItemChanged(position , "value");,可以是任意类型。

3、给可以复用 holder 的 RecyclerView 设置相同的 holder pool,在相同视图中,不会重新创建 holder;

RecyclerView recyclerView = new RecyclerView(context);
//layoutManager.setRecycleChildrenOnDetach(true);//LinearLayoutManager 需要额外设置
recyclerView.setRecycledViewPool(mPool);

4、数据缓存,直接加载网络数据延迟比较重,加载缓存中的数据;

5、优化代码,尽量减少对象的创建,复用对象资源,比如监听;

6、getExtraLayoutSpace 预加载,RecyclerView 只缓存可见 view,滑动时初次加载会导致延迟卡顿,可以使用预加载处理,改变加载的滑动范围;

7、嵌套 RecyclerView 时,通过 setInitialPrefetchItemCount 设置首次显示个数,只有在嵌套且横向列表才生效;

四级缓存

mAttachedScrap : 缓存可见的 ViewHolder,用于执行 onLayout 的时候 ArrayList 集合
mCacheView:缓存将要隐藏 ViewHolder,下次将要显示的 ViewHolder 先从这个缓存里边获取 ArrayList 集合
mViewChcheExtension:需要用户自己实现的缓存
mRecyclerPool:缓存池,这个用户根据不同的 ViewType 保存缓存池

先从 mAttachedScrap 缓存查找 ViewHolder,然后从 mCacheView 查找,然后从 mViewCacheExtension,然后 mRecyclerPool,如果都没有找到就调用 onCreateViewHolder 新建。

黑白屏

系统加载 app 时,会先显示一个空白页,空白页背景色从应用主题中获取,一般默认是白色。

1、通过给启动页单独设置主题背景或颜色来避免,否则每个活动都会设置成一样的启动图片。

设置背景颜色透明,如果启动的活动耗时长,会导致启动卡顿,需要避免启动活动的耗时操作;

设置背景图片,需要引入多张图片来做屏幕适配,而且无法适配所有屏幕,所以一般使用 LayerDrawable,然后引入资源图片,通过设置偏移量等参数达到适配效果。

2、减少 Application 耗时任务。

把一些非必要的第三方等操作单独初始化,比如 IntentService。

app 启动页优化

apk 体积优化

布局优化

1、减少层次嵌套;

2、减少重复绘制,可以通过系统设置中打开 Show GPU Overdraw 设置查看,红色表示需要优化;

3、使用 include(复用布局)、merge(减少嵌套)、ViewStub(按需求加载,只能执行一次)。

包体积优化

1、使用 tint 避免多次导入资源;

2、资源配置,ndk、resConfigs、代码混淆等;

3、删除无引用资源。

ANR 处理

Activity 响应时间为5秒,广播接受者为10秒,服务为20秒。

发生 ANR 时, 系统会在 /data/anr/ 目录下生成一个 traces.txt 文件,可以通过 adb 命令将其导出到本地查看,一般的 ANR 都能定位到具体类。

1、iowait

日志中显示 CPU 占用情况,其中 io 占用大部分,表示有频繁的读写(数据库、文件)操作;

2、dalvik threads free

显示内存不够,一般会触发 oom 异常。

网络优化

1、减少调用次数跟发送和接收数据包的大小,Android Studio 内置 Monitor 工具,可以查看接收和发送速度;

2、网络缓存;

3、七牛资源图片等加载适合的资源,比如压缩图。

自定义 View

1、避免在 onDraw 绘制方法中做内存分配等耗时操作,因为频繁执行容易导致 oom;

2、尽量减少 onDraw 的调用次数。

webView 优化

1、webView 预加载,生成一个 webViewPool,通过 MutableContextWrapper 去替换不同上下文复用,减少创建时间;

webView 只能在主线程初始化,把 webView 放进 Handler 消息队列中去(Looper.myQueue().addIdleHandler()),虽然也是在 UI 线程,但是尽量避免造成卡顿。

2、通过 shouldInterceptRequest 监听请求,由客户端下载好在填充进 webResourceResponse 中;

        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, String url) { 
                if (checkImageRequest(url)) {
                    File imageFile = Glide.with(view.getContext())
                            .asFile()
                            .load(url)
                            .submit()
                            .get();

                    return WebResourceResponse(
                            "image/png,*/*",
                            "UTF-8",
                            new FileInputStream(imageFile)
                    );
                }
            return super.shouldInterceptRequest(view, url);
        }

假设拦截为图片,可以通过本地 Glide 加载缓存,避免多次重复加载。

3、加载本地模板,通过 JS 方法注入数据,过程简单,但是比较耗费流量。

反射

频繁使用反射,调用方法,需要进行大量查找,影响效率。

android 系统 xml 布局就是通过解析标签,然后反射调用组件方法实现,比较具备扩展性,不过影响性能,所以一般代码创建对象速度会更快,不过可读性很差。

可以通过资源缓存,避免多次反射来优化速度。

Fragment 优化

创建方式

1、构造参数(异常销毁后,比如 ConfigChange 屏幕旋转,导致重建时会抛出异常,导致程序崩溃)

2、静态工厂(传入的参数保存在 arguments)

配置旋转属性 

android:configChanges="orientation|keyboard|keyboardHidden"

在改变屏幕方向时,不执行onCreate(),而是直接执行 onConfigurationChanged(),避免重复初始化

posted on 2022-05-05 23:56  翻滚的咸鱼  阅读(471)  评论(0编辑  收藏  举报