欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-04-19 17:36:55
...

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

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

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<TestActivity> 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<Activity> 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<TestActivity> 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<Void,Void,Void>(){
          @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<Void, Void, Void> {
       private WeakReference<TestActivity> 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的写法,写出来的例子,如果有什么写错的,可以评论留言正确的写法,我再改正回来。

相关标签: Android