AsyncTask

作者: 9283856ddec1 | 来源:发表于2020-02-19 20:58 被阅读0次

    为什么要用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
    • execute (Params... params)
      用指定的参数来执行此任务,此方法必须在UI线程中调用,因为要将handler绑定到主线程的Looper。
    • executeOnExecutor(Executor exec,Params... params)
      用指定的参数来执行此任务,指定运行的线程池。
    • getStatus ()
      获得任务的当前状态PENDING(等待执行)、RUNNING(正在运行)、FINISHED(运行完成)。
    • cancel (boolean mayInterruptIfRunning)
      尝试取消这个任务的执行,如果这个任务已经结束或者已经取消或者不能被取消或者某些其他原因,那么将导致这个操作失败。
    • isCancelled ()
      在任务正常结束之前能成功取消任务则返回true,否则返回false。
    注意点

    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)

    相关文章

      网友评论

          本文标题:AsyncTask

          本文链接:https://www.haomeiwen.com/subject/baxafhtx.html