App性能优化之---响应快稳定性省内存体积小

App性能优化之---响应快稳定性省内存体积小

2023年6月28日发(作者:)

App性能优化之---响应快稳定性省内存体积⼩在⽹上看到很多关于性能优化的⽂章,总结起来就是:快,稳,省,⼩。如下图所⽰:接下来针对这四个⽅⾯进⾏讲解 快如何让 app 在运⾏过程过不卡顿,运⾏流畅,速度快,也就是说如何解决卡顿呢?我们先看看那些因素影响卡顿?

1、ui的绘制,刷新等

2、冷启动,热启动等

3、页⾯跳转,前后台切换

4、点击事件,滑动,系统事件UIAndroid 显⽰过程可以简单概括为:Android 应⽤程序把经过测量,布局、绘制后的 surface 缓存数据,通过 SurfaceFlinger 把数据渲染到显⽰屏幕上, 通过 Android 的刷新机制来刷新数据。也就是说应⽤层负责绘制,系统层负责渲染,通过进程间通信把应⽤层需要绘制的数据传递到系统层服务,系统层服务通过刷新机制把数据更新到屏幕上。换⼀种⽅式说:Android 系统每隔 16ms 发出 VSYNC 信号,触发对 UI 进⾏渲染,如果每次渲染都成功,这样就能够达到流畅的画⾯所需的 60FPS。(注:FPS 表⽰每秒传递的帧数。)在理想情况下,60 FPS 就感觉不到卡,这意味着每个绘制时长应该在16 ms 左右。如果某个操作花费的时间是 24ms ,系统在得到 VSYNC 信号时就⽆法正常进⾏正常渲染,这样就发⽣了丢帧现象。也就是延迟了,这种现象在执⾏动画或滑动列表⽐较常见,还有可能是你的 Layout 太过复杂,层叠太多的绘制单元,⽆法在 16ms 完成渲染,最终引起刷新不及时.那么我们如何解决呢,主要从两点⼊⼿:布局优化,绘制优化布局优化1、避免ui布局优化可以先从合理使⽤背景⾊开始,⽐如:如果⼦view和⽗布局公⽤⼀个背景⾊就没有必要了。2、减少不必要的嵌套,⼀般建议不超过5层3、合理使⽤各种布局,尽量使⽤ LinearLayout 和 FrameLayout,因为 RelativeLayout 需要⽐较复杂,测绘也⽐较费时4、合理使⽤ include、merge 和 ViewStub,使⽤include和merge增加复⽤,减少层级; ViewStub 按需加载。绘制优化我们之前说过根据 Android 系统显⽰的原理,View 的绘制频率保证 60fps 是最佳的,这就要求每帧绘制时间不超过16ms(16ms =1000/60),因此要减轻 onDraw() 的负担。所以在绘制时要注意两点:1、onDraw 中不要创建新的局部对象。2、onDraw ⽅法中不要做耗时的任务。还有就是刷新,刷新的话尽量减少不必要的刷新和尽可能减少刷新⾯积启动优化冷启动冷启动是指安装 apk 后⾸次启动应⽤程序,或者应⽤程序上次结束,进程被杀死后重新打开app.1、点击桌⾯App图标,Launcher进程采⽤Binder IPC向system_server进程发起startActivity请求;2、system_server进程接收到请求后,向zygote进程发送创建进程的请求;3、Zygote进程fork出新的⼦进程,即App进程;4、App进程,通过Binder IPC向sytem_server进程发起attachApplication请求;5、system_server进程在收到请求后,进⾏⼀系列准备⼯作后,再通过binder IPC向App进程发送scheduleLaunchActivity请求;6、App进程的binder线程(ApplicationThread)在收到请求后,通过handler向主线程发送LAUNCH_ACTIVITY消息;7、主线程在收到Message后,通过发射机制创建⽬标Activity,并回调te()等⽅法。到此,App便正式启动,开始进⼊Activity⽣命周期,执⾏完onCreate/onStart/onResume⽅法热启动热启动是⽤户 Back 退出应⽤程序,然后⼜重新启动,应⽤程序会再次执⾏ Activity 的 onCreate(),但会从Bundle(savedInstanceState)获取数据,我们平时应⽤成勋崩溃,不也是通过该⽅法保存数据的吗。针对启动⽅式的优化1、Application 的创建过程中尽量少的进⾏耗时操作⽐如:onCreate() 中进⾏友盟,bugly, okhttp,地图,推送等 init() 等操作。如果是必须在 onCreate 中进⾏的如:okhttp 等⽹络请求框架我们在 onCreate 中进⾏,其他的友盟,百度地图啥的我们可以等程序起来后再 onResume ⽅法中执⾏,bugly 等 sdk 可以异步加载。统计SDK执⾏耗时,在代码之间插⼊ethodTracing(filename)和thodTracing()就可以追踪所包含代码的执⾏耗时,这些数据会写⼊⼀个.trace⽂件中,只要导出这个⽂件就可以看到详细信息了//代码追踪开始,参数是trace⽂件保存在⼿机的全路径名

ethodTracing(ernalFilesDir(_MOUNTED).getPath() + "01"); //EventBus初始化 ault().register(this); // 百度地图的初始化,在使⽤SDK各组间之前初始化context信息,传⼊ApplicationContext lize(this); rdType(09LL); //初始化友盟 initUm(); //初始化路由ARouter initRouter(this); //初始化⽇志收集 initCrashReport(); //初始化http initRxHttp(); //代码追踪结束 thodTracing();执⾏以上代码,然后通过将在cmd中输⼊adb pull [trace⽂件保存在⼿机的全路径名] 导出trace⽂件到电脑中,再通过Android Studio打开⽂件从图中可以看到代码中每个⽅法的执⾏时间和占⽤时间的百分⽐,initRouter时间占⽐55.6%、initUm占⽐20.1%、lize占⽐19.5%,主要是这个三个初始化占⽤了⼤多数时间,它们分别是路由框架ARouter,友盟和百度地图的初始化⼀些常⽤的优化思路:考虑异步初始化第三⽅组件,不阻塞主线程延迟第三⽅的初始化时间,因为异步初始化有可能遇到初始化还没完成主线程已经⽤到的情况,这种情况可以考虑延时到第三⽅组件使⽤之前进⾏初始化数据库、IO操作、⽹络请求尽量不要在Application中执⾏,能异步初始化的就尽量异步,如果不能异步初始化就尽量延时,不要在Application中创建线程池在⾸页Activity中,布局尽量减少嵌套,在onCreate、onStart、onResume⽅法中尽量避免耗时操作因为⾸页activity要⽤到组件ARouter,所以我考虑把它的初始化延时到SplashActivity中的使⽤前,经测试,百度地图不能在⼦线程初始化,所以考虑延时,然后友盟初的始化放在⼦线程 //在Application中创建⼯作线程进⾏相关初始化 private void initOnWorkThread() { new Thread(new Runnable() { @Override public void run() { //将线程设置为后台,避免和主线程争抢资源 eadPriority(THREAD_PRIORITY_BACKGROUND); initUm(); initCrashReport(); } }).start(); }

//将下⾯初始化延迟到⾸次显⽰Activity的onCreate⽅法中进⾏,界⾯完成以后才执⾏run⽅法

findViewById(_view).post(new Runnable() { public void run() { //初始化ARouter (tance()); // 在使⽤ SDK 各组间之前初始化 context 信息,传⼊ ApplicationContext lize(tance()); rdType(09LL);

//登录等其他操作 ........ } });优化前后对⽐优化前时间1560

优化后时间

1009

时间相差

551

提升百分⽐ 35.3%优化启动速度整整提升了35.3%2、SplashActivity设置主题背景举个例⼦:使⽤以下⼏种主题,看看APP的启动速度@android:style/reen 平均启动时间:126.8ms@android:style/ 平均启动时间:160ms默认(根据操作系统⾃动选择) 平均启动时间:174.8ms可以得出⼀个结论:使⽤⼀个没有ActionBar的主题,⽐较快,⽽如果连StatusBar也去掉了,速度最快!原因是这样的,启动⼀个Activity的时候,SetContentView中会加载布局⽂件public void setContentView(@LayoutRes int layoutResID) { getWindow().setContentView(layoutResID); initWindowDecorActionBar(); }从Activity的attach⽅法可以知道,mWindow的实体是PhoneWindow:1. 初始化DecorView(对于⼀个window来说最顶级的view)

2. 根据Window的属性选择合适的布局模板add到DecorView中

3. 将我们的布局add到⼀个id为t的ViewGroup中如果Activity的主题设为FullScreen,⽆需加载ActionBar减少⼀层布局,有效提⾼启动速度。另外将主题的Background进⾏处理,使得Splash在启动时根本没有加载实际的View,⽽仅仅是加载了主题,待Activity初始化完成以后,再渲染View,这样就避免了⽩屏和空屏的等待时常,让⽤户感觉到启动速度快@drawable/welcome_layler_drawable通过将⽣成的drawable设置为background的形式最终并不会⽣成任何View,减⼩View绘制占⽤的时间提升启动速度!通过实验,发现市⾯上很多的APP(⾼德地图、⼤众点评、百度地图、ofo⼩黄车等)都是采取了类似的⽅式,通过设置⼀个FullScreen主题的Activity,并设置background为和Splash布局类似的形式,能够做到点下图标的即刻,展现界⾯。BlockCanary分析android卡顿1、Service TimeOut: 未在规定时间执⾏完成:前台服务 20s,后台 200s2、BroadCastQueue TimeOut: 未在规定时间内未处理完⼴播:前台⼴播 10s 内, 后台 60s 内3、ContentProvider TimeOut: publish 在 10s 内没有完成4、Input Dispatching timeout: 5s 内未响应键盘输⼊、触摸屏幕等事件卡顿(ANR)检测原理

从 ANR原理 可以知道,当⼀个事件处理时间超过阈值就会触发ANR。dispatchMessage花费的时间就是每条消息处理时间。从Looper源码中我们发现,执⾏dispatchMessage前后都有⼀个logging打印,并且Looper提供了注册logging的⽅法。可以在MainThread Looper中注册⼀个logging,在每条消息dispatchMessage前后,都能收到⼀条打印记录。通过记录dispatchMessage之前的时间t1和dispatchMessage执⾏之后的log时间t2,totalTime = t2-t1得到该事件执⾏时间。

BlockCanary卡顿检测流程 稳内存溢出的⼏点原因:

1、资源释放问题

程序代码的问题,长期保持某些资源,如Context、Cursor、IO流的引⽤,资源得不到释放造成内存泄露。

2、对象内存过⼤问题

保存了多个耗⽤内存过⼤的对象(如 Bitmap、XML⽂件),造成内存超出限制。

3、static关键字的使⽤问题

static是Java中的⼀个关键字,当⽤它来修饰成员变量时,那么该变量就属于该类,⽽不是该类的实例。所 以⽤static修饰的变量,它的⽣命周期是很长的。4、避免OOM的第⼀步就是要尽量减少新分配出来的对象占⽤内存的⼤⼩,尽量使⽤更加轻量的对象使⽤ArrayMap/SparseArray⽽不是HashMap等传统数据结构,通常的HashMap的实现⽅式更加消耗内存,因为它需要⼀个额外的实例对象来记录Mapping操作。另外,SparseArray更加⾼效在于他们避免了对key与value的autobox⾃动装箱,并且避免了装箱后的解箱如何避免OOM异常

1、图⽚过⼤导致OOM

⽅法 1 :等⽐例缩⼩图⽚

s options = new s();

leSize = 2;

⽅法2 :对图⽚采⽤软引⽤,及时地进⾏recyle()操作

SoftReference bitmap = new SoftReference(pBitmap);

if(bitmap != null){

if(() != null && !().isRecycled()){

().recycle();

bitmap = null;

} }

2、界⾯切换导致OOM

有时候我们会发现这样的问题,横竖屏切换 N次后 OOM了。 这种问题没有固定的解决⽅法,我们从以下⼏个⽅⾯下⼿分析。

1、看看页⾯布局当中有没有⼤的图⽚,⽐如背景图之类的。

去除xml中相关设置,改在程序中设置背景图(放在onCreate()⽅法中):

Drawable drawable = getResources().getDrawable();

ImageView imageView = new ImageView(this);

kgroundDrawable(drawable);

在Activity destory时注意,lback(null); 防⽌Activity得不到及时的释放。

2、使⽤完BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源时,在Activity中的OnDestry中及时的关闭、注销或者释放内存。

内存泄漏出现的场景:

(1)、单例设计模式造成的内存泄漏 (2)、⾮静态内部类创建的静态实例造成的内存泄漏 (3)、Handler造成的内存泄漏 (4)、线程造成的内存泄漏 (5)、资源未关闭造成的内存泄漏 常见的解决⽅案: 1、尽量使⽤Application的Context⽽不是Activity的 2、使⽤弱引⽤或者软引⽤漏 3、⼿动设置null,解除引⽤关系漏 4、将内部类设置为static,不隐式持有外部的实例漏 5、在使⽤完BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源时,⼀定要在Activity中的OnDestry中及时的关闭、注销或者释放内存,

省 省电5.0之后才有像样的⽅案,讲实话这个优化的优先级没有前⾯⼏个那么⾼,但是我们也要了解⼀些避免耗电的坑,⾄于更细的耗电分析可以使⽤这个Battery Historian。Battery Historian 是由Google提供的Android系统电量分析⼯具,从⼿机中导出bugreport⽂件上传⾄页⾯,在⽹页中⽣成详细的图表数据来展⽰⼿机上各模块电量消耗过程,最后通过App数据的分析制定出相关的电量优化的⽅法。我们来谈⼀下怎么规避电⽼虎吧。⾕歌推荐使⽤JobScheduler,来调整任务优先级等策略来达到降低损耗的⽬的。JobScheduler可以避免频繁的唤醒硬件模块,造成不必要的电量消耗。避免在不合适的时间(例如低电量情况下、弱⽹络或者移动⽹络情况下的)执⾏过多的任务消耗电量。具体功能:1、可以推迟的⾮⾯向⽤户的任务(如定期数据库数据更新);2、当充电时才希望执⾏的⼯作(如备份数据);3、需要访问⽹络或 Wi-Fi 连接的任务(如向服务器拉取配置数据);4、零散任务合并到⼀个批次去定期运⾏;5、当设备空闲时启动某些任务;6、只有当条件得到满⾜, 系统才会启动计划中的任务(充电、WIFI…)。同时⾕歌针对耗电优化也提出了⼀个懒惰第⼀的法则:减少:你的应⽤程序可以删除冗余操作吗?例如,它是否可以缓存下载的数据⽽不是重复唤醒⽆线电以重新下载数据?推迟:应⽤是否需要⽴即执⾏操作?例如,它可以等到设备充电才能将数据备份到云端吗?合并:可以批处理⼯作,例如⼏⼗个应⽤程序是否真的有必要在不同时间打开收⾳机发送邮件?省内存主要是加载图⽚,动不动就 OOM,对于图⽚的压缩⽆⾮是:1、图⽚尺⼨压缩2、图⽚质量压缩Glide就是采⽤了 Lrucache 和 LruDiskCache 推荐使⽤。Fresco 采⽤匿名共享内存,更加节省内存。

⼩⼤多指应⽤程序apk体积要⼩。我们先看看⼀个apk⽂件有哪些解压后有哪些⽂件:使⽤Analyze减少APK体积project—>app—>bulid—>outputs—>apk—>[XXX].apk,双击[XXX].apk即可---打开Analyze

File 原size 优化后

assets 13.4M 7.5Mlib 12.6M 6.4Mres 16.2M 7.9M 2.1M 2.6M 408kblib:包含so⽂件,还有armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, and mips优化: ndk { abiFilters "armeabi", "armeabi-v7a" }1、市⾯上主流机型都是arm架构,只保留armeabi或者armeabi-v7a分析⽤户⼿机的cpu舍弃so之前需要进⾏⽤户cpu型号的统计,花了⼏个版本统计了⽤户的cpu型号,然后排除了没有或少量⽤户才会⽤到的so,以达到瘦⾝的⽬的。@NonNullpublic static String getCpuName() { String name = getCpuName1(); if (y(name)) { name = getCpuName2(); if (y(name)) { name = "unknown"; } } return name;}private static String getCpuName1() { String[] abiArr; if (_INT >= N_OP) { abiArr = TED_ABIS; } else { abiArr = new String[]{_ABI, _ABI2}; } StringBuilder abiStr = new StringBuilder(); for (String abi : abiArr) { (abi); (','); } return ng();}private static String getCpuName2() { try { FileReader e = new FileReader("/proc/cpuinfo"); BufferedReader br = new BufferedReader(e); String text = ne(); String[] array = (":s+", 2); (); (); return array[1]; } catch (IOException var4) { tackTrace(); return null; }}注意:如果你⽤了RN,那么对于x86需要谨慎的保留,否则可能会出现⽤户找不到so⽽崩溃的情况。稍有不慎就可能会出现开机崩的情况。so这个东西还是⽐较危险的,虽然可以通过统计cpu型号来降低风险,但还是推荐发布app前⾛⼀遍⼤量机型的云测推荐在崩溃系统中上传⽤户cpu型号的信息,我们可以在第⼀时间知道因找不到so引起的崩溃量,⾄于是否需要增加so就看问题的严重程度了。res:⼀些不会被编译到的资源⽂件。如drawable⽂件、layout⽂件等优化:1、只保留⼀套图,⾮重要的图动态加载,2、保真压缩图⽚,3、使⽤webp替代png体积更⼩,4、使⽤lint删除⽆⽤资源minifyEnabled true, shrinkResources true这是⾕歌给出的建议,简单来说就是:VectorDrawable->WebP->Png->JPG如果是纯⾊的icon,那么⽤svg如果是两种以上颜⾊的icon,⽤webp如果webp⽆法达到效果,选择png如果图⽚没有alpha通道,可以考虑jpg阿⾥系、腾讯系的产品都采⽤了⼀套图⾛天下的路⼦。这样的做法还是有利有弊的,权衡之下我给出如下建议:聊天表情就出⼀套图,放在hdpi中纯⾊⼩icon⽤svg做背景等⼤图,出⼀套放在xhdpi中⼤多数图⽚放在xxhdpi中assets:⼀些通过AssetManager能够检索到的资源。如MP3、字体、webp等资源⽂件。优化:1、删除⽆⽤字体,2、动态下载,MP3、字体、webp等使⽤时下载,3、MP3、字体、webp等放在本地先压缩使⽤时解压:包括了所有可以被编译的位于res/values/⽬录下的编译后的⼆进制资源⽂件优化:删除⽆⽤的语⾔,只保留中⽂:包含了所有的Java⽂件编译后的class⽂件,单个的 ⽂件可以容纳⼤约 64K ⽅法。如果你达到了这个限制,你必须要在你的⼯程中启⽤ multiDexEnabled true,通过设置 minifyEnabled 为 true,混淆将会移除所有未使⽤的⽅法、指令以减⼩ ⽂件。每个模块启⽤了混淆之后我们的 ⼤⼩减⼩了⼏乎 50%。同时你可以看到⽅法数从 29897 降到15168(⼏乎 50%)。:AndroidMainifest⽂件的权限、声明等配置

通常我减⼩ apk 体积的⽅式都是:先⽤ studio ⾃带的代码扫描分析⼯具 lint 删除⽆⽤资源;开启混淆,设置 shrinkResources true和minifyEnabled true;当然你也可以借助第三⽅⼯具如 :乐固加固,360压缩啥的;还有注意不要重复使⽤库;插件化,⽐如功能模块放在服务器上,按需下载,可以减少安装包⼤⼩等都是常见的减少 apk 体积的⽅式。

其他这都是本⼈的⼀些建议:1、序列化采⽤推荐的 Parcelable 代替 Serializable2、集合如果是插⼊和删除⽤的多,建议使⽤ LinkList。如果修改⽤的多,建议 ArrayList。3、写程序要思考,避免创建不必要的对象。4、对常量使⽤ static final,适⽤于基本类型和 String 常量。5、使⽤增强的 for 循环语法(foreach)。6、避免使⽤浮点数,浮点数⽐ Android 设备上的整数慢约2倍。7、尽可能少⽤ wrap_content,wrap_content 会增加布局 measure 时计算成本。8、合理使⽤动画,某些情况下可以⽤硬件加速⽅式来提供流畅度,或者采⽤⾃定义view代替动画,最后记得在Activity的ondestory()⽅法中调⽤()进⾏动画停⽌。9、注意 webview 和 handler,⼀般在⾸次加载后 webview 就会存在于内存中,容易内存泄漏。10、数据量⽐较⼤或者内存⽐较宽裕考虑 HashMap,其他建议使⽤ SpareArray最后,我们⼀定要学会使⽤ Android Studio ⾃带的各种⼯具如:Lint:提⽰未使⽤到资源,不规范的代码,优化建议等。使⽤:选择 Analyze > Inspect Code 具体百度使⽤ Android Profiler 查看内存,已经各个操作内存和⽹络的变化。借助第三⽅⼯具,这个就多了去了,⽐如 LeakCanary,MemoryAnalyzer 等

发布者:admin,转转请注明出处:http://www.yc00.com/news/1687955463a60614.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信