Android性能相关--经验篇
来源:互联网 发布:微信开发 未备案域名 编辑:程序博客网 时间:2024/06/14 04:14
基础知识
底层触发回收机制时机:
- GC_MALLOC内存分配失败时触发
- GC_CONCURRENT分配的对象大小超过384K时触发
- GC_EXPLICIT对垃圾手机的显示调用(System.gc)
- GC_EXTERNAL_ALLOC外部内存分配失败时触发
常见性能问题
UI卡顿:60fps=1000ms / 16ms
- ui线程有微耗时操作
- overdraw(层叠太多,Layout布局重叠或View在draw的时候重叠)
- 同一时间执行动画次数太多
- view频繁触发measure、layout导致measure、layout耗时过多以及view的重新渲染
- 内存频繁触发GC,导致暂时阻塞渲染操作
- 冗余资源及逻辑等导致加载和执行缓慢
ANR:1.主线程5s内没有处理完输入事件 2.主线程10s没处理完BroadCastReceiver.onReceive 3.主线程在Service各生命周期函数时20s没处理完
- 其他进程(包括系统)占用CPU,导致App分配不到足够的CPU时间片。CPU很高,说明当前设备很忙,CPU资源被抢占导致ANR–>Log中搜ActivityManager标签
- 主线程有耗时操作
○ IOwait很高,很可能主线程执行耗时IO操作
○ 网络访问
○ 大量的数据读写
○ 数据库操作
○ 硬件操作(camera等)
○ 其他线程持有锁,导致主线程等待超时 - 其他,主线程被BLOCK
OOM:试图申请的内存+已分配的内存>虚拟机允许的最大内存
- ArrayMap/SparseArray轻量级的数据结构
- 避免使用Enum 枚举
- 图片优化
- String的拼接用StringBuilder
- onDraw里不创建对象
- 避免内存泄漏(应用分配的堆内存16M-48M)
- 静态变量持有大量数据引用
- 资源关闭、注册注销
- 非静态内部类
- ApplicationContext代替ActivityContext
- Handler等异步类的泄露
- 内存对象的重复利用
- 对象池(自建或利用系统,最近使用最多算法)
- 利用系统自带资源(字符串、颜色、图片、动画、样式、简单布局)
- StringBuilder、StringBuffer
内存泄漏:无用对象持续占用内存或得不到及时释放
- Activity的内存泄漏:内部类(Handler和Thread)、Context(尽量使用Application的Context,Dialog必须使用Activity的Context)
- 临时资源主动回收
- 监听器的回收(register、unregister、add listener、remove listener)
- WebView本身泄漏问题(可开一个进程加载WebView,不用时直接销毁整个进程)
- Cursor对象的关闭
- 单例泄漏:单例的生命周期跟app一样长,如果单例持有activity的context等会导致其无法释放【可持有context.getApplicationContext()】
- 匿名内部类/非静态内部类(尤其是放在Activity中的):静态内部类默认持有外部类的引用,若内部类有静态变量则其生命周期也是跟app一样长,导致外部类(尤其为Activity)无法释放【可将内部类置为静态类则不会持有外部类引用】
- Handler:handler为内部类会持有外部类(尤其Activity)的引用,而activity结束时若handler的消息还没处理完则导致内存泄漏【handler置为静态类,且内部若持有外部对象则置为弱引用WeakReference】
- AsyncTask:内存泄漏情况跟Handler一样【外部类退出时调用AsyncTask.cannel()结束掉它】
- 资源未关闭:广播的注册于注销等
内存泄漏检测
- 优先处理常见泄漏Analyze-Inspect Code:常见的有内部类Handler/Thread、IO操作Cursor/FileInputStream、View中使用TypedArray、四大组件的Context(Dialog、startActivity、Layout.Inflation必须用Activity;其他都可以用Application的)
- 开源检测项目Leakcanary
- adb shell;dumpsys meminfo com.hsb.mydemo -d;进入页面前调用命令,查看view等数量–>进入页面各种操作–>退出页面手动触发GC–>调用命令查看view等数量是否一致
- MAT
App闪退常见原因:NullPointer、OOM、数组越界
Force Close常见原因:Error、OOM(内存溢出)、StackOverFlowError、RuntimeException空指针异常
优化建议
代码优化建议
- 数据结构的选择:SparseArray代替HashMap,需注意:1、SparseArray不是线程安全的2、插入按key排序3、删除做了优化,不会立即删除而是设置标志位,后面尝试重用
- Handler和内部类的正确用法
private static Class InnerHandler extends Handler{ private final WeakReference<HandlerActivity> mActivity; public InnerHandler(HandlerActivity activity){ mActivity = activity; } @Override public void handleMessage(){ HandlerActivity activity = mActivity.get(); if(activity != null){...} }}
- 正确使用Context
应用中的Context个数=Activity个数+Service个数+1个ApplicationContext
Application是一个单例,可以context.getApplicationContext()来获取
Activity、Service都是ContextWrapper子类,可以通过getBaseContext来获取各自的Context
BroadcastReceiver有系统通过onReceive传入的一个Context,该Context经过系统的功能裁剪,不可调用registerReceiver和bindService
ContentProvider可以通过getContext获取一个系统传入的Context。如果ContentProvider和调用者在同一个进程中则Context返回的是全局唯一的Context实例;如果不在同一个进程,则Context是ContentProvider所在进程的Context实例
Context的使用问题在于:在单例中如果传入的Context刚好是Activity/Service的则Activity/Service销毁的时候因为单例还存在则导致Activity/Service无法回收
正确使用方式
public class SingleInstance{ private Context mContext; private static SingleInstance sInstance; private SingleInstance(Context context){ mContext = context; } public static SingleInsatance getInstance(Context context){ if(sInstance == null){ sInstance = new SingleInstance(context.getApplicationContext()); } return sInstance; }}
- 对常量使用static修饰
- 使用过静态方法比普通方法提高15%访问速度
- 减少成员变量的定义(尽量缩小变量的作用域)
- 尽量减少new对象
- 尽量少使用枚举、迭代器
- 对Cursor、Receiver、Sensor、File等对象注意他们的创建-回收-注册-解注册
- 避免使用IOC,注解反射的实现会导致性能下降
- 使用RenderScript、OpenGL来进行复杂的绘制
- 使用SurfaceView代替View进行大量、频繁的绘图
图片优化
- 图片格式JPEG(不支持透明度)/PNG(体积大)/WebP
- 图片的压缩:ImageAlpha有损压缩、TinyPNG有损压缩、ImageOptim无损压缩
- 内存减少(inSampleSize缩放比例,ARGB4444,LRUCache,xml中加载的图片不会进行优化)
- LRUCache:LinkedHashMap+最近最少使用算法(使用的时候把item移到队列头,队列尾即最近最少使用的了),回收对象只需将其remove,GC自然会回收(存在队列中则持有强引用,remove后则不可达)
- 不用的时候recycle
- inBitmap
电量优化
- 应用切换到后台应该尽量避免一些不必要的操作,特别是BroadcastReceiver、Service中的一些操作
- 数据传输:蓝牙传输、WIFI传输、移动网络传输。尽量做到:1、应用进入后台避免不必要的传输2、数据传输应根据业务进行合理的合并网络请求,避免轮询等
- GPS定位,耗电
- AlannManager系统级别的唤醒服务,比较耗电
- WakaLock保持设备处于唤醒状态(即使用户长时间不操作),非常耗电
布局优化
- 避免overdraw,检测工具Enable GPU Overdraw
- 优化布局层级,View树尽量低
- 避免嵌套过多无用布局
- 多用来替代FrameLayout,减少不必要的层
- 重用
- view的延迟加载;用此可推迟布局加载
- 多用RelativeLayout少用LinearLayout,减少布局层次
- 工具HierarchyViewer;github.com/romainguy/ViewServer
网络优化
- 避免DNS解析,使用IP访问代替域名访问
- 合并网络请求
- 预先获取数据
- 避免轮询
- 优化重连机制
- 离线缓存
- 压缩数据大小
- 不同的网络环境使用不同的超时策略
- CDN的使用
ListView优化
- 重用converView
- 减少findViewById
- 避免在getView中做耗时操作
- RecycleView代替ListView(对比)
- 避免半透明元素(滑动过程消耗很大,可滑动过程不透明,滑动完再设置透明)和item的过度复杂。
- 开启硬件加速
动画优化 CPU/GPU 内存
1.常规优化(图片优化 调用刷新的时机减少invalidate以及invalidate带参数 数据的提前准备 多个view做动画->一个view做多个动画)
2.逻辑优化 动画本身的实现方法 动画的状态控制
3.布局优化 不再改变或者消失的或者被遮住的背景的处理 尽可能减少layer
4.是否开启硬件加速,开启硬件加速多占用一部分内存
启动优化
1.冷启动优化:1.windowBackround设置为透明2.windowBackground设置欢迎图3.windowBackground设置为首页布局
2.Application里尽量不做初始化
3.oncreate 里不要做耗时操作 onstart可见 onresume可触
4.mat可以查看每个方法的执行时间和执行次数,可用于检测
○ 内存泄漏
■ Drawable.Callback引起内存泄漏
■ staitc中不要保存Drawable对象
■ 保存Drawable对象时,调用Drawable.setCallback(null)
■ Context泄漏
■ Handler泄漏
○ 转移图片内存地址;java虚拟机16M内存,Native4G内存。
■ 图片少:可将图片放到java heap中
■ 图片多:放到native中
● BitmapFactory.Options
○ -inNativeAlloc//图片内存放在native
■ BitmapFactory.Options.class.getField(inNativeAlloc).setBoolean(options,true);
- Android性能相关--经验篇
- Android性能相关--工具篇
- Android相关经验积累总结
- Android 性能优化相关
- Android性能优化相关
- android性能优化相关
- Android-性能相关
- Android性能优化相关资料
- Android性能相关常用命令收集
- android系统性能相关学习
- Android性能相关常用命令收集
- android 性能优化相关整理
- Android性能工具相关教程
- Android应用性能优化系列逻辑篇——线程相关性能优化
- 【Android开发经验】Android相关问题的好文章整理
- Android——性能优化相关文章
- Android 线性布局(LinearLayout)性能相关
- 8.Android String相关类性能测试
- 洛谷P1455 搭配购买(tarjan+dp)
- 拔盘Demo大赛,1000元现金等你拿!
- Web 缓存知识
- Trees in a Row CodeForces
- PHP方法字符串拼接转化mysql进行数据查询
- Android性能相关--经验篇
- 基于主键创建物化视图(MATERIALIZED VIEW)
- 完成端口模型IOCP详解 (一)
- Linux中修改环境变量
- idea中安装jrebel插件实现热部署
- 从键盘输入一个大写字母,要求改用小写字母输出
- 类似网易新闻的导航标题栏
- ionic2-基础环境搭建
- ionic2-动手开始