继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Android/java 多线程(六)-AsyncTask使用详解及源码分析

慕村9548890
关注TA
已关注
手记 1249
粉丝 227
获赞 989

简介

一个Android封装好的轻量级异步抽象类,使用的话需要继承并重写部分方法

作用

方便的实现多线程,并能方便的实现主线程与工作线程的通信,并且逻辑都在一个类中,不同于Handler的实现机制在不同的回调中,内部采用线程池管理策略,方便管理

使用介绍

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

可以看到有三个泛型参数,它们的作用分别是:

  • Params 传递给异步任务的参数类型,对应execute()方法和doInBackground()中的参数类型

  • Progress 进度跟新参数类型,对应onProgressUpdate()方法返回的参数类型

  • Result 异步任务执行完毕的返回结果类型,对应doInBackground()方法的返回结果类型和onPostExecute()方法的参数类型

如果不需要使用到,则可以使用Void类代替

简单示例:

申明一个实现类TestAsyncTask,主要打印方法的执行顺序以及参数及运行的线程名称

/**
 * Created by hj on 2018/12/29.
 * 说明:
 */public class TestAsyncTask extends AsyncTask<String,Integer,Integer> {    @Override
    protected void onPostExecute(Integer integer) {        super.onPostExecute(integer);
        Log.i("HJ","onPostExecute方法接收的参数值:"+integer+"--"+runThreadName());
    }    @Override
    protected void onPreExecute() {        super.onPreExecute();
        Log.i("HJ","onPreExecute"+"--"+runThreadName());
    }    @Override
    protected void onProgressUpdate(Integer... values) {        super.onProgressUpdate(values);
        Log.i("HJ","onProgressUpdate:"+ Arrays.toString(values)+"--"+runThreadName());
    }    @Override
    protected Integer doInBackground(String... strings) {
        Log.i("HJ","doInBackground()"+"--"+runThreadName());
        publishProgress(50);        return 1;
    }    private String runThreadName(){        return "运行在:"+Thread.currentThread().getName()+"线程";
    }
}

使用:

//必须是在主线程中
 TestAsyncTask task = new TestAsyncTask();
        task.execute();

打印结果:

I/HJ: onPreExecute--运行在:main线程
I/HJ: doInBackground()--运行在:AsyncTask #1线程I/HJ: onProgressUpdate:[50]--运行在:main线程
I/HJ: onPostExecute方法接收的参数值:1--运行在:main线程

可以看到,只有doInBackground()方法执行在异步线程中,其他的方法都是运行在主线程中,方法执行顺序为:
onPreExecute()---->doInBackground()---->调用publishProgress()方法---->onProgressUpdate()------>onPostExecute()

下面介绍一下方法的具体作用:

  • onPreExecute  在进行异步任务处理前的一些数据准备工作

  • doInBackground 处理异步任务逻辑,内部可以调用publishProgress更新进度

  • onProgressUpdate 进度更新回调

  • onPostExecute  异步处理完毕后的结果回调 ,处理ui逻辑

源码解析

AsyncTask内部的实现原理为:线程池+Handler

其内部有两个线程池:

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;public static final Executor THREAD_POOL_EXECUTOR;

SERIAL_EXECUTOR对应内部的SerialExecutor内部实现类,主要实现了异步任务的顺序分发:

private static class SerialExecutor implements Executor {        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;  //当前要处理的异步任务

        //给execute方法加锁保证了顺序执行
        public synchronized void execute(final Runnable r) {           //将一个runnable添加进双端队列中
            mTasks.offer(new Runnable() {                public void run() {                    try {
                        r.run();  //执行
                    } finally {
                        scheduleNext();
                    }
                }
            });            if (mActive == null) {
                scheduleNext();
            }
        }        //此方法的作用是将SerialExecutor 池中的任务的第一个任务赋值给mActive ,并压入到
       //THREAD_POOL_EXECUTOR线程池中
        protected synchronized void scheduleNext() {            //poll()方法的作用是删除队列中的第一个并返回结果,如果为null则返回null
            if ((mActive = mTasks.poll()) != null) {                //将第一个任务添加到THREAD_POOL_EXECUTOR线程池中
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

而THREAD_POOL_EXECUTOR的实现是在这里:

    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

可以看出它是一个常见的工作线程池,所以,这两个线程池,一个负责消息的任务调度,保证按照顺序执行,另外一个则是真正的异步任务处理池

接下来看一下它的构造方法:

public AsyncTask(@Nullable Looper callbackLooper) {        //初始化一个Handler处理主线程的通信
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);        //初始化一个可以存储Params参数的callable实现,其实也是 
       //THREAD_POOL_EXECUTOR.execute()的执行回调
        mWorker = new WorkerRunnable<Params, Result>() {            public Result call() throws Exception {               //里面的回调是不是很熟悉,和HandlerThread类似
                mTaskInvoked.set(true); //添加线程标识,用于postResultIfNotInvoked方法的检查
                Result result = null;  //这就是onPostExecute()方法的result
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                    //noinspection unchecked
                    result = doInBackground(mParams); //doInBackground方法在这里执行了
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true); //抛异常了取消任务
                    throw tr;
                } finally {
                    postResult(result); //此方法的作用是将结果发送到主线程
                }                return result;
            }
        };         //初始化一个Future回调,主要用于检查处理结果是否发送
        mFuture = new FutureTask<Result>(mWorker) {            //done()方法是在callable()方法之后的回调
            @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);
                }
            }
        };
    }//mWorker 的实现
    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;  //保存传入的参数
    }

接下来看看以上检查的方法的实现:

private void postResultIfNotInvoked(Result result) {        //执行了mWorker 里的call()回调的都会变为true,如果为false,说明任务没有被执行
        final boolean wasTaskInvoked = mTaskInvoked.get();        if (!wasTaskInvoked) {
            postResult(result);
        }
    }    //将此AsyncTask对象作为message参数发送,接收到之后就会调用finish()方法结束
    private Result postResult(Result result) {        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();        return result;
    }

其中的getHandler()中的Handler的实现类是InternalHandler,来看看它的实现:

    private static class InternalHandler extends Handler {        public InternalHandler(Looper looper) {            super(looper);
        }        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})        @Override
        public void handleMessage(Message msg) {
            
            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;            switch (msg.what) {                case MESSAGE_POST_RESULT:                    //result.mData[0]就是从postResult发送过来的AsyncTask对象
                    result.mTask.finish(result.mData[0]);  //处理结果分发,回调对应的方法
                    break;                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);  //这里处理进度更新
                    break;
            }
        }
    }  private void finish(Result result) {        // 先判断是否调用了Cancelled()
            // 1. 若调用了则执行我们复写的onCancelled()
            // 即 取消任务时的操作
            if (isCancelled()) {
                onCancelled(result);
            } else {            // 2. 若无调用Cancelled(),则执行我们复写的onPostExecute(result)
            // 即更新UI操作
                onPostExecute(result);
            }            // 注:不管AsyncTask是否被取消,都会将AsyncTask的状态变更为:FINISHED
            mStatus = Status.FINISHED;
        }

最后来看一下执行方法execute():

    @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {        return executeOnExecutor(sDefaultExecutor, params);
    }   @MainThread
    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; //mWorker中的参数是在这里保存的
        exec.execute(mFuture);  //将mFuture对象添加到THREAD_POOL_EXECUTOR 线程池中,mFuture在构造方法中做了初始化。

        return this;
    }

总结:
1.初始化两个线程池,一个负责任务调度(SerialExecutor),一个负责任务处理THREAD_POOL_EXECUTOR
2.构造方法中实例化了子线程中的callable接口方法,从WorkerRunnable中取出Params对象并赋值给dodoInBackground(mParams)方法执行耗时任务。
3.执行execute()方法将任务提交到THREAD_POOL_EXECUTOR线程池中,并将Params参数赋值到了WorkerRunnable中。
4.调用了postResult(result),通过InternalHandler 将消息回调到了主线程(执行了finish()方法,里面有onPostExecute方法),实现了UI的更新



作者:我是黄教主啊
链接:https://www.jianshu.com/p/26c359715750


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP