自定义无内存泄漏的Handler内部类

Posted 碎格子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义无内存泄漏的Handler内部类相关的知识,希望对你有一定的参考价值。

最近做项目有很多需要在子线程中进行耗时操作,因为操作也比较简单,也就是单纯的发送网络请求然后处理回调更新UI,所以选择了Thread+Runnable+Handler的组合。
然后有了最初的代码:
代码片段1:SGAddressFragment.java

Handler handler;
public void onActivityCreated(@Nullable Bundle savedInstanceState) 
    super.onActivityCreated(savedInstanceState);
    if (getView() != null) 
        ...
        handler = new Handler()
            @Override
            public void handleMessage(Message msg) 
                updateView();
                super.handleMessage(msg);
            
        ;
    


private void saveNewAddress() 
    saveNewThread = new Thread(new Runnable() 
        @Override
        public void run() 
            Message msg = new Message();
            Bundle bundle = new Bundle();
            try 
                boolean isSaved = doSaveNewAddress();
                bundle.putBoolean("boolean_save", isSaved);
             catch (Exception e) 
                e.printStackTrace();
            
            msg.setData(bundle);
            handler.sendMessage(msg);
        
    );
    saveNewThread.start();
    threads.add(saveNewThread);

其实很多人可能一不小心就会写出这样的代码,好在android Studio检测出来了这样的情况,并且给出了警告:

Android Studio自己检查出来可能出现内存泄漏,然后他推荐我们使用静态类来避免。为什么一定要是静态内部类?这里应该很多人都知道,非静态内部类会持有外部类的引用,而静态内部类则不会有这样的情况。具体原因可以参考这篇文章。那么我们就照它所推荐的方法,将Handler改造成静态内部类:
代码片段2:

static class AddressHandler extends Handler 
        WeakReference<SGAddressFragment> sgAddressFragmentRef;

        AddressHandler(SGAddressFragment sgAddressFragment) 
            sgAddressFragmentRef = new WeakReference<>(sgAddressFragment);
        

        @Override
        public void handleMessage(Message msg) 
            boolean b;
            if (msg.getData() != null) 
                sgAddressFragmentRef.get().update();
                
            
            super.handleMessage(msg);
        
    

以上就将我们的Handler改造成了静态的内部类。这里由于更新要用到外部类Fragment里的非静态方法,所以将一个Fragment对象传进来,而大家可以看到,我使用了WeakReference对传入的对象进行弱引用处理,我们可以借助弱引用类型对外部非静态变量进行操作,而Handler仅有一条弱引用指向了Fragment对象,所以不会影响Fragment的回收,使用WeakReference也是避免内存泄漏很重要的一点。
还有一点不得不说,眼尖的朋友可以看到,在代码片段1里,当我start了线程之后,有这样一段代码:threads.add(saveNewThread);而这段代码在内存泄漏处理中也起到了非常大的作用。当我们新开一个线程,如果这个线程的工作一直到Activity被finish掉也没有处理完,那它将一直持有这个Activity导致Activity不能被回收。所以我在代码中创建了一个ArrayList对象用来存入新开的线程:ArrayList<Thread> threads = new ArrayList<>();每当我们新开了线程之后,就将thread对象添加进list里:threads.add(saveNewThread);然后在onDestroy()方法里将所有添加进去的线程中断:

for (Thread thread : threads) 
    if (thread != null && thread.isAlive()) 
        thread.interrupt();
    

threads.clear();

这样我们就能彻底避免内存泄露啦!
所以综上所述,只有做到这“三重”防护,我们才算是真正做到避免了内存泄漏☺。

以上是关于自定义无内存泄漏的Handler内部类的主要内容,如果未能解决你的问题,请参考以下文章

一次性讲清楚 Handler 可能导致的内存泄漏和解决办法

内存泄漏篇--1

解读在Activity中使用Handler的内存泄漏问题

内存泄漏篇--1.基础问题

Handler系列:Handler为什么会引起内存泄漏,怎么解决?

Android面试Android线程间通信Handler消息机制