10.2019安卓性能优化相关

LeakCanary检测内存泄漏的原理

LeakCanary在Application中install既初始化之后,通过ApplicationContext统一注册监听的方式(application.registerActivityLifecycleCallbacks),来观察所有的Activity的生命周期,在Activity执行onDestroy的时候通过RefWatcher执行watch方法来检测本页面是否存在内存泄漏的问题(watch传入的参数是activity引用,如果我们想单独监听某块代码,如fragment或View等,我们需要手动去调用watch()来检测;因为默认的watch()仅执行于Activity的Destroy时),watch方法会创建一个 KeyedWeakReference(key value的形式保存activity引用,防止在多个相同Activity实例存在的时候无法判断是哪个activity) 来包装要被监控的对象。然后根据检测引用是否被清除(如何判断引用是否被清除?被弱引用包裹的actvity如果被回收,就会把这个弱引用加入到引用队列,如果队列中存在这个activity的弱引用,那么就说明activity被回收),如果当前引用不存在了,说明没有泄漏发生,不再执行。如果当前引用仍然存在,则手动触发一次gc操作,然后再次检测引用是否被清除,如果是,说明没有泄漏发生,如果仍然存在,则说明发生了内存泄漏,生成文件,保存内存分析信息 。

性能优化的几个方面

1.布局优化

a.降低布局层级,合理的选用适合某场景的ViewGroup,例如,LinearLayout和FrameLayout都是一种简单高效的ViewGroup,而RelativeLayout比较复杂
b.标签的使用 ,ViewStub可以通过setVisibility和inflate方法加载,二者的区别在于setVisibility可以多次调用,第一次调用的时候视将ViewStub替换掉,之后都只是设置显示,而inflate只能调用一次,第二次调用会抛出异常

2.绘制优化

主要针对View的onDraw方法,第一,避免在onDraw中创建新的布局对象,第二,onDraw方法中不做耗时任务,也不要执行大量的循环操作

3.内存泄漏优化

a.避免静态变量引用Activity,如静态Context静态View
b.静态单例模式的观察者持有activity引用没有及时unregister
b.属性动画导致内存泄漏,注意在Activity onDestory的时候取消动画animator.cancel()
c.避免非静态内部类持有Activity引用
d.避免Context Handler的不合理使用导致的泄漏

4.响应速度优化和避免ANR

主线程不做耗时操作,并且防止代码中出现的ANR问题,trace.txt文件帮助Anr检测

5.列表和bitmap优化

ListView GridView RecyclerView的优化主要关注点是根据列表滑动状态来控制任务的执行频率,比如当列表快速滑动时不进行异步任务操作,第二点开启硬件加速使列表滑动更流畅

6.线程优化

使用线程池,线程池可以避免线程的创建和销毁带来的性能开销,还能控制线程的最大并发数,避免线程抢占系统资源而导致阻塞现象

7.其他细节优化

a.避免创建过多对象
b.避免使用枚举,可以用@IntDef代替
c.常量使用static final修饰
d.使用Android特有的数据结构,如SparseArray ArrayMap等轻量数据结构
e.合理使用弱引用和软引用
f.合理使用内存
g.采用静态内部类避免内存泄漏

性能优化工具

1.Memory Monitor:监视应用程序的性能和内存使用情况
CPU Monitor:
GPU Monitor:
Network Monitor:
2.Allocation Tracker:

webview怎么优化加载速度

1.开启离线缓存
在缓存可获取并且没有过期的情况下加载缓存,否则通过网络获取资源。这样的话可以减少页面的网络请求次数。
离线的情况下,设置缓存策略为setCacheMode(WebSettings.LOAD_CACHE_ONLY) 不使用网络,只加载缓存。
针对资源无法及时更新的问题,WebSettings.LOAD_DEFAULT中的页面中的缓存版本好像不是很起作用,我们需要自己做一个缓存版本控制。这个缓存版本控制可以放在APP版本更新中,在版本更改时清空webview缓存
2.预加载
将页面加载的大量资源打包进APK里面,然后当页面加载这些资源的时候让它从本地获取,这样可以提升加载速度也能减少服务器压力
3.H5优化
Android的OnPageFinished事件会在Javascript脚本执行完成之后才会触发。iPhone是显示完页面才会触发脚本的执行。所以我们这边的解决方案延迟JS脚本的载入,这个方面的问题是需要Web前端工程师帮忙优化的,网上应该有比较多LazyLoad插件
4.加载时先加载文本,后加载图片调用方式如下:

public void onProgressChanged(WebView view, int newProgress) { 
if (newProgress == 100) { 
    // 网页加载完成 
    settings.setBlockNetworkImage(false); 
} else { 
    // 网页加载中
 } 
webview内存泄漏的原因

webview引起的内存泄漏主要是因为org.chromium.android_webview.AwContents 类中注册了component callbacks,但是未正常反注册而导致的。
org.chromium.android_webview.AwContents 类中有这两个方法 onAttachedToWindow 和 onDetachedFromWindow;系统会在attach和detach处进行注册和反注册component callback;
在onDetachedFromWindow() 方法的第一行中:
if (isDestroyed()) return;,

如果 isDestroyed() 返回 true 的话,那么后续的逻辑就不能正常走到,所以就不会执行unregister的操作;我们的activity退出的时候,都会主动调用 WebView.destroy() 方法,这会导致 isDestroyed() 返回 true;destroy()的执行时间又在onDetachedFromWindow之前,所以就会导致不能正常进行unregister()。
然后解决方法就是:让onDetachedFromWindow先走,在主动调用destroy()之前,把webview从它的parent上面移除掉。
ViewParent parent = mWebView.getParent();
if (parent != null) {
((ViewGroup) parent).removeView(mWebView);
}

mWebView.destroy();

完整的activity的onDestroy()方法:

@Override
protected void onDestroy() {
    if( mWebView!=null) {

        // 如果先调用destroy()方法,则会命中if (isDestroyed()) return;这一行代码,需要先onDetachedFromWindow(),再
        // destory()
        ViewParent parent = mWebView.getParent();
        if (parent != null) {
            ((ViewGroup) parent).removeView(mWebView);
        }

        mWebView.stopLoading();
        // 退出时调用此方法,移除绑定的服务,否则某些特定系统会报错
        mWebView.getSettings().setJavaScriptEnabled(false);
        mWebView.clearHistory();
        mWebView.clearView();
        mWebView.removeAllViews();
        mWebView.destroy();

    }
    super.on Destroy();
}

你可能感兴趣的:(10.2019安卓性能优化相关)