美文网首页
非静态内部类Handler类引起内存泄露

非静态内部类Handler类引起内存泄露

作者: 程序员学园 | 来源:发表于2017-04-04 01:01 被阅读0次

    最近在项目中使用延时Handler做Splish页面的跳转。

    
    new Handler().postDelayed(new Runnable() {
           @Override
           public void run() {
           Intent intent = new Intent(SplishActivity.this,MainActivity.class);
           startActivity(intent);
           finish();
        }
    },100);
    
    

    谁知道产生如下内存泄露。

    static android.app.Instrumentation.mRecommendActivity
    
    referencs android.app.Instrumentation$RecommendActivity.mTarget
    
    leaks XXX.SplishActivity instance
    
    8D922718668811AB9F21445AB0017F90.jpg

    仔细一想确实是这么回事,因为可能延时Handler还没处理消息,页面就finish了,但是因为Handler是非静态内部内,会持有外部Activity的引用,所以导致外部Activity不能被销毁,故而产生内存泄露。

    所以为了安全起见,把Handler改为静态内部类,并且持有弱引用。

     private Handler mHandler = new MyHandler(this);
        private static class MyHandler extends Handler{
            private final WeakReference<Activity> mActivity;
            public MyHandler(Activity activity) {
                mActivity = new WeakReference<Activity>(activity);
            }
            @Override
            public void handleMessage(Message msg) {
                System.out.println(msg);
                if(mActivity.get() == null) {
                    return;
                }
            }
        }
        private Runnable mRunable = new Runnable() {
            @Override
            public void run() {
                Intent intent = new Intent(SplishActivity.this,MainActivity.class);
                startActivity(intent);
                finish();
            }
        };
    
    
    mHandler.postDelayed(mRunable,100);
    
      @Override
        protected void onDestroy() {
            super.onDestroy();
            mHandler.removeCallbacks(mRunable);
        }
    

    总结内部Handler类引起内存泄露的原因

    1、当Android应用启动的时候,会先创建一个应用主线程的Looper对象,Looper实现了一个简单的消息队列,一个一个的处理里面的Message对象。主线程Looper对象在整个应用生命周期中存在。

    2、当在主线程中初始化Handler时,该Handler和Looper的消息队列关联。发送到消息队列的Message会引用发送该消息的Handler对象,这样系统可以调用 Handler#handleMessage(Message) 来分发处理该消息。

    3、在Java中,非静态(匿名)内部类会引用外部类对象。而静态内部类不会引用外部类对象。
    如果外部类是Activity,则会引起Activity泄露

    4、当Activity finish后,延时消息会继续存在主线程消息队列中,然后处理消息。而该消息引用了Activity的Handler对象,然后这个Handler又引用了这个Activity。这些引用对象会保持到该消息被处理完,这样就导致该Activity对象无法被回收,从而导致了上面说的 Activity泄露。

    5、要修改该问题,只需要按照Lint提示的那样,把Handler类定义为静态即可,然后通过WeakReference 来保持外部的Activity对象。

    更正一下

    上面

    mHandler.postDelayed(mRunable,100);
    

    上面用mRunable还是提示内存泄露。

    改成sendMessageDelayed

     mHandler.sendMessageDelayed(Message.obtain(), 100);
    
    

    相关文章

      网友评论

          本文标题:非静态内部类Handler类引起内存泄露

          本文链接:https://www.haomeiwen.com/subject/uqhaottx.html