Android 有关线程非静态内部类+弱引用避免内存泄漏记录

      分享一篇文章说明(非静态内部类(包括匿名内部类),默认就会持有外部类的引用,当非静态内部类对象的生命周期比外部类对象的生命周期长时,就会导致内存泄漏。)

      目前在我的项目中也都尽量采用了非静态内部类+弱引用的方式来处理线程,给自己简单记录一下

Android典型(容易造成内存泄漏)场景一:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rxjava);
        Message message=Message.obtain();
        message.what=1;
        handler.sendMessage(message);
    }
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                //........................
            }
        }
    };

引用文章 ----   也许有人会说, mHandler 并未作为静态变量持有 Activity 引用, 生命周期可能不会比 Activity 长,应该不一定会导致内存泄露呢, 显然不是这样的!


熟悉 Handler 消息机制的都知道, mHandler 会作为成员变量保存在发送的消息 msg 中, 即 msg 持有handler 的引用, 而 handler 是 Activity 的非静态内部类实例, 即 handler 持有 Activity 的引用, 那么我们就可以理解为 msg 间接持有 Activity 的引用。 msg 被发送后先放到消息队列
MessageQueue 中, 然后等待 Looper 的轮询处理(MessageQueue 和 Looper 都是与线程相关联的,MessageQueue 是 Looper 引用的成员变量, 而 Looper 是保存ThreadLocal 中的)。 那么当 Activity退出后, msg 可能仍然存在于消息对列 MessageQueue 中未处理或者正在处理, 那么这样就会导致Activity 无法被回收, 以致发生 Activity 的内存泄露。

 

 

通常在 Android 开发中如果要使用内部类, 但又要规避内存泄露, 一般都会采用静态内部类+弱引用的方式。

 

   Activiy 代码示例:

public class TestActivity extends AppCompatActivity {
    private Handler handler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rxjava);

        handler=new MyHandler(this);
        Message message = Message.obtain();
        message.what = 1;
        handler.sendMessage(message);
    }


    private class MyHandler extends Handler {
        private WeakReference weakReference;

        public MyHandler(TestActivity testActivity) {
            weakReference = new WeakReference<>(testActivity);
        }

        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            TestActivity testActivity = weakReference.get();
            if(testActivity!=null){
                switch (msg.what){
                    //.............
                }
            }
        }
    }

/*handler通过弱引用的方式持有 Activity, 当 GC 执行垃圾回收时, 遇到 Activity 就会回收并释
放所占据的内存单元。 这样就不会发生内存泄露了。
上面的做法确实避免了 Activity 导致的内存泄露, 发送的 msg 不再已经没有持有 Activity 的引用
了, 但是 msg 还是有可能存在消息队列 MessageQueue 中, 所以更好的是在 Activity 销毁时就将
handler的回调和发送的消息给移除掉。*/

    @Override
    protected void onDestroy() {
        super.onDestroy();
        handler.removeCallbacksAndMessages(null);
    }
}

 fragemnt:

 

 

public class BlankFragment extends Fragment {
    private Handler handler;
    public BlankFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view=inflater.inflate(R.layout.fragment_blank, container, false);
        handler=new MyHandler(getActivity());
        Message message=Message.obtain();
        message.what=1;
        handler.sendMessage(message);
        return view;
    }


    private class MyHandler extends Handler {
        private WeakReference weakReference;

        public MyHandler(Activity activity) {
            weakReference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Activity activity = weakReference.get();
            if (activity != null) {
                switch (msg.what) {
                    //......................
                }
            }
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        handler.removeCallbacksAndMessages(null);
    }
}

还有 Thread和AsyncTask的写法一样都会容易造成泄漏,我们可以按照Handler的方法来处理。

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rxjava);
        

      new Thread(new Runnable() {
          @Override
          public void run() {
              try {
                  Thread.sleep(3000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
      }).start();
      
      
    }

 

Activity Thread参考例子:

public class TestActivity extends AppCompatActivity {
    //  private Handler handler;
    // private MyAsyncTask myAsyncTask;
    private Thread mythread;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rxjava);
       //第一种写法,匿名内部类
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        //第二种写法,非静态内部类+弱引用
        mythread= new Thread(new MyThreadRunnable(this));
        mythread.start();
    }

    private class MyThreadRunnable implements Runnable {
        private WeakReference weakReference;

        public MyThreadRunnable(TestActivity testActivity) {
            weakReference = new WeakReference<>(testActivity);
        }
        @Override
        public void run() {
            TestActivity testActivity=weakReference.get();
            if(testActivity!=null){
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mythread.destroy();
    }
}








 

Activity AsyncTask 参考例子:

public class TestActivity extends AppCompatActivity {
  //  private Handler handler;
    //  private MyAsyncTask handler;
     private MyAsyncTask myAsyncTask;

    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rxjava);

      //第一种写法,匿名内部类
      new AsyncTask(){
          @Override
          protected Void doInBackground(Void... voids) {
              try {
                  Thread.sleep(3000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              return null;
          }
      }.execute();

    //第二种写法,非静态内部类+弱引用
        myAsyncTask= new MyAsyncTask(this);
        myAsyncTask.execute();
    }



   private class MyAsyncTask extends AsyncTask {
       private WeakReference weakReference;

       public MyAsyncTask(TestActivity testActivity) {
           weakReference = new WeakReference<>(testActivity);
       }

       @Override
       protected Void doInBackground(Void... voids) {

           TestActivity testActivity=weakReference.get();

           if(testActivity!=null){
               try {
                   Thread.sleep(3000);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }

           return null;
       }
   }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        myAsyncTask.cancel(true);
    }
}




后面这两个的例子是我自己模仿Handler的写法,写出来的例子,如果有什么写错的,可以评论留言正确的写法,我再改正回来。

你可能感兴趣的:(线程)