一、布局优化
布局优化就是删除布局中无用的控件和层级,可以用Hierarchy Viewer工具来检测,其次有选择地使用性能较低的ViewGroup。
include标签include标签只支持以android:layout开头的属性,比如android:layout_width;android:layout_height等,其他属性不支持,比如android:background.当然属性id还是支持的,如果include制定了这个id属性,同时被包含的布局文件也指定了id属性,那么以<include>指定的id属性为准,需要注意的是,如果include指定了android:layout_*这种属性,那么width,height必须存在,否则其他的android:layout形式的属性无法生效。
merge标签merge标签一般和include标签一起使用从而减少布局的层级,由于当前布局是一个竖直方向的Linearlayout,被包含的布局文件中的根布局也是Linearlayout,显然这个Linearlayout是多余的,通过merge标签就可以去掉多余的这一层。
ViewStubViewStub继承了View,它非常轻量级且宽/高都是0,因此它本身不参与任何的布局和绘制过程。ViewStub的意义在于按需加载所需的布局文件,在使用的时候再加载,提高了程序初始化时的性能。例子如下:
<ViewStub android:id="@+id/tv" android:layout_width="match_parent" android:layout_height="wrap_content" /> //用法一 ((ViewStub)findViewById(R.id.tv)).setVisibility(View.VISIBLE); //用法二 View view=((ViewStub)findViewById(R.id.tv)).inflate();二、卡顿优化
1、绘制优化 onDraw
(1)首先,onDraw中不要创建新的局部对象,这是因为onDraw方法可能会被频繁调用,这样一瞬间产生大量的临时对象,不仅占用过多的内存而且还频繁GC,降低了程序的执行效率。
(2)在onDraw中不要做耗时的操作,也不能执行成千上万的循环操作。View的绘制帧率保证60fps是最佳的,这就要求每帧的绘制时间不超过16ms(16ms=1000/60)。
2、过度绘制 使用手机开发者模式GPU
3、事件冲突
4、处理数据,内存抖动
三、内存泄漏优化
1、静态变量导致的内存泄漏 public class MainActivity extends Activity{ private static Context sContext; protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sContext=this; } } 单利模式导致的内存泄漏(1)如果参数是context,不要用某个activity的context,使用application的context。
观察者模式类型的只注册,未反注册
private List<DataListener> list=new ArrayList<>(); public void registerListener(DataListener listener){ list.add(listener); } public void unRegisterListner(DataListener listener){ list.remove(listener); } 属性动画导致的内存泄漏属性动画中的无线循环动画,如果没有在activity的ondestory()方法中去停止动画,尽管看不到动画效果,但是动画会一直播放下去,这时候动画持有了view,view只有了activity,最终activity无法释放,调用animator.cancel()来停止动画。
ObjectAnimatior animatior=ObjectAnimatior.ofFloat(mButton,"rotation",0,360).setDuration(2000); animator.cancel(); 数据库导致的内存泄漏自定义view中获取自定义属性,没有释放recycle非静态内部类导致的内存泄漏(handler)Bitmap未释放强引用,弱引用,软应用,虚引用类型点9图片webview
四、响应速度优化
响应速度优化的核心思想是避免在主线程中做耗时操作,如果在主线程中做耗时操作,activity启动时出现黑屏现象,甚至出现ANR,所以耗时操作在工作线程中完成。
(1)数据传递 序列化
(2)ANR Application Not Responding应用程序无响应
以下四个条件都可以造成ANR:
InputDispatching Timeout 5s没无法响应屏幕触摸事件或键盘输入事件BroadcastQueue Timeout 在执行前台广播(BroadcastRrceiver)的onReceive()函数时10s没有处理完成,后台为60sService Timeout 前台服务20s内,后台服务在200s内没有执行完毕ContentProvicer Timeout ContentProvider的publish在10s内没进行完分析方法
(1)log日志
开发阶段,可以查看android studio的日志
如果无法看开发工具日志,可以连接手机,导出手机日志,命令如下:
adb logcat -d >E:/anr.txt打印日志如下:
通过日志,可以简单分析CPU使用率,如果使用率很高,则是大规模的计算造成的,使用率很低,是因为主线程被阻塞了。
(2)traces.txt文件
当发生ANR的时候,会生成data/anr/traces.txt文件,导出来进行分析
adb pull data/anr/traces.txt F:/anr //把文件导出到f盘的anr文件夹下日志如下:
----- pid 6537 at 2019-12-26 01:01:44 ----- Cmd line: com.thor Build fingerprint: 'google/sdk_google_phone_x86/generic_x86:7.0/NYC/4409132:user/release-keys' ABI: 'x86' Build type: optimized Zygote loaded classes=4353 post zygote classes=260 Intern table: 41464 strong; 310 weak JNI: CheckJNI is on; globals=480 (plus 152 weak) Libraries: /system/lib/libandroid.so /system/lib/libcompiler_rt.so /system/lib/libjavacrypto.so /system/lib/libjnigraphics.so /system/lib/libmedia_jni.so /system/lib/libwebviewchromium_loader.so libjavacore.so libopenjdk.so (8) Heap: 18% free, 6MB/7MB; 36070 objects Dumping cumulative Gc timings Total number of allocations 36070 Total bytes allocated 6MB Total bytes freed 0B Free memory 1492KB Free memory until GC 1492KB Free memory until OOME 377MB Total memory 7MB Max memory 384MB Zygote space size 1064KB Total mutator paused time: 0 Total time waiting for GC to complete: 0 Total GC count: 0 Total GC time: 0 Total blocking GC count: 0 Total blocking GC time: 0 Histogram of native allocation 0:602,128:219,256:111,384:58,512:10,640:1,896:16,1152:2 bucket size 128 Histogram of native free 32:7,64:2,96:59,192:201,288:38,480:7 bucket size 32 /data/app/com.thor-2/oat/x86/base.odex: interpret-only Current JIT code cache size: 124B Current JIT data cache size: 924B Current JIT capacity: 64KB Current number of JIT code cache entries: 1 Total number of JIT compilations: 1 Total number of JIT compilations for on stack replacement: 0 Total number of deoptimizations: 0 Total number of JIT code cache collections: 0 Memory used for stack maps: Avg: 36B Max: 36B Min: 36B Memory used for compiled code: Avg: 79B Max: 79B Min: 79B Memory used for profiling info: Avg: 144B Max: 640B Min: 16B Start Dumping histograms for 1 iterations for JIT timings Compiling: Sum: 60.976ms 99% C.I. 60.976ms-60.976ms Avg: 60.976ms Max: 60.976ms TrimMaps: Sum: 21us 99% C.I. 21us-21us Avg: 21us Max: 21us Done Dumping histograms Memory used for compilation: Avg: 29KB Max: 29KB Min: 29KB ProfileSaver total_bytes_written=0 ProfileSaver total_number_of_writes=0 ProfileSaver total_number_of_code_cache_queries=0 ProfileSaver total_number_of_skipped_writes=0 ProfileSaver total_number_of_failed_writes=0 ProfileSaver total_ms_of_sleep=2000 ProfileSaver total_ms_of_work=0 ProfileSaver total_number_of_foreign_dex_marks=0 ProfileSaver max_number_profile_entries_cached=1 ProfileSaver total_number_of_hot_spikes=0 ProfileSaver total_number_of_wake_ups=0 suspend all histogram: Sum: 398us 99% C.I. 25us-82us Avg: 39.800us Max: 82us DALVIK THREADS (14): "Signal Catcher" daemon prio=5 tid=3 Runnable | group="system" sCount=0 dsCount=0 obj=0x12c580d0 self=0xa0025e00 | sysTid=6543 nice=0 cgrp=default sched=0/0 handle=0xa8ed7920 | state=R schedstat=( 0 0 0 ) utm=0 stm=0 core=1 HZ=100 | stack=0xa8ddb000-0xa8ddd000 stackSize=1014KB | held mutexes= "mutator lock"(shared held) native: #00 pc 0056d8de /system/lib/libart.so (_ZN3art15DumpNativeStackERNSt3__113basic_ostreamIcNS0_11char_traitsIcEEEEiP12BacktraceMapPKcPNS_9ArtMethodEPv+238) native: #01 pc 00539f6e /system/lib/libart.so (_ZNK3art6Thread9DumpStackERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEEbP12BacktraceMap+526) native: #02 pc 00536f6b /system/lib/libart.so (_ZNK3art6Thread4DumpERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEEbP12BacktraceMap+75) native: #03 pc 005568bb /system/lib/libart.so (_ZN3art14DumpCheckpoint3RunEPNS_6ThreadE+1115) native: #04 pc 0054cb7e /system/lib/libart.so (_ZN3art10ThreadList13RunCheckpointEPNS_7ClosureE+590) native: #05 pc 0054c706 /system/lib/libart.so (_ZN3art10ThreadList4DumpERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEEb+310) native: #06 pc 0054c591 /system/lib/libart.so (_ZN3art10ThreadList14DumpForSigQuitERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEE+929) native: #07 pc 0051f35c /system/lib/libart.so (_ZN3art7Runtime14DumpForSigQuitERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEE+380) native: #08 pc 00528b7e /system/lib/libart.so (_ZN3art13SignalCatcher13HandleSigQuitEv+2494) native: #09 pc 005272e0 /system/lib/libart.so (_ZN3art13SignalCatcher3RunEPv+416) native: #10 pc 00074fb2 /system/lib/libc.so (_ZL15__pthread_startPv+210) native: #11 pc 0002026e /system/lib/libc.so (__start_thread+30) native: #12 pc 0001e046 /system/lib/libc.so (__bionic_clone+70) (no managed stack frames) "main" prio=5 tid=1 Sleeping | group="main" sCount=1 dsCount=0 obj=0x73ced000 self=0xa9b8b400 | sysTid=6537 nice=0 cgrp=default sched=0/0 handle=0xaded3534 | state=S schedstat=( 0 0 0 ) utm=8 stm=31 core=3 HZ=100 | stack=0xbf5ac000-0xbf5ae000 stackSize=8MB | held mutexes= at java.lang.Thread.sleep!(Native method) - sleeping on <0x021bdfde> (a java.lang.Object) at java.lang.Thread.sleep(Thread.java:371) - locked <0x021bdfde> (a java.lang.Object) at java.lang.Thread.sleep(Thread.java:313) at com.thor.service.DemoService.add(DemoService.java:36) at com.thor.service.DemoService.onStartCommand(DemoService.java:21) at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3297) at android.app.ActivityThread.-wrap21(ActivityThread.java:-1) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1565) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6077) at java.lang.reflect.Method.invoke!(Native method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)全局搜main关键字,查看的是主线程的情况,再详细分析。每次发生ANR,traces文件都被清空,重新写入ANR的最新一次。
2、如果运行命令抛出如下错误,
adb: error: failed to stat remote object 'data/anr/traces.txt': No such file or directory
尝试方法如下:
F:\projects\Shop>adb shell OnePlus5:/ $ cd data/anr OnePlus5:/data/anr $ ls //下面是列出来的所有文件 anr_2019-05-19-10-28-38-549 anr_2019-05-19-11-04-01-915 anr_2019-05-19-11-08-39-264 dumptrace_JYOoPa system_server trace_01 transaction_log anr_2019-05-19-10-29-59-089 anr_2019-05-19-11-07-28-693 anr_2019-05-19-11-09-02-860 state trace_00 trace_02 transactions F:\projects\Shop>adb pull data/anr/anr_2019-05-19-11-09-02-860 //退出 OnePlus5:/data/anr $ exit四、启动优化
1、分类
冷启动现象: 点击app的icon,显示白屏或者黑屏
冷启动流程: 加载启动app-->app启动之后展示一个空白的window-->创建app进程-->创建app对象-->启动MainThread-->创建启动的activity对象-->加载view
解决办法:1、设置默认启动activity的主题里面windowback属性为透明
<style name="SplashTheme" parent="AppTheme"> <item name="android:windowBackground">@null</item> <item name="android:windowContentOverlay">@null</item> <item name="android:windowDisablePreview">@null</item> </style>2、设置默认启动activity的主题里面windowback属性为默认图片
<style name="SplashTheme" parent="AppTheme"> <item name="android:windowBackground">@drawable/abc_vector_test</item> <item name="android:windowContentOverlay">@null</item> <item name="android:windowDisablePreview">@null</item> </style>3、上面的1,2方法只是治标,辅以下面方法
applicaiton的oncreate方法初始化各种sdk判断是否在当前进程
applicaiton的onCreate方法不做耗时操作
sdk的初始化如果可以最好延迟加载
热启动
最快,从后台到前台
温启动2、启动时间测量方式
adb命令(不严谨,线下使用方便,不能线上使用)ThisTime:最后一个activity启动耗时
TotalTime:所有Activity启动耗时
WaitTime:AMS启动Activity的总耗时
手动打点(精确,可带到线上,进行统计) public class SingleApplication extends Application { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); //记录开始时间 } //在activity中加载完xml,记录结束时间(3)启动优化工具
两种工具互补
traceview
图形的形式展示执行时间,调用栈等,信息全面,包含所有线程
使用方式:
Debug.startMethodTracing("文件名")
Debug.stopMetodTracing();
生成文件在sd卡:Android/data/packagename/files/名字.trace
五、耗电优化
六、安装包大小优化
res图片一套,删除无用的文件代码混淆七、线程优化
使用线程池
