Android优化_Aron
2019-07-12 10:01:03 1 举报
AI智能生成
为你推荐
查看更多
优化建议
作者其他创作
大纲/内容
Android优化_Aron
调试
耗时
共享参数
3次写入 平均每次11.8ms
android.app.SharedPreferencesImpl$EditorImpl.commit\t3\t34.133ms
18次 212.5ms
日期格式化
3次时间格式化 平均每次16.9ms
java.text.DateFormat.format\t3\t48.366ms
18次 305.8ms
读文件大小
file.length
大约1ms
调试Debug
logcat定位错误
关键字
Caused by
fatal
FATAL
Fatal
ANR
广播
BroadcastQueue: Timeout
SCREEN_OFF
包名
jv.ink.launcherink
反向过滤log
^(?!.*(http|GET)).*$
过滤掉http和GET
打印log
打印方法调用堆栈
Thread.currentThread().getStackTrace();
new Exception(\"this is a log\").printStackTrace();
简介trace.txt
//开头显示进程号、ANR发生的时间点和进程名称----- pid 21786 at 2016-01-01 09:47:34 -----Cmd line: com.example.androidtest
\"main\" prio=5 tid=1 Sleeping | group=\"main\" sCount=1 dsCount=0 obj=0x7285da50 self=0xb47f6a00//sysTid是线程号,主线程的线程号和进程号相同 | sysTid=21786 nice=0 cgrp=bg_non_interactive sched=0/0
//JDWP线程是支持虚拟机调试的线程,不需要关心\"JDWP\" daemon prio=5 tid=4 WaitingInMainDebuggerLoop
/线程名称后面标识有daemon,说明这是个守护线程\"HeapTaskDaemon\" daemon prio=5 tid=5 Blocked
| held mutexes= at java.lang.Thread.sleep!(Native method) - sleeping on <0x02b0b44c> (a java.lang.Object) at java.lang.Thread.sleep(Thread.java:1031) - locked <0x02b0b44c> (a java.lang.Object) at java.lang.Thread.sleep(Thread.java:985)
线程状态
anr/trace文件错误定位
ANR关键字
held by thread
查找Block
held by tid
cmd line
查看所有的进程
Blocked
sleeping on
waiting on
event log中检索 am_anr 关键字
原因
CPU使用过高、事件没有得到及时的响应、死锁等
AS的debug
Evaluate Expression计算表达式
Alt+F8
修改变量的值
可快速调试一些其他情况
Esc 关闭窗口
处理混淆后的log
该工具位于 <android-sdk>/tools/proguard/bin/ 目录下。里面的 proguardgui.bat 为 GUI 工具,
1) 运行 proguardgui.bat2) 从左边的菜单选择 “ReTrace”3) 在上面的 mapping 文件中选择你的 mapping 文件 ,在下面输入框输入要还原的代码4) 点击 “ReTrace!” 按钮
输入
at eink.plugin.mediacontrol.f$1.handleMessage(SourceFile:114)at android.os.Handler.dispatchMessage(Handler.java:102)at android.os.Looper.loop(Looper.java:136)at android.app.ActivityThread.main(ActivityThread.java:5017)
结果
at eink.plugin.mediacontrol.global.GlobalPlayerController$1.void handleMessage(android.os.Message)(SourceFile:114)at android.os.Handler.dispatchMessage(Handler.java:102)at android.os.Looper.loop(Looper.java:136)at android.app.ActivityThread.main(ActivityThread.java:5017)
retrace.bat 为命令行工具, 把 mapping 文件和 要还原的堆栈信息保存在 stacktrace 文件中,然后把这两个文件复制到 retrace.bat 目录下,运行如下命令即可。retrace.bat -verbose mapping.txt stacktrace.txt > out.txt 这里就对ProGuard 的一个小功能简单的介绍下。方便自己和大家的学习。
retrace.bat -verbose mapping.txt stacktrace.txt > out.txt
Native (NE)
原始的linux,对于用户进程崩溃之后,处理方式有2种:直接终止进程;输出coredump再终止进程。 而在Android,为了方便调试,在收到崩溃信号后,会先输出tombstone,然后在根据设置是否抓取coredump,最后再终止进程
mtk平台上会在这基础上将coredump及其他关键信息打包成一个db文件,位于mtklog下的aee_exp中,db文件的生成前提条件是eng版本或是user版本打开了mtklog
Native Excption
SIGSEGV(段错误),SIGBUS(内存访问错误),SIGFPE(算数异常)属于这种信号。2、进程调用的库发现错误,给自己发送中止信号,默认情况下,该信号会终止进程。在本文中,SIGABRT(中止进程)属于这种信号
AEE DB 和 Coredump
log中的core-dump
超时5秒机制
startTime
kDefaultTimeOutMs
TimeOut
位置
cat /proc/sys/kernel/core_pattern
cat /proc/sys/kernel/core_pattern/data/corefile/core-%e-%p@%t
/sbin/sysctl kernel.core_pattern
AndroidLog
signal
SIGSEGV
疑似地址映射错误
典型的多线程引起的问题
SIGABRT
/system/bin/tombstoned: received crash request for pid 15049
/system/bin/tombstoned: Tombstone written to: /data/tombstones/tombstone_07
backtrace
如果crash发生在oat文件里面,所以用下面的命令把oat文件dump出来,先查看下汇编代码:adb shell oatdump --oat-file= /system/framework/arm64/boot.oat > oatdump_boot.txtadb shell oatdump --oat-file= /system/framework/arm64/boot-framework.oat > oatdump_boot-framework.txt
网络优化
磁盘优化
IO读写优化
数据库频繁读写可以视情况改成 事务处理
beginTransaction
setTransactionSuccessful()
endTransaction()
Serializable是Java中的序列化接口,其使用起来简单但是开销很大,在序列化和反序列化过程中需要大量的I/O操作。而Parcelable是Android中的序列化方式,因此更适合用在Android平台上,它的缺点就是使用起来稍微麻烦点,但是它的效率很高。
内存优化
代码获取内存
@TargetApi(Build.VERSION_CODES.KITKAT) public static int getMemory() { Debug.MemoryInfo memoryInfo = new Debug.MemoryInfo(); Debug.getMemoryInfo(memoryInfo); // dalvikPrivateClean + nativePrivateClean + otherPrivateClean; int totalPrivateClean = memoryInfo.getTotalPrivateClean(); // dalvikPrivateDirty + nativePrivateDirty + otherPrivateDirty; int totalPrivateDirty = memoryInfo.getTotalPrivateDirty(); // dalvikPss + nativePss + otherPss; int totalPss = memoryInfo.getTotalPss(); // dalvikSharedClean + nativeSharedClean + otherSharedClean; int totalSharedClean = memoryInfo.getTotalSharedClean(); // dalvikSharedDirty + nativeSharedDirty + otherSharedDirty; int totalSharedDirty = memoryInfo.getTotalSharedDirty(); // dalvikSwappablePss + nativeSwappablePss + otherSwappablePss; int totalSwappablePss = memoryInfo.getTotalSwappablePss(); int total = totalPrivateClean + totalPrivateDirty + totalPss + totalSharedClean + totalSharedDirty + totalSwappablePss; return total ; }
图片大小优化
BitmapFactory优化
内存分析工具
MAT
MemoryAnalysisTool
内存泄漏 LeakMemoryleakcanary
build.gradle中配置debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.2' releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.2'
Project Structure -- app -- Dependencies 点击加号搜索
leakcanary-android
Application的onCreate中调用
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);
内存问题分析
粗略判断是否存在内存泄漏
工具Android Studio
Android Monitor --> 左侧System Information --> Memory Usage
查看Objects
log关键字
lowmemorykiller: Error opening /proc/8295/oom_score_adj; errno=2
内存占用
adb shell
procrank
可以查看 分应用
adb shell procrank
VSS- Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)RSS- Resident Set Size 实际使用物理内存(包含共享库占用的内存)PSS- Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)USS- Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS
案例分析
GC问题 Object.finalize
深入分析Object.finalize方法的实现原理
常见泄漏
Handler持有Context或Activity等不同生命周期的对象
资源性流 未关闭
注册 忘记反注册
WebView
android:process
不正确的单例模式 传入Activity的Context
参数传的APP的context
匿名类和非静态内部类
性能/CPU优化
性能分析工具
Android官方
StrictMode
严格模式主要用来做主线程优化分析
代码中APP或Activity中onCreate中加入最好加个判断区分Debug模式
if (BuildConfig.DEBUG) { // 针对线程的相关策略 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectDiskReads() .detectDiskWrites() .detectNetwork() // or .detectAll() for all detectable problems .penaltyLog() .build()); // 针对VM的相关策略 StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() .detectLeakedSqlLiteObjects() .detectLeakedClosableObjects() .penaltyLog() .penaltyDeath() .build()); }
if (true) {// if (BuildConfig.DEBUG) { // 针对线程的相关策略 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectDiskReads() .detectDiskWrites() .detectNetwork() // or .detectAll() for all detectable problems .penaltyLog() .build()); // 针对VM的相关策略 StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() .detectLeakedSqlLiteObjects() .detectLeakedClosableObjects() .penaltyLog() .penaltyDeath() .build()); }
开发者选项开启严格模式
Systrace
使用
4.3以上版本
cd android-sdk/platform-tools/systrace
python systrace.py --time=10 -o mynewtrace.html sched gfx view wm
4.2及以下
adb shell stopadb shell start
停止和重启
Hierarchy Viewer
AndroidSDK发布的工具,位置在tools文件夹下,名为hierarchyviewer.bat
TraceView
CPU线程分析
AS Monitor --> CPU即TraceView
Start Methods Tracing
APP内执行一些操作
Stop
top -m 10 -s cpu
(-m显示最大数量,-s 按指定行排序)
界面卡顿
FPS
adb shell dumpsys gfxinfo <package | pid>
前提:开发者选项=>GPU呈现模式分析确保打开=>在adb shell dumpsys gfxinfo中or 在屏幕上显示为线型图
adb shell dumpsys gfxinfo com.android.launcher3
dumpsys gfxinfo com.android.launcher3
Draw: 表示在Java中创建显示列表部分中,OnDraw()方法占用的时间。Prepare:表示程序准备时间Process:表示渲染引擎执行显示列表所花的时间,view越多,时间就越长Execute:表示把一帧数据发送到屏幕上排版显示实际花费的时间。Draw + Prepare+Process + Execute = 完整显示一帧 ,这个时间要小于16ms才能保存每秒60帧
可绘制出折线图和柱状图
文件读取优化
JSONArray和JSONObject
耗时1.3s
耗时1.18s
改成解析2个字段
耗时优化不明显
改成gson或者fastJson
启动优化
计算启动时间
adb shell am force-stop com.android.jv.ink.launcherink
am force-stop com.android.launcher3
am force-stop com.transsion.hilauncher
adb shell am start -W com.coolyota.logreport/com.coolyota.logreport.LogSettingActivity
am start -W com.android.launcher3/.Launcher
am start -W -p com.android.launcher3 -c android.intent.category.HOME
am start -W -p com.transsion.hilauncher -c android.intent.category.HOME
adb shell am start -W com.android.jv.ink.launcherink/.ui.home.JvMainActivity
背屏冷启动
优化前
1217ms
1138ms
λ adb shell am start -W com.android.jv.ink.launcherink/.ui.home.JvMainActivityStarting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.android.jv.ink.launcherink/.ui.home.JvMainActivity }Status: okActivity: com.android.jv.ink.launcherink/.ui.home.JvMainActivityThisTime: 749TotalTime: 749WaitTime: 791Complete
λ asdb shell am start -W com.android.jv.ink.launcherink/.ui.home.JvMainActivityStarting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.android.jv.ink.launcherink/.ui.home.JvMainActivity }Status: okActivity: com.android.jv.ink.launcherink/.ui.home.JvMainActivityThisTime: 642TotalTime: 642WaitTime: 680Complete
01-08 03:23:08.457 1671-1813/system_process I/ActivityManager: Displayed com.android.jv.ink.launcherink/.ui.home.JvMainActivity: +642ms01-08 03:23:28.116 1671-1813/system_process I/ActivityManager: Displayed com.android.jv.ink.launcherink/.ui.edit.JvEditActivity: +187ms
Displayed
app启动时间
adb shell am start -W packagename/MainActivity命令,计算启动时间
adb pull sdcard/BLauncher.mp4
logcat 过滤 Displayed
录制查看帧
adb shell screenrecord --bugreport /sdcard/BLauncher.mp4
用KMP逐帧播放
mac上quicktime
延时调用 / 子线程调用 / 空闲时调用耗时方式
空闲时调用
将onCreate()中的耗时操作放到Idle中
但有个问题,如果UI线程的任务一直不执行完呢?会有这情况?举个🌰,Activity首页顶部有个滚动的Banner,banner的滚动是通过不断增加延迟Runnable实现。那么,初始化任务就可能一直没法执行。
延时调用
弊端
UI绘制结束时调用
onWindowFocusChanged()
至于为什么要在onWindowFocusChanged()再通过Handler.post()延后一个任务,一开始我是通过打点,发现没post()时,onWindowFocusChanged()打点在Log“Displayed”之前,增加post()便在Log“Displayed”之后,梳理了下调用流程,大概是渲染调用requestLayout()也是增加任务监听,只有SurfaceFlinger渲染信号回来时才会触发渲染,因此延后一个任务,刚好在其之后
View.post(Runnable runnable)
需要注意的是,该方案只有在onResume()或之前调用有效。
View内部维护了一个HandlerActionQueue,我们可以在DecorView attachToWindow前,通过View.post()将任务Runnables存放到HandlerActionQueue中。
设置全屏无标题主题提升体验
Activity
主要使用Traceview、monkey、monkey runner调试,traceview类似java web调优的visualvm,使用方法如下:在需要调优的activity onCreate函数中添加android.os.debug.startMethodTracing(\"Entertainment\");onDestrory函数中添加android.os.debug.stopMethodTracing();
数据库DB
线程优化
线程池ExecutorService
Android中数据不多时表查询可能耗时不多,不会导致anr,不过大于100ms时同样会让用户感觉到延时和卡顿,可以放在线程中运行,但sqlite在并发方面存在局限,多线程控制较麻烦,这时候可使用单线程池,在任务中执行db操作,通过handler返回结果和ui线程交互,既不会影响UI线程,同时也能防止并发带来的异常。
流畅度
布局优化
merge
3.<merge>标签的限制小白: <merge />标签有什么限制没?小黑: <merge />只能作为XML布局的根标签使用。当Inflate以<merge />开头的布局文件时,必须指定一个父ViewGroup,并且必须设定attachToRoot为true。
代码优化
AS代码分析检查
左上角菜单中Analyze-Inspect code
编译优化
组件化
if (isDebug.toBoolean()) { apply plugin: 'com.android.application'} else { apply plugin: 'com.android.library'}
子模块在debug模式下单独作为APP运行
if(isDebug.toBoolean()) { manifest.srcFile 'src/debug/AndroidManifest.xml' } else { manifest.srcFile 'src/release/AndroidManifest.xml' }
资源包大小优化
0 条评论
回复 删除
下一页