【Android笔记】项目优化 & abiFilters

590 阅读6分钟

一、UI优化

打印界面绘制时间方案
黄金分割:将一条线段分为两部分:较长部分与较短部分的比例等于全长与较长部分的比例。其比值约为 1:1.618(或 0.618:1)
百分比:较长部分 a:约 0.618 ---------- 较短部分 b:约 0.382

override fun onResume() {
    super.onResume()
    Log.d("yeTest", "onResume: ")
    val start = System.currentTimeMillis()
    Looper.myQueue().addIdleHandler {
        Log.d("yeTest", "onRender cost: ${System.currentTimeMillis() - start}")
        false
    }
}

1、XML结构

1、纯LinearLayout的性能非常高

尽可能少使用wrap_content属性,会增加计算成本

  1. ConstraintLayout嵌套LinearLayout实现部分功能,性能也比纯Cons约束性能高
  2. Cons套Cons性能损耗较大,尤其是Activity中套Fragment,Linear套Cons要好的多

2、使用include抽取通用部分重用布局

通过布局复用性,减少测量/绘制时间。

  1. 具体操作方法:选中想要抽取的布局—鼠标右键—Refactor—Extract-Layout
  2. 控制include 可见,如果使用了DataBinding要加root,否则不用,
  • include方式可以直接引用,记得要把xml转为databinding
  • findViewByID不能引用根结点,不然会报空crash
 binding.includeSleepOrigin.root.visibility= View.GONE

3、使用Merge

配合Include使用减少最外层级,其会将其中的子元素添加到Merge标签Parent中,布局定位方式受其parent所在定位影响

  1. Android开发merge使用方法详解

4、使用ViewStub

按需加载且减少首次绘制;轻量级的View,即使是Gone也会初始化创建对象,而viewstub则是在需要的时候才手动创建;

2、ViewStub介绍

  1. 效率对比
  • gone也能达到UI优化的效果,但invisible和gone内存占用差不多,viewstub效果较为明显;可能涉及到动态加载的缘故,recycleView能达到优化的效果也是这个
  1. ViewStub只能加载一次,重复加载会导致异常,因为ViewStub只要加载过一次,其自身就会被移除(对应viewstub自身Id),把并自身所包含的内容(对应inflatedId)全部传给父布局
  2. 当ViewStub里面的TextView进行文字改变的时候,宽度发生变化时的处理方案

3、代码样例:

lateinit var vsDemoBinding:ViewStubDemoBinding

override fun initDate() {
    super.initDate()
    inflateViewStub()
    vsDemoBinding.tvTextOne.text="你好"
}

private fun inflateViewStub() {
    if (!binding.vsDemo.isInflated) {
        val vsInflate: View? =  binding.vsDemo.viewStub?.inflate()
        vsDemoBinding= vsInflate?.let {
            DataBindingUtil.getBinding(it)
        }!!
    }
}

2、避免过度绘制

不要在onDraw()中创建新的局部对象,不要在其中进行大量耗时操作;

1、移除默认的windows背景

2、定位类VIEW的选择

性能GuideLine>Space>View,虽然一个纯定位无背景的View,对绘制层级无影响

行为影响
android:background="@color/white"多了一层
android:background="@color/transparent"【#00000000】无影响
android:background="@color/transparent"【#1A000000】多了一层
background+android:visibility="invisible"无影响
  • 一个不带背景的View是不会影响过度绘制的,View.Gone对优化绘制有效,对于加载fragment组中,不考虑预加载的情况,绘制影响主要是第一个显示Fragment,其他的是不是Gone影响不大

二、包体优化

1、png转webp格式

在这里插入图片描述

1、部分超大的图片转换会失败,在文件夹里能非常明显的看出失败的图

image.png

image.png

2、搜索项目中未引用的资源

1、新老版本AndroidStudio删除无用资源方法总结_android studio去除无用资源-CSDN博客

3、纯色图可使用tint着色器改变颜色,非常好用

4、配置项启用混淆和摇树优化

  1. 开启混淆后其实包体积缩得就蛮明显的;
    buildTypes {
        release {
            /*开启混淆且删除无引用代码*/
            minifyEnabled true
            /*删除无引用资源文件  若有反射不建议开这个*/
            shrinkResources true
            //zioalign优化
            zipAlignEnabled true

            
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

5、三方库查看目标源码,将所需的源码集成;

1、Google的aab格式文件支持用户下载根据其机型使用对应的so,挺好用的;

2、简单的自定义View,使用第三方依赖和引导本地其实对包体积影响不大。

3、为何大厂APP如微信、支付宝、淘宝、手Q等只适配了armeabi-v7a/armeabi

  • 默认情况下,Gradle(无论是通过 Android Studio 使用,还是从命令行使用)会针对所有非弃用 ABI 进行构建。要限制应用支持的 ABI 集,请使用 abiFilters
  • Android ABI
android {
    defaultConfig {
        ndk {
            abiFilters 'arm64-v8a', 'x86_64'
        }
    }
}
  • adb查看当前手机CPU架构:adb shell getprop ro.product.cpu.abi

  • 马甲包

abiFilters 'armeabi-v7a', 'arm64-v8a'
  • 设置只编译某些语言
android {
    defaultConfig {
        ...
        // 仅支持 中文
        resConfigs "zh" 
        
        //新版这样写
        resourceConfigurations.addAll(listOf("zh", "en"))
    }
}

4、 Remove Unuseed resources:【Android 安装包优化】移除无用资源 ( 自动移除无用资源 | 直接引用资源 | 动态获取资源 id | Lint 检查资源 )

image.png

三、性能优化

1、内存泄漏

1、检测方案

2、内存泄漏处理

1、Android 引起内存泄漏的几种情况

2、持有未释放例子

  1. 例如内部类对外部类的持有

3、Android内存泄露及解决方法总结

4、Android 内存泄漏

5、ANR 问题分析

2、内存优化:

1、使用MMKV

1、【面试黑洞】Android 的键值对存储有没有最优解? (rengwuxian.com)

  1. 虚拟内存分为用户与内核,mmkv使用内存映射(MMAP),略去了外写内,内写磁盘,直接虚拟内存与磁盘进行映射,重要的指针,操作内存相当于操作文件,免去了冗余读写,使用不需要切线程。即通过内存映射,直接将写入磁盘的操作交给系统,免去app通过与文件系统的交互后再写入磁盘。 2、某些情况存/取Json也很好用

3、内存管理

1、 理解Java的强引用、软引用、弱引用和虚引用

  • 判断时候使用全局Context和弱引用的场景
  • 弱引用是持有一个获取强引用的途径,使用时new一个对象,用完后把new出来的对象置空
public class MainActivity extends AppCompatActivity {
    private MyObject myObject;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MyObject strongReference = new MyObject();
        WeakReference<MyObject> weakReference = new WeakReference<>(strongReference);

        // 获取强引用并持有 
        myObject = weakReference.get();

        // 使用 myObject 判断非null

        // 使用完毕后释放强引用
        myObject = null;
    }
}

2、 安卓性能优化、ANR、内存泄漏等常见问题总结

3、 JVM 内存分析工具 MAT 的深度讲解与实践——入门篇

4、 四种引用类型及引用队列

吐槽

  1. findviewbyId从View树一层层找过去,Binding类会自动生成好,类似一个Hash模式

四、功耗优化

五、启动优化