AsyncTask

2020-02-19  本文已影响0人  9283856ddec1

为什么要用AsyncTask

任务线程Thread执行完耗时操作后,进行UI更新,通常的做法是通过Handler投递一个消息给UI线程,然后更新UI。这种方式对于整个过程的控制比较精细,但是也有缺点:(1) 代码相对臃肿;(2) 在多个任务同时执行时,不易对线程进行精确控制。

为了简化操作,系统提供AsyncTask工具类,对用户隐藏Thread、Runnable、Handler等相关对象,使的创建异步任务更加简单,只须重写相关方法即可实现后台操作和UI更新。

AsyncTask使用

可实现的函数

AsyncTask的定义:

public abstract class AsyncTask<Params, Progress, Result>{}

说明:3种泛型类型分别表示参数类型、后台任务执行的进度类型、返回的结果类型。如果不需要某个参数,可以设置为Void类型。

一个异步任务的执行一般包括以下几个步骤:
(1)execute(Params... params)
执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。
(2)onPreExecute()
在execute被调用后立即执行,在UI线程中执行,一般用于后台任务执行前对UI做一些标记。
(3)doInBackground(Params... params)
在onPreExecute()完成后立即执行,用于执行较为耗时的操作。在执行过程中可以调用publishProgress来更新进度信息。
(4)onProgressUpdate(Progress... values)
执行在UI线程,在调用publishProgress时,此方法被执行,可以将进度信息更新到UI组件上。
(5)onPostExecute(Result result)
当后台任务执行结束后,调用此方法,将计算结果作为参数,在UI线程上进行相关结果的UI更新。

常用公共API
注意点

1)AsyncTask不与任何组件绑定生命周期
在Activity/或者Fragment中创建执行AsyncTask时,最好在Activity/Fragment的onDestory()调用 cancel(true);

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

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

4)串行或者并行的执行异步任务
目前AsyncTask支持并行和串行的执行异步任务,当想要串行执行时,直接执行execute()方法,如果需要并行执行,则要执行executeOnExecutor(Executor exec, Object... params)。

5)AsyncTask的实例必须在UI线程中创建,execute方法必须在UI线程中调用。一个任务实例只能执行一次,执行多次会抛出异常。不能在doInBackground中更新UI组件的信息;

AsyncTask实现

AsyncTask机制

AsyncTask实现原理如下所示:


AsyncTask内部原理.jpg
Params与任务包装

WorkerRunnable定义:

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
    Params[] mParams;
}

FutureTask定义:

public class FutureTask<V> implements RunnableFuture<V> {
    private Callable<V> callable;
 
    public FutureTask(Callable<V> callable) {
        //必须传入非空的实现CallBack接口的工作线程WorkRunnable
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;
    }
    ...
}

Params、WorkerRunnable、FutureTask建立关联:

public abstract class AsyncTask<Params, Progress, Result> { 
    private final WorkerRunnable<Params, Result> mWorker;
    private final FutureTask<Result> mFuture;
    
    mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                //设置为true,代表当前方法被调用过
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    //设置线程的优先级
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    
                    //将任务参数传递给doInBackground方法处理
                    result = doInBackground(mParams);  
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    // 处理执行结果
                    postResult(result);
                }
                return result;
            }
        };
    
        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    postResultIfNotInvoked(get());
                } catch (InterruptedException e) {
                    android.util.Log.w(LOG_TAG, e);
                } catch (ExecutionException e) {
                    throw new RuntimeException("An error occurred while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };

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

    public final AsyncTask<Params, Process, Result> executeOnExecutor(Executor exec, Params... params){
        if (mStatus != Status.PENDING) {
            switch (mStatus) {
                // 任务处于执行阶段或者完成阶段,再调用execute抛出异常
                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; //任务执行参数-传递给WorkRunnable
 
        //默认线程池或者指定的线程池,执行execute(),传入FuturTask对象
        exec.execute(mFuture);
 
        return this;
    }   
}

说明:
1)外部传递参数params设置到WorkerRunnable中进行保管,在执行后台任务时,将此参数传递给doInBackground方法。
2)FutureTask(Callable<V> callable)构造方法中,将WorkerRunnable传递进去,保存在成员变量callable中。

SerialExecutor任务顺序分发

SerialExecutor负责将异步任务分发给ThreadPoolExecutor线程池,线程池执行完任务后再派发下个任务。

public abstract class AsyncTask<Params, Progress, Result> {
    ...
    private static class SerialExecutor implements Executor {
        // 定义队列,存储Runnable类型的成员
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;
        
        public synchronized void execute(final Runnable r){
            // 将mFuture封装到Runnable中,并存入队列mTasks的队尾
            mTasks.offer(new Runnable(){
                public void run(){
                    try{
                        r.run();
                    }finally{
                        scheduleNext();
                    }
                }
            });

            if(mActive == null){
                scheduleNext();
            }
        }
        protected synchronized void scheduleNext(){
            // 从mTasks的队首取一个任务
            if(mActive = mTasks.poll() != null){
                // 将取出的任务放入线程池中执行
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }
}

说明:SerialExecutor将传入的mFuture封装到Runnable,使每次向线程池中传递一个任务,在执行完毕后再取下一个任务,达到顺序执行的目的。

线程任务的执行
public abstract class AsyncTask<Params, Progress, Result> { 
    private final WorkerRunnable<Params, Result> mWorker;
    private final FutureTask<Result> mFuture;

    /**
    *创建新的异步任务,这个构造器必须在UI线程上调用。
    */
    public AsyncTask() {
        this((Looper) null);
    }
 
    /**
     * 创建新的异步任务,这个构造器必须在UI线程上调用。
     * @hide---不可以直接调用
     */
    public AsyncTask(@Nullable Looper callbackLooper) {
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
             ? getMainHandler(): new Handler(callbackLooper);
    
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
            //设置为true,代表当前方法被调用过
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    //设置线程的优先级
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    
                    //将任务参数传递给doInBackground方法处理
                    result = doInBackground(mParams);  
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    // 处理执行结果
                    postResult(result);
                }
                return result;
            }
        };
    
        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    postResultIfNotInvoked(get());
                } catch (InterruptedException e) {
                    android.util.Log.w(LOG_TAG, e);
                } catch (ExecutionException e) {
                    throw new RuntimeException("An error occurred while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
        
        // 利用handler将结果发送到主线程
        private Result postResult(Result result) {
            @SuppressWarnings("unchecked")
            Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                                   new AsyncTaskResult<Result>(this, result));
            message.sendToTarget();
            return result;
        }
    }
}

1> 线程池执行FutureTask,调用其成员变量callable的call()方法,即WokerRunnable被执行。
2> WokerRunnable的call()方法中执行doInBackground(mParams),并把结果通过postResult(Result result) 传递给Hander,最终会调用重写的onPostExecute(result)方法。

参考资料

[1] Android应用性能优化,Herve Guihot
[2] AsyncTask使用及解析,(https://blog.csdn.net/qq_37321098/article/details/81625580)

上一篇下一篇

猜你喜欢

热点阅读