AsyncTask介绍

来源:互联网 发布:阿里云的作用 编辑:程序博客网 时间:2024/06/05 20:16

0x01.简介

AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by thejava.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.
谷歌官网的介绍,大意是用来辅助Thread和Handler的类,不能作为一个独立线程框架。AsyncTask用来做短时间的任务,如果你想做长时间的任务,最好用别的框架。
其实,AsyncTask就是用于更加简便的执行一个耗时任务,在主线程更新UI。

0X02.简单使用

google提供的AsyncTask的简单示例。
 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {     protected Long doInBackground(URL... urls) {         int count = urls.length;         long totalSize = 0;         for (int i = 0; i < count; i++) {             totalSize += Downloader.downloadFile(urls[i]);             publishProgress((int) ((i / (float) count) * 100));             // Escape early if cancel() is called             if (isCancelled()) break;         }         return totalSize;     }     protected void onProgressUpdate(Integer... progress) {         setProgressPercent(progress[0]);     }     protected void onPostExecute(Long result) {         showDialog("Downloaded " + result + " bytes");     } }
在几个我们可以复写的方法中,除了doInBackgroud方法别的都是执行在主线程中的。
当我们使用一个AsyncTask的时候我们必须指定3个泛型类型和实现doInBackground()函数。
public abstract class AsyncTask<Params, Progress, Result>
这是AnsyncTask需要定义的3个泛型数据。
第一个Params是我们需要指定重写的doInBackgroud的参数
protected abstract Result doInBackground(Params... params);
第二个progress是用于指定更新进度方法传入的参数
protected void onProgressUpdate(Progress... values) {}
第三个Result是用于我们指定doInBackgroun返回值和onPostExecute方法的参数
protected void onPostExecute(Result result) {}
必须要实现的abstract方法doInBackgroud,就是我们需要在后台做的任务。
整个执行流程



上面就是AsyncTask的一般流程(AsyncTask提供的cancel()方法,当我们调用这个方法的时候,流程就不是这个样子了),execut是需要我们自己调用以开始执行。在我们可以的复写的方法中,只有doInBackgroud是在额外线程中执行的。我们可以在doInBackgroud中调用publishProgress方法这样主线程会去调用OnProgressUpdate方法。在开启线程正常完成任务后会给主线程发送消息,调用OnPostExecute方法。
上面是官网提供的各种API,并且具有cancel, get等方法(是不是很熟悉,AsyncTask中就是包含一个FutureTask)。executeOnExecutor执行方法中允许我们自己定义Executor,也就是说我们可以用线程池去Execute去执行也可以用Thread。

0x03.源码分析

Execute()

我们先从execute开始看
    @MainThread    public final AsyncTask<Params, Progress, Result> execute(Params... params) {        return executeOnExecutor(sDefaultExecutor, params);//调用另外一个execute方法,并且传入默认的Executor    }    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;    }

从execute中执行会自动调用executeOnExecutor方法,并且传入一个默认的sDefaultExecutor, 等下会说这个sDefaultExecutor是干什么的(接下来涉及到Executor接口和ThreadPoolExecutor, 可以看下简单的用法再食用- -;),一开始会先对实例是否执行做一个检查,如果没问题的话就开始执行。改变状态,调用回调。mWorker是一个实现了Callable接口并且可以保存传入参数的实例,等回详细介绍,执行mFuture,mFuture其实就是封装了mWorker的一个FutureTask。

默认执行Runnable的Executor

 public static final Executor SERIAL_EXECUTOR = new SerialExecutor();//AsyncTask静态,静态,静态的变量 private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;//volatile保证多线程下数据的可见性,但是注意无法保证原子性(不理解也没有关系) private static class SerialExecutor implements Executor {     final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();//双向队列     Runnable mActive;     public synchronized void execute(final Runnable r) {//这个方法是线程安全的     mTasks.offer(new Runnable() {//将传入的Runnable             public void run() {                 try {                     r.run();//执行异步任务                 } finally {                     scheduleNext();//当一个异步任务执行完成之后必定会调用这个方法,不管是否正常结束                 }             }         });         if (mActive == null) {//在当前无异步执行的时候调用             scheduleNext();         }     }     protected synchronized void scheduleNext() {//线程安全              THREAD_POOL_EXECUTOR.execute(mActive);         }     } }

sDefaultExecutor是静态内部类 SerialExecutor的一个静态实例。这个变量是用来执行所有异步操作,我们看execute将传入的Runnable封装成另外一个Runnable,以便在执行run方法后执行scheduleNext()方法,并且入队,如果没有异步操作的话就会调用scheduleNext()方法。scheduleNext()是调用mTask中取出一个元素,放入THREAD_POOL_EXECUTOR来执行,THREAD_POOL_EXECUTOR其实是一个是一个ThreadPoolExecutor的实例,每次执行异步任务都是放入一个线程池中执行。从上面的代码可以看出,每次线程池中只有一个线程在运行,如果当前有线程在运行的话,那么只会将传入的Runnable入队,等待执行完毕后调用,并且所有的异步都是由duque来保存的所以所有任务执行顺序按 。
        也就是说在默认的Executor中执行异步操作,因为sDefaultExecutor是一个静态类,所有的异步操作都是一个一个进行的,而且先后有序,我猜想这就是为什么google建议你运行短时间的原因,如果一个异步花太多时间执行,那么必将导致别的异步任务也将很长时间执行完成,降低体验。
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();//获取虚拟机的处理器核心数    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));//线程池的核心线程数    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;//线程池最大线程数    private static final int KEEP_ALIVE_SECONDS = 30;//线程池超过核心线程    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;    }    private static final ThreadFactory sThreadFactory = new ThreadFactory() {//创建线程池每个线程的工厂        private final AtomicInteger mCount = new AtomicInteger(1);        public Thread newThread(Runnable r) {            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());//为每个线程起名        }    };
上面是对线程池各种参数设置,

mWorker和mFuture


    private final WorkerRunnable<Params, Result> mWorker;    private final FutureTask<Result> mFuture;    public AsyncTask() {        mWorker = new WorkerRunnable<Params, Result>() {            public Result call() throws Exception {                mTaskInvoked.set(true);//标记任务被调用                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                //noinspection unchecked                Result result = doInBackground(mParams);//调用回调                Binder.flushPendingCommands();//                return postResult(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);                }            }        };    }    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {        Params[] mParams;    }    @SuppressWarnings({"RawUseOfParameterizedType"})    private static class AsyncTaskResult<Data> {        final AsyncTask mTask;        final Data[] mData;        AsyncTaskResult(AsyncTask task, Data... data) {            mTask = task;            mData = data;        }    }
        可以看出mWorker是一个实现了Callable接口和可以保存mParams的一个实例。调用doInBackgroud和postResult,返回结果。mFuture将mWorker封装成一个FutureTask对象,那么mWorker就可以被一个实现了Executor接口的类所调用了。并且在mFuture中保证如果没有执行Task的话调用PostResultIFNotInvoked,这个方法如果发现task没有被执行,那么回去调用 postResult(result),用于完成onPostExecute的回调。
        到现在我们可以整理下,我们调用execute(params),在调用execute线程执行onPreExecute()用默认的Executor异步执行封装了mWorker的Future,在mWorker中执行了doInBackgroud并且将结果传给postResult(result)。大致的流程理清楚了。那么postResult(result)中有什么?

postResult(result)


    private Result postResult(Result result) {        @SuppressWarnings("unchecked")        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,                new AsyncTaskResult<Result>(this, result));        message.sendToTarget();        return result;    }    private static Handler getHandler() {//根据单例模式获取        synchronized (AsyncTask.class) {//对类上锁,以防多次创建            if (sHandler == null) {                sHandler = new InternalHandler();            }            return sHandler;        }    }    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;            }        }    }    protected final void publishProgress(Progress... values) {        if (!isCancelled()) {//发送低啊用用onprogressUpdate的回调            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();        }    }    private void finish(Result result) {        if (isCancelled()) {//看是否取消了            onCancelled(result);        } else {            onPostExecute(result);        }        mStatus = Status.FINISHED;//标记状态结束    }
        在postResult中会直接生成一个绑定主线程的Message并且投递给主线程,让主线程调用finish,根据是否被取消了,调用具体的回调。publishProgress也是一样通过向主线程投递消息,让主线程调用onProgressUpdate。



0 0