深入理解AsyncTask

1 AsyncTask介绍

Android中有Handler和AsyncTask来实现异步类,Android中UI的更新只能在主线程中完成,为了不阻塞主线程,耗时的操作需要在异步类中完成。

AsyncTask是Android提供的轻量级的异步类,可以直接继承AsyncTaask,在类中实现异步操作,并提供结构反馈当前异步执行的程度,简单快捷,进程可控。

AsyncTask定义了三种泛型类型参数,Params, Progress和Result。
- Params 启动任务执行的输入参数,如Http请求的URL
- Progress 后台任务执行的百分比
- Result 后台执行任务最终返回的结果

使用AsyncTask来实现异步任务时,至少需要重写以下两个方法:
- doInBackground(Params…) 后台执行的耗时操作,如网络请求,注意不能在这个方法中更新UI。
- onPostExecute(Result) 这个方法是在UI线程中,主要用来在耗时操作完成后更新UI

还有其他的三个方法,但不是必须要实现的
- onProgressUpdate(Progress) 显示任务执行的进度
- onPreExecute() 任务执行之前调用此方法,可以在这里显示进度对话框
- onCancelled() 用户取消耗时操作时的操作

使用AsyncTask类实现异步操作时,需要注意一下几点:
- Task必须在主线程中创建
- execute()方法必须在主线程中调用
- 每个task只能执行一次,多次调用会产生异常

下面是一个AsyncTask使用的例子,注意需要在主线程中调用execute()方法

public class ProgressBarAsyncTask extends AsyncTask<Integer, Integer, String> {  

    private TextView textView;  
    private ProgressBar progressBar;  


    public ProgressBarAsyncTask(TextView textView, ProgressBar progressBar) {  
        super();  
        this.textView = textView;  
        this.progressBar = progressBar;  
    }  


    /**  
     * 这里的Integer参数对应AsyncTask中的第一个参数   
     * 这里的String返回值对应AsyncTask的第三个参数  
     * 该方法并不运行在UI线程当中,主要用于异步操作,所有在该方法中不能对UI当中的空间进行设置和修改  
     * 但是可以调用publishProgress方法触发onProgressUpdate对UI进行操作  
     */  
    @Override  
    protected String doInBackground(Integer... params) {  
        NetOperator netOperator = new NetOperator();  
        int i = 0;  
        for (i = 10; i <= 100; i+=10) {  
            netOperator.operator();  
            publishProgress(i);  
        }  
        return i + params[0].intValue() + "";  
    }  


    /**  
     * 这里的String参数对应AsyncTask中的第三个参数(也就是接收doInBackground的返回值)  
     * 在doInBackground方法执行结束之后在运行,并且运行在UI线程当中 可以对UI空间进行设置  
     */  
    @Override  
    protected void onPostExecute(String result) {  
        textView.setText("异步操作执行结束" + result);  
    }  


    //该方法运行在UI线程当中,并且运行在UI线程当中 可以对UI空间进行设置  
    @Override  
    protected void onPreExecute() {  
        textView.setText("开始执行异步线程");  
    }  


    /**  
     * 这里的Intege参数对应AsyncTask中的第二个参数  
     * 在doInBackground方法当中,,每次调用publishProgress方法都会触发onProgressUpdate执行  
     * onProgressUpdate是在UI线程中执行,所有可以对UI空间进行操作  
     */  
    @Override  
    protected void onProgressUpdate(Integer... values) {  
        int vlaue = values[0];  
        progressBar.setProgress(vlaue);  
    }  
}  

2 AsyncTask代码解析

我们进入AsyncTask类中查看这个异步类的工作工作流程,当我们在主线程中调用AsyncTask的execute()方法后。

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

执行的是executeOnExecutor()方法,其中一个参数是我我们调用时的params,而sDefaultExecutor我们就不知道是什么类型了。查课你sDefaultExecutor的定义,是一个SerialExecutor类的对象。SerialExecutor内部类定义如下:

 private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
           ...
        }

        protected synchronized void scheduleNext() {
           ...
        }
    }

SerialExecutor类实现了Executor的接口,主要是execute()方法。我们稍后再介绍。回到前面executeOnExecutor()函数,我们看一下这个函数的定义.

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        if (mStatus != Status.PENDING) {
            switch (mStatus) {
                case RUNNING:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task is already running.");
                case FINISHED:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task has already been executed "
                            + "(a task can be executed only once)");
            }
        }
        mStatus = Status.RUNNING;
        onPreExecute();
        mWorker.mParams = params;
        exec.execute(mFuture);
        return this;
    }

首先判断状态status, Status是一个枚举类型,包含三个值:
- PENDING : 待定状态
- RUNNING : 正在运行状态,如果执行一个操作,而这个操作的状态为正在执行,会抛出异常
- FINISHED : 已完成状态

如果状态为PENDING, 则会继续执行,首先会把状态改为RUNNING,然后回调onPreExecute()方法。接下来我们看一下mWorker的定义。

public AsyncTask() {  
        mWorker = new WorkerRunnable<Params, Result>() {  
            public Result call() throws Exception {  
                mTaskInvoked.set(true);  

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
                //noinspection unchecked  
                return postResult(doInBackground(mParams));  
            }  
        };  
//….  

}  

可以看到mWorker在构造方法中完成了初始化,在call方法中最终调用了我们熟悉的doInBackground()方法,并返回Result值作为参数给postResult方法。

接下来我们分析postResult方法

private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

在postResult方法中,首先调用了getHandler()方法,可以猜测这个方法得到了一个实现异步消息机制的Handlder对象,我们查看该函数

    private static Handler getHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler();
            }
            return sHandler;
        }
    }

果然,函数返回一个Handler对象,不过对象是自定义的InternalHandler的。我们继续查看InternalHandler类的定义

private static class InternalHandler extends Handler {
        public InternalHandler() {
            super(Looper.getMainLooper());
        }

        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
        @Override
        public void handleMessage(Message msg) {
            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
            switch (msg.what) {
                case MESSAGE_POST_RESULT:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }

当msg.what = MESSAGE_POST_RESULT时,调用了mTask的finish方法,当msg.what = MESSAGE_POST_PROGRESS时,调用了mTask.onProgressUpdate()方法。我们分析一下finish()方法

    private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

当请求没有被cancel时,调用了onPostExecute(result)函数,即通过handler,在主线程中改变UI的状态。最后将状态改为已完成。

3 AsyncTask存在的问题

(1) 生命周期

很多人认为一个在Activity中的AsyncTask会随着Activity的销毁而销毁,然而事实并非如此,AsyncTask会一直执行doInBackground方法直到方法结束。一旦上述方法结束,会根据情况进行不同的操作:
- 如果cancel(boolean)调用了,则执行onCancelled(Resule)方法
- 如果cancel(boolean)没有调用,则执行onPostExecute(Result)方法

(2)内存泄露

在Activiy中使用非静态匿名内部AsyncTask类,由于java内部类的特点,AsysncTask内部类会持有外部类的隐式引用。由于AsyncTask的生命周期可能比Activity的长,当Activity销毁时AsyncTask还在执行,而AsyncTask持有Activity的引用,导致Activity无非回收,进而产生内存泄露。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值