Android之AsyncTask的内存泄露问题

AsyncTask是Android提供的一种用于异步处理数据的异步类,使用AsyncTask可以不用直接使用Thread和Handler来处理后台操作。AsyncTask被引入到Android中就被贴上了"无忧线程"的标签,目的是为了让子线程与UI线程交互更加简单容易。AsyncTask其本质是一个由5个核心线程组成的,最大队列数为128的线程池。我们在使用的过程中,通常会重写doInBackground(Params…) 方法,该方法在子线程中,所以比较耗时的操作都可以放在这里,由于这个方法在子线程中所以就不能直接操作UI。我们在doInBackground完成耗时操作之后返回结果,在onPostExecute方法中更新UI,该方法相当于Handler处理UI的方式。虽然说AsyncTask操作简单,但是AsyncTask并不是毫无缺点的,它的缺点甚至可以说比较糟糕的。

生命周期。有时候我们会认为在Activity中创建的AsyncTask内部类会随着Activity的销毁而被销毁结束。其实并不是这样,AsyncTask会一直执行,直到doInBackground方法执行完成。此时,如果执行cancel(boolean)操作,onCancelled(Result result) 方法会被执行。这样AsyncTask占据的内存才会被通知回收。否则,会继续执行onPostExecute(Result result) 方法。如果我们的Activity销毁之前,没有取消 AsyncTask,这有可能让我们的AsyncTask崩溃(crash)。也就是说我们在Activity销毁之前要手动cancel掉AsyncTask。因为此时AsyncTask已经没有存在的意义了。

但是有一点比较坑爹,有时候你即使执行了cancel操作,也未必就会取消AsyncTask的运转。因为doInBackground方法中有一个不可中断的操作,比如BitmapFactory.decodeStream(),这个操作会继续执行下去。所以这个方法里面不要执行不可以中断的操作。

内存泄露,根据上面对AsyncTask生命周期的分析可以发现,如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会保留一个对创建了AsyncTask的Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄露。

所以还是那句话,在Activity销毁之前cancel掉AsyncTask。即中断AsyncTask的执行,因为此时已经没有必要让AsyncTask继续执行了。

结果丢失,屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。

在Android 1.6之前的版本,AsyncTask是串行的,在1.6至2.3的版本,改成了并行的。在2.3之后的版本又做了修改,可以支持并行和串行,当想要串行执行时,直接执行execute()方法,如果需要并行执行,则要执行executeOnExecutor(Executor)。


你可能感兴趣的:(Android)