zoukankan      html  css  js  c++  java
  • Android -> 怎样避免Handler引起内存泄露

    很多其它内容,可訪问个人博客www.liangfeizc.com

    错误代码

    假设在Activiy中通过内部类(Runnable)的方式定义了一个变量runnable,

    final Runnable runnable = new Runnable() {
        public void run() {
            // ... do some work
        }
    };
    handler.postDelayed(runnable, TimeUnit.SECONDS.toMillis(10)
    

    由于Runnable不是static类型,所以会有一个包括Activity实例的implicit reference --- Activity.this。

    假设Activity在runnable变量run之前(10s内)被finish掉了可是Activity.this仍然存在。那么Activity的对象就不会被GC回收,从而导致memory leak

    即使使用一个静态内部类,也不能保证万事大吉。

    static class MyRunnable implements Runnable {
        private View view;
        public MyRunnable(View view) {
            this.view = view;
        }
        public void run() {
            // ... do something with the view
        }
    }
    

    如果在runnable运行之前。View被移除了。可是成员变量view还在继续引用它,仍然会导致memory leak

    上面的两个样例其中,导致内存泄露的两种使用方法各自是隐式引用(implicit reference)显式引用(explicit reference)

    解决方法

    解决隐式引用的方法比較简单。仅仅要使用内部非静态类(non-static inner class)或者 top-level class(在一个独立的java文件里定义的变量)就能够将隐式变为显式,从而避免内存泄露。

    假设继续使用非静态内部类,那么就要在onPause的时候手动结束那些挂起的任务(pending task)。

    关于怎样结束不论什么,Handler可參考这篇文章中的Canceling a pending RunnableCanceling pending Messages。HandlerThread可參考这篇文章

    解决第二个问题要用到WeakReference。WeakReference的使用方法能够google一下。简而言之就是:仅仅要还有其它的stronger reference。WeakReference就能够继续引用。

    static class MyRunnable implements Runnable {
        private WeakReference>View< view;
        public MyRunnable(View view) {
            this.view = new WeakReference>View<(view);
        }
        public void run() {
            View v = view.get();
            if (v != null) {
                // ... do something with the view
            }
        }
    }
    

    这样一来问题就攻克了。美中不足的是每次使用view之前都要做空指针推断。另外一个比較高效的方法就是在onResume中为runnable的view赋值,在onPause中赋值为null。

    private static class MyHandler extends Handler {
        private TextView view;
        public void attach(TextView view) {
            this.view = view;
        }
        public void detach() {
            view = null;
        }
        @Override
        public void handleMessage(Message msg) {
            // ....
        }
    

    总结

    在继承Handler或者HandlerThread的时候。

    • 尽量定义一个static类或者top-level类。
    • 假设用到了ui元素,一定要在Activity的生命周期接触之前释放掉。

    參考

    Asynchronous Android - Steve Liles

  • 相关阅读:
    Firefox页面截图插件Pearl Crescent Page Saver
    Effective C++ (5) 几个关于数组的问题
    Notice
    Effective C++ (4) c++中的命名空间
    Effective C++ (7) 强制类型转换
    Effective C++ (3) 避免C++头文件的多重包含
    Effective C++ (2) C#中的Const和Readonly
    总结一下这段时间的生活
    如何让rose一开始的那个向导对话框出现?
    Effective C++ (8) 顺序容器vector,list,deque
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/5136751.html
Copyright © 2011-2022 走看看