一、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属性,会增加计算成本
- ConstraintLayout嵌套LinearLayout实现部分功能,性能也比纯Cons约束性能高
- Cons套Cons性能损耗较大,尤其是Activity中套Fragment,Linear套Cons要好的多
2、使用include抽取通用部分重用布局
通过布局复用性,减少测量/绘制时间。
- 具体操作方法:选中想要抽取的布局—鼠标右键—Refactor—Extract-Layout
- 控制include 可见,如果使用了DataBinding要加root,否则不用,
- include方式可以直接引用,记得要把xml转为databinding
- findViewByID不能引用根结点,不然会报空crash
binding.includeSleepOrigin.root.visibility= View.GONE
3、使用Merge
配合Include使用减少最外层级,其会将其中的子元素添加到Merge标签Parent中,布局定位方式受其parent所在定位影响
4、使用ViewStub
按需加载且减少首次绘制;轻量级的View,即使是Gone也会初始化创建对象,而viewstub则是在需要的时候才手动创建;
- gone也能达到UI优化的效果,但invisible和gone内存占用差不多,viewstub效果较为明显;可能涉及到动态加载的缘故,recycleView能达到优化的效果也是这个
- ViewStub只能加载一次,重复加载会导致异常,因为ViewStub只要加载过一次,其自身就会被移除(对应viewstub自身Id),把并自身所包含的内容(对应inflatedId)全部传给父布局
- 当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、部分超大的图片转换会失败,在文件夹里能非常明显的看出失败的图
2、搜索项目中未引用的资源
1、新老版本AndroidStudio删除无用资源方法总结_android studio去除无用资源-CSDN博客
3、纯色图可使用tint着色器改变颜色,非常好用
4、配置项启用混淆和摇树优化
- 开启混淆后其实包体积缩得就蛮明显的;
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 检查资源 )
- 减少ENUM的使用,每减少一个ENUM可以减少大约1.0到1.4 KB的大小
- APK瘦身属性——android:extractNativeLibsandroid:extractNativeLibs - 掘金
三、性能优化
1、内存泄漏
1、检测方案
2、内存泄漏处理
2、持有未释放例子
- 例如内部类对外部类的持有
5、ANR 问题分析
2、内存优化:
1、使用MMKV
1、【面试黑洞】Android 的键值对存储有没有最优解? (rengwuxian.com)
- 虚拟内存分为用户与内核,mmkv使用内存映射(MMAP),略去了外写内,内写磁盘,直接虚拟内存与磁盘进行映射,重要的指针,操作内存相当于操作文件,免去了冗余读写,使用不需要切线程。即通过内存映射,直接将写入磁盘的操作交给系统,免去app通过与文件系统的交互后再写入磁盘。 2、某些情况存/取Json也很好用
3、内存管理
- 判断时候使用全局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;
}
}
3、 JVM 内存分析工具 MAT 的深度讲解与实践——入门篇
4、 四种引用类型及引用队列
吐槽
- findviewbyId从View树一层层找过去,Binding类会自动生成好,类似一个Hash模式