老李分享:Android性能优化之内存泄漏 2

Handler造成的内存泄漏

Handler的使用造成的内存泄漏问题应该说最为常见了,平时在处理网络任务或者封装一些请求回调等api都应该会借助Handler来处理,对于Handler的使用代码编写一不规范即有可能造成内存泄漏,如下示例:

 

public class MainActivity extends AppCompatActivity {

    private Handler mHandler = new Handler() {

        @Override

        public void handleMessage(Message msg) {

            //...

        }

    };

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        loadData();

    }

    private void loadData(){

        //...request

        Message message = Message.obtain();

        mHandler.sendMessage(message);

    }

}

这种创建Handler的方式会造成内存泄漏,由于mHandler是Handler的非静态匿名内部类的实例,所以它持有外部类Activity的引用,我们知道消息队列是在一个Looper线程中不断轮询处理消息,那么当这个Activity退出时消息队列中还有未处理的消息或者正在处理消息,而消息队列中的Message持有mHandler实例的引用,mHandler又持有Activity的引用,所以导致该Activity的内存资源无法及时回收,引发内存泄漏,所以另外一种做法为:

public class MainActivity extends AppCompatActivity {

    private MyHandler mHandler = new MyHandler(this);

    private TextView mTextView ;

    private static class MyHandler extends Handler {

        private WeakReference<Context> reference;

        public MyHandler(Context context) {

            reference = new WeakReference<>(context);

        }

        @Override

        public void handleMessage(Message msg) {

            MainActivity activity = (MainActivity) reference.get();

            if(activity != null){

                activity.mTextView.setText("");

            }

        }

    }

 

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        mTextView = (TextView)findViewById(R.id.textview);

        loadData();

    }

 

    private void loadData() {

        //...request

        Message message = Message.obtain();

        mHandler.sendMessage(message);

    }

}

创建一个静态Handler内部类,然后对Handler持有的对象使用弱引用,这样在回收时也可以回收Handler持有的对象,这样虽然避免了Activity泄漏,不过Looper线程的消息队列中还是可能会有待处理的消息,所以我们在Activity的Destroy时或者Stop时应该移除消息队列中的消息,更准确的做法如下:

public class MainActivity extends AppCompatActivity {

    private MyHandler mHandler = new MyHandler(this);

    private TextView mTextView ;

    private static class MyHandler extends Handler {

        private WeakReference<Context> reference;

        public MyHandler(Context context) {

            reference = new WeakReference<>(context);

        }

        @Override

        public void handleMessage(Message msg) {

            MainActivity activity = (MainActivity) reference.get();

            if(activity != null){

                activity.mTextView.setText("");

            }

        }

    }

 

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        mTextView = (TextView)findViewById(R.id.textview);

        loadData();

    }

 

    private void loadData() {

        //...request

        Message message = Message.obtain();

        mHandler.sendMessage(message);

    }

 

    @Override

    protected void onDestroy() {

        super.onDestroy();

        mHandler.removeCallbacksAndMessages(null);

    }

}

使用mHandler.removeCallbacksAndMessages(null);是移除消息队列中所有消息和所有的Runnable。当然也可以使用mHandler.removeCallbacks();或mHandler.removeMessages();来移除指定的Runnable和Message。


你可能感兴趣的:(软件测试开发)