美文网首页
AsyncTask源码分析

AsyncTask源码分析

作者: _Once1 | 来源:发表于2018-07-20 21:25 被阅读0次

使用示例

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]);
            // 此方法可在doInBackground中调用,发布进度更新
            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");
    }
}

// 调用方法: 
new DownloadFilesTask().execute(url1, url2, url3);

简述

AsyncTask中封装了两个线程池和一个handler,其中SerialExecutor用于任务的排队,而THREAD_POOL_EXECUTOR用于真正的执行任务
下面看一下该类中定义的属性

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;

// 真正用于执行任务的线程池
public static final Executor THREAD_POOL_EXECUTOR
    = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,  TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

可见,该线程池核心线程数目为CPU数目+1,最大线程数量为2*CPU + 1
然后看一下另一个用于任务排队的线程池:

// 该线程池只是用于任务的排队,真正执行任务的还是THREAD_POOL_EXECUTOR
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() {
            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);
        }
    }
}

该线程池只是一个串行的线程池,一个进程中所有的AsyncTask全都在这个串行的池中排队执行
首先,会将一个任务插入任务队列中,如果此时没有正在执行的任务,则调用scheduleNext执行一个任务,当任务执行结束,继续回调该方法,直道所有任务都执行结束
由此可见,其是串行执行的


下面从execute()方法开始看起:
new DownloadFilesTask().execute(url1, url2, url3);

注意:该方法必须在主线程中调用,默认实现是在线程池中串行执行的,如果需要并行执行的效果,可以调用executeOnExecutor方法,传入THREAD_POOL_EXECUTOR

execute又调用了executeOnExecutor(sDefaultExecutor, params);方法
该方法内部的实现逻辑为:

  1. 首先,检查当前的执行状态,若正在执行或者已执行,则会报错
  2. 调用onPreExecute()
  3. 调用传入的线程池去执行任务
    下面再看sDefaultExecutor内部的实现
  • 会将一个任务插入任务队列中,如果此时没有正在执行的任务,则调用scheduleNext执行一个任务,当任务执行结束,继续回调该方法,直道所有任务都执行结束
  • 当执行futureTask的run方法时,会执行mWorker的call方法,因此,该方法最终会在线程池中执行
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                return postResult(doInBackground(mParams));
            }
        };

看一下call方法的逻辑:
调用doInBackground,之后,再将结果调用postResult方法发送出去

private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

说到handler,也解释了AsyncTask 必须在主线程中加载的原因:
其内部的Handler是静态的,为了让其能成功切换执行环境,该Handler必须在主线程中创建,因此,该类必须在主线程中加载

消息发出之后,会回调finish方法

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

会根据是否取消,回调两种方法


总结
内部封装2线程池+handler,一个负责将任务串行排序,另一个负责真正执行任务;执行完毕后,通过Handler将结果,进度等回调出去。
自从3.0之后,默认是采用一个线程来串行执行任务,但仍可以通过调用executeOnExecutor方法,传入线程池来实现并行执行的效果


参考:《Android开发艺术探索》

相关文章

  • Android源码解析-Asynctask

    android源码分析-AsyncTask 我们一般创建一个AsyncTask的任务代码如下: 下面开始分析源码:...

  • AsyncTask异步任务类

    目录介绍 01.先看下AsyncTask用法 02.AsyncTask源码深入分析2.1 构造方法源码分析2.2 ...

  • AsyncTask源码分析

    前言 IntentService使用及源码分析 HandlerThread源码分析 AsyncTask使用及封装实...

  • AsyncTask 使用及封装实践

    前言 IntentService使用及源码分析 HandlerThread源码分析 AsyncTask使用及封装实...

  • Android - AsyncTask (SDK 24)

    利用AsyncTask给ListView异步加载图片 实现图文混排 链接 AsyncTask源码分析 知乎

  • 4.AsyncTask使用,原理

    资料 AsyncTask处理机制详解及源码分析-工匠若水 AsyncTask 源码解析-鸿洋 带你认识不一样的As...

  • AsyncTask带你更深入点看源码

    关键词 AsyncTask源码分析 FutureTask源码分析 快过年了,公司同事已经开始进行迁移之旅,目前来...

  • AsyncTask工作原理

    AsyncTask工作原理调用图 AsyncTask工作原理源码分析,建议配合调用图一起看 调用 AsyncTas...

  • AsyncTask源码分析

    一 AsyncTask使用的场景 在MainThread线程中执行耗时不长的最多几秒钟的后台工作。 二 Async...

  • AsyncTask源码分析

    Android中UI的更新主要在主线程中,而耗时操作一般在子线程中进行;我们可以通过handler发送消息的方式处...

网友评论

      本文标题:AsyncTask源码分析

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