目录
- 1)布局优化
- 2)绘制优化
- 3)ListView和Bitmap优化
- 4)线程优化
- 5)App启动优化
- 6)内存优化
- 7)电量优化
- 8)网络优化
- 9)性能优化工具
- 10)响应速度优化和ANR日志分析
- 11)一些性能优化建议
1)布局优化
布局优化就是尽量减少布局文件的层数。
方式 | 说明 |
---|---|
去掉其他不必要的背景 | overdraw (过渡绘制)的关键点在于一个像素被绘制了几次 |
<include> | 可以将一个指定的布局文件加载到当前布局文件中 |
<merge> | 一般和<include>一起使用,可以少一层嵌套 |
ViewStub | 继承View,更轻量级且宽高为0。可以做到按需加载以提升性能,而不是界面初始化的时候加载,如网络异常的界面。 |
<include layout="@layout/merge_button">
// ~res/layout/merge_button.xml
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</merge>
<ViewStub
android:id="@+id/stub_import"
android:layout="layout/xxx"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
//通过setVisibility后,ViewStub就会被他内部的布局替换掉
(ViewStub)findViewById(R.id.stub_import).setVisibility(View.VISIBLE)
工具 | 说明 |
---|---|
Layout Inspector | Tools -> Android -> Layout Inspector |
调试GPU过度绘制功能 | 手机-开发者选项 |
2)绘制优化
Android 屏幕刷新机制
android屏幕刷新显示机制
Google的官方性能标准,View的绘制帧率保持在60fps为最佳,这就要求每一帧的绘制时间不超过16ms(1000/60)。
丢帧,卡顿
View的onDraw()要避免大量操作
- 因为onDraw()会被频繁调用,所以此方法内不要创建局部变量。大量局部变量会造成频繁GC,频繁GC也会造成卡顿,因为GC会中断程序运行。
- onDraw()不要做耗时任务
3)ListView和Bitmap优化
请参阅之前笔记。
- ListView 避免在getView()中执行耗时操作,其次快速滑动时无需开启大量异步任务去请求图片。
- Bitmap 图片压缩和缓存
4)线程优化
- 采用线程池,避免大量的Thread。
5)App启动优化
5.1) 在Application初始化的时候执行了大量的操作
- 通过traceview检查方法执行时长
- 采用IntentService在线程中加载操作
//~ MainApplication.java
public void onCreate()
{
Debug.startMethodTracing("Application");
super.onCreate();
//ARouter init
if (BuildConfig.DEBUG) { // 这两行必须写在init之前,否则这些配置在init过程中将无效
ARouter.openLog(); // 打印日志
ARouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
}
ARouter.init(this);
//jpush init
JPushInterface.init(this);
//shareSDK init
ShareSDK.initSDK(this);
//RNinit
SoLoader.init(this, /* native exopackage */ false);
//LeakCanary
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
LeakCanary.install(this);
Debug.stopMethodTracing();
}
运行后可以在sdcard中找到trace
打开 也可以Monitor打开
5.2)首屏加载不要耗时过长
App没有完全起来时, 屏幕会一直显示一块空白的窗口。
Android最新的Material Design建议我们使用一个placeholder UI来展示给用户直至App加载完毕
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 底层白色 -->
<item android:drawable="@android:color/white" />
<!-- 顶层Logo居中 -->
<item>
<bitmap
android:gravity="center"
android:src="@drawable/ic_launcher" />
</item>
</layer-list>
<style name="SplashTheme" parent="AppTheme">
<item name="android:windowBackground">@drawable/logo_splash</item>
</style>
//启动页
public class SplashActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startActivity(new Intent(this,WelcomeActivity.class));
finish();
}
}
<activity android:name=".ui.SplashActivity"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
6)内存优化
内存抖动:短时间大量的对象被创建又释放,会造成锯齿状内存,产生频繁的GC,造成卡顿。
解决:1-避免循环创建对象;2-onDraw不要创建对象;3-对于无法避免可使用对象池。
一个永远不会被使用的对象,因为一些引用没有断开,没有满足GC条件,导致不会被回收
- 静态变量(如一个静态变量持有了Activity的引用,将会导致Activity无法销毁)
- 非静态内部类(非静态内部类如Handler或Runnable会维持一个到外部类实例的引用,可以使用静态内部类和WeakReference代替)
- Handler临时性内存泄露(非静态的Handler持有外部如Activity引用,而MQ又持有Handler的引用)
- 资源未关闭( Cursor、SQLiteDatabase,io流)
- 广播和监听器没有反注册(unregister,removelistener)
- adapter未使用contentView缓存
7)电量优化
adb bugreport > bugreport.txt
使用 Battery Historian.来导入bugreport通过图形界面查看电量消耗。
- 优化网络请求
- 监听手机充电状态(如手机充电时进行一些文件上传,用户数据同步等操作)
IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = context.registerReceiver(null, ifilter);
int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
status == BatteryManager.BATTERY_STATUS_FULL;
- 6.0 Doze模式会延迟后台网络或cpu来减少电量消耗
8)网络优化
- Android Porfiler监控网络请求
- 更好的接口设计,更合理的接口调用。还可以打包网络请求
- request Cache-Control
- 弱网测试
- 图片size
9)性能优化工具
性能优化工具- StrictMode -严格模式
// 分别为MainThread和VM设置Strict Mode
if (BuildConfig.DEBUG) {
//线程策略
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectAll() //侦测一切潜在违规
.detectDiskReads() //侦测磁盘读
.detectDiskWrites() //侦测磁盘写
.detectNetwork() //侦测网络操作
.detectCustomSlowCalls() //侦测自定义的耗时操作
.penaltyDialog() //违规时,向开发者显示一个恼人的Dialog对话框
.build());
//虚拟机策略
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects() //当显式中止方法调用之后,假如可被Closeable类或其他的对象没有被关闭。
.detectLeakedRegistrationObjects()
.detectActivityLeaks()
.penaltyLog() //违规时,将违规信息写入系统日志
.build());
}
-
Lint检查
Analyze->Inspect Code
Lint检查
-
HierarchyViewer的替代Layout Inspector
Tools -> Android -> Layout Inspector
Layout Inspector
- TraceViewer
-
Android Porfiler
Android Porfiler
-
调试GPU过度绘制功能 手机-开发者选项
10)响应速度优化和ANR日志分析
组件 | ANR时间 |
---|---|
Activity | 5秒 |
BroadcastReceiver | 10秒 |
Service | 20秒 |
adb pull /data/anr/traces.txt 文件可以看到ANR日志
11)一些性能优化建议
- 避免创建过多对象
- 避免过多使用枚举,枚举占用内存空间大
- 常量使用static final修饰
- 使用Android特有数据结构,如SpaceArray何Pair等
- 适当使用软引用和弱引用
- 内存缓存和磁盘缓存
- 尽量采用静态内部类,避免由于内部类导致的内存泄漏
参考资料
Android应用优化最全指南和清单
Android App优化之性能分析工具
Android APP 性能优化的一些思考
---`
网友评论