AsyncTask的正确使用

来源:互联网 发布:淘宝店铺红包在哪里看 编辑:程序博客网 时间:2024/04/29 22:42

首先,附上AsyncTask使用时的缺陷问题:

出处:

http://blog.csdn.net/goodlixueyong/article/details/45895997

原文内容:

在Android开发中,AsyncTask可以使得用户避免直接使用Thread类和Handler 来处理后台操作,适用于需要异步处理数据并将数据更新到界面上的情况。AsyncTask适用于后台操作只有几秒的短时操作。但是AsyncTask本身存在很多糟糕的问题,如果使用中不注意,将会影响程序的健壮性。

1、生命周期

       很多开发者会认为一个在Activity中创建的AsyncTask会随着Activity的销毁而销毁。然而事实并非如此。AsyncTask会一直执行, 直到doInBackground()方法执行完毕。然后,如果 cancel(boolean)被调用, 那么onCancelled(Result result) 方法会被执行;否则,执行onPostExecute(Result result) 方法。如果我们的Activity销毁之前,没有取消 AsyncTask,这有可能让我们的AsyncTask崩溃(crash)。因为它想要处理的view已经不存在了。所以,我们总是必须确保在销毁活动之前取消任务。总之,我们使用AsyncTask需要确保AsyncTask正确地取消

       另外,即使我们正确地调用了cancle() 也未必能真正地取消任务。因为如果在doInBackgroud里有一个不可中断的操作,比如BitmapFactory.decodeStream(),那么这个操作会继续下去。

2、内存泄漏

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

3、结果丢失

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

4、并行还是串行

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



------------------------------------------------------------------------------------------------------------------------------

目前项目中使用了大量的异步任务(AsyncTask)来处理后台接口的数据(执行网络操作)。有时候网络比较慢或者执行长时间的网络的时候(长时网络不建议使用AsyncTask),用户返回当前的Activity,但是doInBackground方法还在执行,如果我们不使用静态内部类的方式来创建AsyncTask的话,这个task会一直持有activity的引用,这就很可能会造成内存泄露,并且当doInBackground方法执行完成,调用onPostExecute去更新UI的时候,更有可能出现异常(使用了已经不存在的View)。

所以我们应该正确的关闭task,并且防止引用activity引起内存泄露。

关于如何关闭Task:

AsyncTask为我们提供了cancel方法,但是只执行cancel是不能够完全停止任务的,特别是doInBackground方法中在执行网络操作,或是线程在执行sleep循环操作的时候,这个时候是打断不了这些操作的。那么cancle到底有什么用呢?

我们来看下如下代码:

private AsyncTask task;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        /* 用匿名内部类的方式创建*/         task = new AsyncTask() {            @Override            protected Object doInBackground(Object[] params) {                for(int i=0;i<10;i++){                    Log.i("task","i="+i);                    try {                        Thread.sleep(2000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    if(isCancelled()){                        break;                    }                }                return null;            }             @Override             protected void onPostExecute(Object o) {                 super.onPostExecute(o);                 Log.i("task","执行结束了");             }             @Override             protected void onCancelled() {                 super.onCancelled();                 Log.i("task","执行了取消");             }         };        task.execute();    }    @Override    protected void onDestroy() {        super.onDestroy();        task.cancel(true);    }
我在activity中简单的创建了一个异步任务(注意这里使用了匿名内部类来创建,这样创建会导致task持有当前activity的引用),doInBackground中执行一个循环计数的操作,每次计数睡眠2s(这里可以看做是一个网络请求的场景),当我把
task.cancel(true);
注释掉后,这个任务该怎么执行还是怎么执行,按返回键退出当前activity后,这个循环计数还在后台继续执行,当执行完成后会调用onPostExecute方法(可看打印结果)

当去掉

task.cancel(true);
的注释,把

if(isCancelled()){                        break;                    }
注释掉。虽然在退出的时候执行了cancel,但是doInBackground里的循环还是继续在执行,但是当执行完成的时候不会再调用onPostExecute方法了,而是调用了onCancelled方法(可看打印结果)


把注释全部取消,我们在doInBackground的for循环体里面做了isCancelled判断,当退出的时候调用task.cancel方法的时候,我们进入这个条件,通过这个条件判断可以退出循环,结束任务,最后调用onCancelled方法。

对于这样的一个场景,我们确实可以通过执行task的cancel方法,通过判断isCancelled值来退出任务,在activity结束的时候就结束了任务。但是相对于其他情况(比如说操作网络的时候),doInBackground方法里面还是会继续执行,直到结束。但是至少,我们使用了cancel方法,最终不会执行onPostExecute,而改去执行

onCancelled
我们肯定不会在这个方法里面去操作UI的啦。这样就避免了一些异常的发生。


于是相对于不能中断的任务,为避免任务一直持有activity,我们可以通过使用静态内部类,并且使用WeakReference来包裹我们的activity以达到更新UI的目的

如下代码:

static class MyTask extends AsyncTask<String,Integer,String>{        private WeakReference<Activity> weakAty;        public MyTask(Activity activity){            weakAty = new WeakReference<Activity>(activity);        }        @Override        protected String doInBackground(String... params) {            for(int i=0;i<10;i++){                Log.i("Mytask","i="+i);                try {                    Thread.sleep(2000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                if(isCancelled()){                    break;                }            }            return null;        }        @Override        protected void onPostExecute(String s) {            super.onPostExecute(s);            Log.i("Mytask","执行结束了");            AsyncTaskActivity mActivity;            if((mActivity= (AsyncTaskActivity) weakAty.get())!=null){                mActivity.doSomething();            }        }        @Override        protected void onCancelled() {            super.onCancelled();            Log.i("Mytask","执行了取消");        }    }


附上完整代码:

public class AsyncTaskActivity extends Activity {    private AsyncTask task;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        /* 用匿名内部类的方式创建*/         task = new AsyncTask() {            @Override            protected Object doInBackground(Object[] params) {                for(int i=0;i<10;i++){                    Log.i("task","i="+i);                    try {                        Thread.sleep(2000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    if(isCancelled()){                        break;                    }                }                return null;            }             @Override             protected void onPostExecute(Object o) {                 super.onPostExecute(o);                 Log.i("task","执行结束了");             }             @Override             protected void onCancelled() {                 super.onCancelled();                 Log.i("task","执行了取消");             }         };        task.execute();        //从log可以看到,上个task和下面的task是串行执行的        new MyTask(this).execute();    }    @Override    protected void onDestroy() {        super.onDestroy();        task.cancel(true);        //这里不做取消MyTask的任务是为了验证weakReference是否起作用    }    public void doSomething(){        //为保险,还是需要判断下当前activity是否已经销毁,因为weakReference修饰的对象并不是马上就能被回收        Log.i("AsyncActivity","异步任务完成,更新UI");    }    static class MyTask extends AsyncTask<String,Integer,String>{        private WeakReference<Activity> weakAty;        public MyTask(Activity activity){            weakAty = new WeakReference<Activity>(activity);        }        @Override        protected String doInBackground(String... params) {            for(int i=0;i<100;i++){                Log.i("Mytask","i="+i);                try {                    Thread.sleep(2000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                if(isCancelled()){                    break;                }            }            return null;        }        @Override        protected void onPostExecute(String s) {            super.onPostExecute(s);            Log.i("Mytask","执行结束了");            AsyncTaskActivity mActivity;            if((mActivity= (AsyncTaskActivity) weakAty.get())!=null){                mActivity.doSomething();            }        }        @Override        protected void onCancelled() {            super.onCancelled();            Log.i("Mytask","执行了取消");        }    }}



记录只为整理自己理解的,如果有不对,还请指正!

0 0