自定义无内存泄漏的Handler内部类
2016-07-13 00:08
609 查看
最近做项目有很多需要在子线程中进行耗时操作,因为操作也比较简单,也就是单纯的发送网络请求然后处理回调更新UI,所以选择了Thread+Runnable+Handler的组合。
然后有了最初的代码:
代码片段1:SGAddressFragment.java
其实很多人可能一不小心就会写出这样的代码,好在Android Studio检测出来了这样的情况,并且给出了警告:
Android Studio自己检查出来可能出现内存泄漏,然后他推荐我们使用静态类来避免。为什么一定要是静态内部类?这里应该很多人都知道,非静态内部类会持有外部类的引用,而静态内部类则不会有这样的情况。具体原因可以参考这篇文章。那么我们就照它所推荐的方法,将Handler改造成静态内部类:
代码片段2:
以上就将我们的Handler改造成了静态的内部类。这里由于更新要用到外部类Fragment里的非静态方法,所以将一个Fragment对象传进来,而大家可以看到,我使用了WeakReference对传入的对象进行弱引用处理,我们可以借助弱引用类型对外部非静态变量进行操作,而Handler仅有一条弱引用指向了Fragment对象,所以不会影响Fragment的回收,使用WeakReference也是避免内存泄漏很重要的一点。
还有一点不得不说,眼尖的朋友可以看到,在代码片段1里,当我start了线程之后,有这样一段代码:
这样我们就能彻底避免内存泄露啦!
所以综上所述,只有做到这“三重”防护,我们才算是真正做到避免了内存泄漏☺。
然后有了最初的代码:
代码片段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();
这样我们就能彻底避免内存泄露啦!
所以综上所述,只有做到这“三重”防护,我们才算是真正做到避免了内存泄漏☺。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories