Android多线程-AsyncTask工作流程(源码)

栏目: IOS · Android · 发布时间: 7年前

内容简介:Android多线程-AsyncTask工作流程(源码)

AsyncTask的源码是很简单的,看着并不复杂。只是对Handler和ThreadPoolExecutor进行了一下封装。

基于api25(7.1)的代码,

使用起来也是很简单的,看 上个就知道了 。一般要继承AsyncTask并重写下面几个方法,这些方法的执行顺序一目了然:

原文地址

//任务执行前调用
protected void onPreExecute() {}
//执行后台任务
protected abstract Result doInBackground(Params... params);
//返回任务执行结果
protected void onPostExecute(Result result) {}
//返回任务执行进度
protected void onProgressUpdate(Progress... values) {}
//任务取消时调用
protected void onCancelled() {}

只有 doInBackground 一个方法是抽象的,必须重写,其他的可以不用重写。

然后通常的调用方法是这样的:

new MyAsyncTask().execute();

Handler和线程池

既然是对Handler和线程池的封装,就先看看封装的什么用的Handler和线程池。都是定义在AsyncTask类中。

handler

private static InternalHandler sHandler;
private static class InternalHandlerextends 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;
            }
        }
    }
private staticHandlergetHandler(){
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler();
            }
            return sHandler;
        }
    }

首先有一个变量sHandler。

InternalHandler是一个静态内部类

在这个构造方法中可以看出,InternalHandler使用了主线程也就是UI线程的Looper来处理消息,所以这个Handler收到的消息会在主线程中处理。使用这个Handler就达到了跟主线程进行交互的目的。

然后提供了一个方法getHandler,用单例来获取唯一的一个InternalHandler。

线程池

public static final Executor 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 static final Executor SERIAL_EXECUTOR = new SerialExecutor();
//默认的线程池
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

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

        public synchronized void execute(finalRunnable r){
            mTasks.offer(new Runnable() {
                public void run(){
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext(){
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }
/** @hide*/
    public static void setDefaultExecutor(Executor exec){
        sDefaultExecutor = exec;
    }

在这里可以看见连个线程池, THREAD_POOL_EXECUTORSERIAL_EXECUTOR ,以及一个默认使用的线程池变量 sDefaultExecutor

这两个线程池关系到了 为什么AsyncTask的任务是串行的 。在ActivityThread中有这样一段代码:

//android.os.Build.VERSION_CODES.HONEYCOMB_MR1=12
if (data.appInfo.targetSdkVersion <= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) {
    AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}

看来只有当版本小于13的时候,才会将 THREAD_POOL_EXECUTOR 作为默认线程池,可以并行执行任务。

THREAD_POOL_EXECUTOR

其中 THREAD_POOL_EXECUTOR 是在静态代码块中定义的,在类加载的时候就执行了,而且只会执行一次。

直接使用 ThreadPoolExecutor 的构造方法来构造了一个线程池,来看一下参数:

  • private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    

    核心线程数,其中 CPU_COUNT = Runtime.getRuntime().availableProcessors() 表示CPU数量。最低两个,最多四个。

  • private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    

    最大线程数,是CPU核心数的2倍+1.

  • private static final int KEEP_ALIVE_SECONDS = 30;
    

    空闲线程存活时间,30 。根据第四个参数 TimeUnit.SECONDS 知道是30秒。

  • private static final BlockingQueue<Runnable> sPoolWorkQueue =new LinkedBlockingQueue<Runnable>(128);
    

    使用了 LinkedBlockingQueue ,超过核心线程数量的任务会在队列中排队。

  • private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);
    
        publicThreadnewThread(Runnable r){
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };
    

    这个只是给每个线程池中创建的额线程起了个名字,叫 AsyncTask # 数字 ,数字自增长。

然后设置语序核心线程空闲超时 threadPoolExecutor.allowCoreThreadTimeOut(true)

这是一个中规中矩的线程池,然而默认使用的线程池并不是这个。而是下面的 SERIAL_EXECUTOR

SERIAL_EXECUTOR

SERIAL_EXECUTOR 中维护了一个双端数组队列 mTasks ,里面存放的Runnable。

当调用他的 execute 方法执行 Runnable 时,他会把这个 Runnablerun 方法和 scheduleNext() 方法重新加工包装成一个新的 Runnable 放在队列中。

然后下面会判断 mActive 是不是空的,第一次肯定是空的,所以会执行 scheduleNext() 方法。

在这个方法中,会调用队列的 poll 方法取出一个 Runnable ,然后调用上面的线程池 THREAD_POOL_EXECUTOR 来执行任务。

因为每个任务经过加工都加上了 scheduleNext() 方法,所以队列中的任务都会按顺序执行完。

  • 由此可见,这个队列仅仅起到一个 排序 功能,是各个任务依次执行,真正的执行还是交给了线程池 SERIAL_EXECUTOR .

AsyncTask的其他内部类

状态Status

AsyncTask有一个枚举类定义了三个状态:

public enum Status {
    /**
     * Indicates that the task has not been executed yet.
     * 表明任务尚未执行
     */
    PENDING,
    /**
     * Indicates that the task is running.
     * 表明任务正在执行
     */
    RUNNING,
    /**
     * Indicates that {@link AsyncTask#onPostExecute} has finished.
     * 表明onPostExecute已经结束
     */
    FINISHED,
}

当然就有一个表示状态的变量, mStatus 默认是 Status.PENDING :

private volatile Status mStatus = Status.PENDING;

WorkerRunnable

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

这个类就是个CallAble接口,里面增加了一个参数数组。

AsyncTaskResult

这个类其实就是个存储类,保存了一个 AsyncTaskData[] .

private static class AsyncTaskResult<Data>{
    final AsyncTask mTask;
    final Data[] mData;

    AsyncTaskResult(AsyncTask task, Data... data) {
        mTask = task;
        mData = data;
    }
}

运行过程

上面的都准备好了,下面就能运行了。

看着调用方法:

new MyAsyncTask().execute();

先实现一个AsyncTask,这时要定义 三个参数类型

AsyncTask<Params, Progress, Result>

先new一个,然后调用 execute方法

new的时候肯定会调用构造方法

构造方法

AsyncTask的构造方法中初始化了两个变量:

private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
public AsyncTask(){
    mWorker = new WorkerRunnable<Params, Result>() {
        publicResultcall()throwsException{
            mTaskInvoked.set(true);
            Result result = null;
            try {
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                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);
            }
        }
    };
}

mWorker 前面看到了,是一个 WorkerRunnable ,所以要重写 call 方法。

这个任务其实才是后台任务,所以这个任务就是真正的AsyncTask的任务了。

然后就调用了 doInBackground(mParams) ,把参数穿了进去。

mFuture 是个 FutureTask ,他把上面的 mWorker 又进行了一次包装,会先执行 mWorkercall 方法中的内容,再执行 done()

execute

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

这个方法是真正开始执行任务的方法,一般都会传入个参数Params。

里面直接调用了 executeOnExecutor(sDefaultExecutor, params) 方法,使用的线程池是默认的 ,也就是上面的 SERIAL_EXECUTOR 。串行执行任务。

onPreExecute

public finalAsyncTask<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;
}

这里先判断任务的状态 mStatus ,如果是正在运行或者说运行结束了,都会抛异常。所以一个任务只能执行一次 executef 方法,一个任务只能执行一次,不能重复执行。

mStatusPENDING 的时候,先 mStatus = Status.RUNNING 表示任务正在执行了。

然后就调用到了 onPreExecute() 方法。

mWorker.mParams = params 前面看见 WorkerRunnable 中有一个变量 Params[] mParams ,保存了传入的参数。

一直到这时候都还是在原来的线程中运行,并没有开启多线程。所以这个方法也是在原来的线程中运行的。

然后调用传入的线程池的 execute 方法,来执行构造方法中新建的 mFuture 。这个时候就使用线程池开新线程了。

doInBackground

mFuture 里有个 mWorker ,会执行他的call方法,这个方法中的内容都会在子线程中运行,其中包括了 doInBackground ,他的参数 mParamsWorkerRunnable 里的变量。:

mWorker = new WorkerRunnable<Params, Result>() {
    publicResultcall()throwsException{
        mTaskInvoked.set(true);
        Result result = null;
        try {
            ...
            result = doInBackground(mParams);
            ...
        } catch (Throwable tr) {
            mCancelled.set(true);
            throw tr;
        } finally {
            postResult(result);
        }
        return result;
    }
};

首先把 mTaskInvoked 设置为 true 表示这个任务已经开始了。

然后调用重写过的 doInBackground 方法,运行咱们需要后台运行的任务。

doInBackground 有一个返回值,也是个泛型。

出现异常时,将 mCancelled 设置为 true ,表示任务取消了。

最终都会调用 postResult(result) 方法。

这个方法也很简单:

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

getHandler() 前面知道是通过单例获取到一个使用主线程 Looper 创建的 Handler ,就是 InnerHandler ,所以他对消息的处理会回到主线程中。

然后通过这个Handler发送消息,消息内容是 new AsyncTaskResult<Result>(this, result) 。前面也看了这是个载体,将这个 AsyncTask 本身和后台任务 doInBackground 的返回结果传了进去。

然后整个工作就完成了。

onProgressUpdate

这个方法用来更新进度,不能直接调用,要通过 publishProgress 方法来调用。

doInBackground ,通常会手动调用 publishProgress 方法来更新进度

protected final void publishProgress(Progress... values) {
    if (!isCancelled()) {
        getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                new AsyncTaskResult<Progress>(this, values)).sendToTarget();
    }
}

这个方法贤惠判断任务是否取消,如果取消了就什么都不做。

没取消就也用 InnerHandler 发送消息,内容是 new AsyncTaskResult<Progress>(this, values) 。传入当前的 AsyncTask 和进度信息 values .

这些方法最终都是以通过Handler发送个消息结束,所以后面的就是Handler的事了

之前已经看过了这个类:

private static class InternalHandlerextends 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;
        }
    }
}

handleMessage 中能看到, result 是个 AsyncTaskResult 类型,在前面也知道这个里面保存了 AsyncTask 和要传递的数据。前面两个消息携带的信息也是这个类型。

msg.what==MESSAGE_POST_PROGRESS 的时候,表示要更新进度,就先从 result 中拿到里面的 AsyncTask->result.mTask ,然后调用他的 onProgressUpdate 方法,参数是 result 中的 mData->result.mData

如果重写过这个方法,就可以根据这个值更新进度。

onPostExecute

msg.what==MESSAGE_POST_RESULT 的时候,表示有结果了,这是后台任务已经执行结束了。

调用里面的 AsyncTaskfinish 方法,参数是消息里的 mData

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

里面也是先判断是否取消,取消了就调用取消的回调 onCancelled ,没取消就调用正常的回调 onPostExecute ,并最后把任务状态改为 Status.FINISHED

整个任务结束。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Pro Django

Pro Django

Marty Alchin / Apress / 2008-11-24 / USD 49.99

Django is the leading Python web application development framework. Learn how to leverage the Django web framework to its full potential in this advanced tutorial and reference. Endorsed by Django, Pr......一起来看看 《Pro Django》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具