android中的Handler和AsyncTask怎么防止内存泄露
android中的Handler和AsyncTask如何防止内存泄露
Handler泄露的关键点有两个:
1). 内部类
2). 生命周期和Activity不一定一致
第一点,Handler使用的比较多,经常需要在Activity中创建内部类,所以这种场景还是很多的。
内部类持有外部类Activity的引用,当Handler对象有Message在排队,则无法释放,进而导致Activity对象不能释放。
如果是声明为static,则该内部类不持有外部Acitivity的引用,则不会阻塞Activity对象的释放。
如果声明为static后,可在其内部声明一个弱引用(WeakReference)引用外部类。
第二点,其实不单指内部类,而是所有Handler对象,如何解决上面说的Handler对象有Message在排队,而不阻塞Activity对象释放?
解决方案也很简单,在Activity onStop或者onDestroy的时候,取消掉该Handler对象的Message和Runnable。
通过查看Handler的API,它有几个方法:removeCallbacks(Runnable r)和removeMessages(int what)等。
上面的代码太长?好吧,出大招:
AsyncTask的泄露和Handler类似,避免方法如下:
一 适当使用弱引用:
二在activity退出时,终止asynctask任务:
具体退出方法如下:
官方的例子是很好的,在后台循环中时刻监听cancel状态,防止没有及时退出。
Handler泄露的关键点有两个:
1). 内部类
2). 生命周期和Activity不一定一致
第一点,Handler使用的比较多,经常需要在Activity中创建内部类,所以这种场景还是很多的。
内部类持有外部类Activity的引用,当Handler对象有Message在排队,则无法释放,进而导致Activity对象不能释放。
如果是声明为static,则该内部类不持有外部Acitivity的引用,则不会阻塞Activity对象的释放。
如果声明为static后,可在其内部声明一个弱引用(WeakReference)引用外部类。
public class MainActivity extends Activity { private CustomHandler mHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mHandler = new CustomHandler(this); } static class CustomHandlerextends Handler { // 内部声明一个弱引用,引用外部类 private WeakReference<MainActivity > activityWeakReference; public MyHandler(MyActivity activity) { activityWeakReference= new WeakReference<MainActivity >(activity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); MyActivity act= activityWeakReference.get(); if (activityWeakReference!= null && act!= null) { // ...... } } // ... ... } }
第二点,其实不单指内部类,而是所有Handler对象,如何解决上面说的Handler对象有Message在排队,而不阻塞Activity对象释放?
解决方案也很简单,在Activity onStop或者onDestroy的时候,取消掉该Handler对象的Message和Runnable。
通过查看Handler的API,它有几个方法:removeCallbacks(Runnable r)和removeMessages(int what)等。
/ 一切都是为了不要让mHandler拖泥带水 @Override public void onDestroy() { mHandler.removeMessages(MESSAGE_1); mHandler.removeMessages(MESSAGE_2); mHandler.removeMessages(MESSAGE_3); mHandler.removeMessages(MESSAGE_4); // ... ... mHandler.removeCallbacks(mRunnable); // ... ... }
上面的代码太长?好吧,出大招:
@Override public void onDestroy() { // If null, all callbacks and messages will be removed. mHandler.removeCallbacksAndMessages(null); }
AsyncTask的泄露和Handler类似,避免方法如下:
一 适当使用弱引用:
static class DisableChanger extends AsyncTask<Object, Object, Object> { final PackageManager mPm; final WeakReference<InstalledAppDetails> mActivity; final ApplicationInfo mInfo; final int mState; DisableChanger(InstalledAppDetails activity, ApplicationInfo info, int state) { mPm = activity.mPm; mActivity = new WeakReference<InstalledAppDetails>(activity); mInfo = info; mState = state; } }
二在activity退出时,终止asynctask任务:
具体退出方法如下:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> { protected Long doInBackground(URL... urls) { int count = urls.length; long totalSize = 0; for (int i = 0; i < count; i++) { totalSize += Downloader.downloadFile(urls[i]); publishProgress((int) ((i / (float) count) * 100)); // Escape early if cancel() is called // 注意下面这行,如果检测到cancel,则及时退出 if (isCancelled()) break; } return totalSize; } protected void onProgressUpdate(Integer... progress) { setProgressPercent(progress[0]); } protected void onPostExecute(Long result) { showDialog("Downloaded " + result + " bytes"); } }
官方的例子是很好的,在后台循环中时刻监听cancel状态,防止没有及时退出。