• Android应用性能优化


    整理自http://androidperformance.com的几篇博客

    代码内存优化-Java篇

    • 避免创建不必须的对象,虽然GC可以回收不用的对象,但为对象分配内存和回收它们同样是需要消耗资源的。
    • 选择static而不是Virtual,当我们不需要访问一个对象的值域时,请将方法声明为static,这样方法调用将快15%-20%;
    • 将常量声明为static final类型
    • 避免内部的Getters和Setters,在对象的设计中应该有getters和setters,但在类内部访问时,应该直接访问变量;在没有JIT时,直接访问的速度是getters的3倍,有JIT时,是 getters的7倍;
    • 使用增强的for循环写法,for(Obj obj:Array); 但如果Array是ArrayList,则使用for(int i=0;i<len;++i)的写法会好一些;
    • 使用包级访问,而不是内部类的私有访问,当内部类需要访问外部类的私有域时,请把外部类的私有域声明为包访问权限,但这可能会存在安全问题;
    • 避免使用float,float类型在Android中的访问速度是int型的一半;

    Android内存优化——OnTrimMemory()优化

    OnTrimMemory()回调是Android 4.0开始提供的一个API,它主要是提示开发者在系统内存不足的时候,通过处理部分资源来释放内存,从而避免被系统杀死,进而可以在下一次启动时更快速地启动。这个回调方法主要就是让应用程序在不同情况下对自身占用的内存进行翻译,从而避免被系统杀死,提高用户体验。任何实现了ComponentCallbacks2 接口的类都可以重写实现这个回调方法。

    尽管系统在内存不足时是按照LRU Cache从低到高的顺序杀进程的,但它同时会考虑杀死那些占用内存高的应用来快速恢复系统的内存。因此如果你的应用占用内存小,就减少了被系统杀死的概率,从而快速地恢复(如果应用没有被杀死,则再次启动时是热启动,否则就是冷启动,速度之差在2到3倍之间),因此在不同的OnTrimMemory()回调中释放自己的UI资源,可以提供较好的用户体验。

    Android系统会根据不同的内存使用情况,调用这个函数,并传入相应的等级:

    • TRIM_MEMORY_UI_HIDDEN 表示应用的所有UI界面被隐藏了,也就是用户点击Home键或者Back键导致应用的界面不可见,这时应该释放一些资源;
    • TRIM_MEMORY_RUNNING_MODERATE表示应用程序可以正常运行,并且不会被杀死,但手机内存已经有点低了,系统可能会根据LRU缓存规则来杀死一些进程了。
    • TRIM_MEMORY_RUNNING_LOW表示应用程序可以正常运行,并且不会被杀死,但此时手机内存已经非常低了,我们应该释放一些不必须的资源来提升系统性能;
    • TRIM_MEMORY_RUNNING_CRITICAL表示应用程序可以正常运行,但此时系统已经根据LRU缓存规则杀掉大部分缓存进程,这时我们应该尽可以地释放一些不必要的资源,否则系统可能继续杀掉所有缓存中的进程,并且可能杀掉本应该运行的进程,如后台运行的服务;

    上面的几个等级是应用程序在运行时会收到的回调,下面的几个等级是应用程序在缓存时,会收到的回调:

    • TRIM_MEMORY_BACKGROUND表示手机的内存已经非常低了,系统开始根据据LRU缓存规则来杀死一些进程了,我们的应用处于LRU的最近位置,不太可能被杀掉,但应该去释放一些比较容易恢复的资源,让手机内存更充足,可以让我们的应用在缓存中存活的时间更长;这样当用户返回我们程序时,会感到更顺畅。
    • TRIM_MEMORY_MODERATE表示手机的内存已经非常低了,系统开始根据LRU缓存规则来杀死一些进程了,我们的应用处于LRU的中间位置,如果手机的内存得不到释放的话,我们的应用程序很大可能会被杀死;
    • TRIM_MEMORY_COMPLETE表示手机内存已经很低了,系统开始根据LRU缓存规则来杀死一些进程,并且我们的应用处于LRU的最后位置,系统会优先考虑杀死我们的进程,这个时候,应该尽可能释放一切可以释放的资源。

    正常情况下,Application,Activity,Fragment,Service,ContentProvider都可以实现OnTrimMemory()回调方法。

    在OnTrimMemory回调中应该释放哪些资源

    • 缓存,包括图片缓存,文件缓存等,缓存在用户正常使用时很有作用,但当应用程序的UI不可见时,这些缓存就可以清除以减少内存的使用,如第三方图片库的缓存;
    • 一些动态生成动态添加的View,这些动态生成动态添加的View且少数情况下才使用到的View,这时候可以释放,下次使用时再动态生成即可。如原生桌面中,会在OnTrimMemory的TRIM_MEMORY_MODERATE等级中,释放所有的AppsCustomizePagedView的资源,保证在低内存的时候,桌面应用程序不会被杀掉。

    OnTrimMemory()与OnStop()方法区别

    OnTrimMemory()方法中TRIM_MEMORY_UI_HIDDEN回调只有当我们应用的所有UI不可见时都会触发,但OnStop()方法会在一个Activity完全不可见时就会调用,如用户打开了我们程序的另一个Activity,因此我们可以在OnStop()方法中释放一些Activity相关的资源,如取消网络连接,注销广播接收器等,但与UI相关的资源要等到OnTrimMemory()方法中TRIM_MEMORY_UI_HIDDEN回调之后才去释放,这样当用户从应用程序的一个Activity跳回到另一个Activity,可以保证程序的响应速度。并且这个回调是在OnStop()方法之前调用的。

    应用场景

    • 常驻内存的应用,如Launcher,电话等,在用户使用完退出后需要调用OnTrimMemory()来释放用户使用的多余的内存资源,如动态生成的View,图片缓存,Fragment等;
    • 有后台Service运行的应用,这些应用不是常驻内存的,意味着可以被任务管理器杀掉,但在某些情况下,用户不会去杀,如音乐,下载。当用户退出UI界面后,音乐还在后台播放,此时应该释放掉一些UI资源和Cache;

    Android内存优化--资源篇

    1. Bitmap优化,Android开发中遇到的大部分内存问题归根结底是Bitmap问题,如果Bitmap没有被释放,要么是用户在使用完这个Bitmap时,没有主动释放Bitmap资源,要么就是这个Bitmap资源被引用没有办法被释放。因此我们需要:
    • 主动释放Bitmap资源,当这个Bitmap资源不再使用时,建议手动调用recycle()方法,释放其Native内存;
    • 主动释放ImageView的图片资源
    • 主动释放ImageView的背景资源
    • 尽量少用Png图,多用NinePatch的图,现在手机的分辨率越来越高,图片资源被加载后占用的内存也越来越大,因此要避免使用大的Png图片,改用NinePatch图。
    • 使用大图之前,尽量先对其进行压缩
    1. 查询数据库后,主动关闭游标,如果使用完后,没有关闭游标,且我们的结果集比较小时,需要常时间大量的操作才会复现内存问题,会给测试和问题排查带来困难和风险;
    2. 构造Adapter时,使用缓存的contentView,以ListView为例,初始化时,ListView会根据屏幕布局实例化一定数量的View对象,并缓存,并ListView向上滚动时,位于最上面的View对象会被回收用来创建新出现的最后的ListView Item,contentView就是那个被缓存起来的View对象。如果每次使用都重新实例化一个View对象,即浪费资源,也浪费时间,会消耗大量的内存资源。
    3. 及时释放对象的引用,当我们使用完某个对象时,要及时释放掉这个对象的引用,以便当前这个对象在不需要时,可以被GC掉;否则,由于没有及时释放掉对象的引用,导致当前这个对象一直不能被回收,后面需要用到这个对象时,则会重复创建,让系统存在大量的不可回收的对象,最后导致OutOfMemory; 即当我们在对象B中 引用了一个对象A,则B应该在使用完A对象后,及时释放A对象的引用,以便在使用完对象B后,对象B可以被系统回收。
    4. 在Activity中释放资源
    5. 消除过度绘制,过度绘制指一个像素被绘制多次,如TextView中含有背景,则TextView的文本像素就会被绘制两次,一次是绘制背景,一次是文本;产生过度绘制的原因有:同一层级的View的叠加和复杂的层级叠加
    6. 使用系统自带的资源
    7. 使用内存相关工具检测,在开发的过程中,有意识地使用内存检测工具来进行专门的检查,如Lint,MAT等

    Android内存优化——官方篇

    • 节制地使用Service,当我们启动一个Service时,系统会倾向于将这个Service依赖的进程保留,这会让这个进程变得非常耗内存,只有当任务需要运行时,才让Service运行起来。因此为了控制Service的生命周期,官方推荐用IntentService替代Service,这样当任务执行完后,这个Service会自动停止,从而最大限度地避免Service内存泄漏。
    • 当界面不可见和内存紧张时,释放内存(OnTrimMemory()回调)
    • 检查可以使用的内存数量
    • 避免在Bitmap上浪费内存,不要去加载不需要的高分辨率的图片;
    • 使用优化过的容器,如SparseArraySparseBooleanArray,LongSparseArray
    • 为序列化数据使用nano protobufs;
    • 避免使用依赖注入框架;
    • 使用ProGuard来剔除不需要的代码;
    • 对最终的APK使用zipalign;
    • 分析应用的内存使用情况,进行优化;
  • 相关阅读:
    day10T3改错记
    day9T1改错记
    day8T1改错记
    洛谷P5068[Ynoi2015]我回来了(bfs+bitset)
    BZOJ4939[Ynoi2016]掉进兔子洞(莫队+bitset)
    [学习笔记]dsu on tree
    [学习笔记]FWT(快速沃尔什变换)
    [学习笔记]FMT(快速莫比乌斯变换)&子集卷积(待填坑)
    POJ-1743-Musical Theme(后缀数组)
    后缀数组模板
  • 原文地址:https://www.cnblogs.com/WoodJim/p/4712585.html
Copyright © 2020-2023  润新知