zoukankan      html  css  js  c++  java
  • 02、Android进阶AsyncTask原理解析

    AsyncTask原理

    Android提供了 AsyncTask,它使得异步任务实现起来更加简单。

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

    AsyncTask是一个抽象的泛型类,它有3个泛型参数,分别为Params、Progress和Result。

    Params为 参数类型

    Progress为后台任务执行进度的类型

    Result为返回结果的类型。

    如果不需要某个参数,可以将其设置为Void类型。

    AsyncTask中有4个核心方法,如下所示:

    (1)onPreExecute():在主线程中执行。一般在任务执行前做准备工作,比如对 UI 做一些标记。

    (2)doInBackground(Params...params):在线程池中执行。在 onPreExecute方法执行后运行,用来执

    行较为耗时的操作。在执行过程中可以调用publishProgress(Progress...values)来更新进度信息。

    (3)onProgressUpdate(Progress...values):在主线程中执行。当调用 publishProgress(Progress...values)时,此方法会将进度更新到UI组件上。

    (4)onPostExecute(Result result):在主线程中执行。当后台任务执行完成后,它会被执行。 doInBackground方法得到的结果就是返回的result的值。此方法一般做任务执行后的收尾工作,比如更新UI和数据。

    源码分析

    AsyncTask在3.0版本之前和3.0 及以后版本有着较大的改动,

    Android 3.0版本之前的AsyncTask

    下面是Android 2.3.7版本的AsyncTask的部分源码。

    public abstract class AsyncTask<Params, Progress, Result> {
        private static final String LOG_TAG = "AsyncTask";
        // 核心线程数
        private static final int CORE_POOL_SIZE = 5;
        // 线程池允许创建的最大线程数
        private static final int MAXIMUM_POOL_SIZE = 128;
        // 非核心线程空闲等待新任务的最长时间
        private static final int KEEP_ALIVE = 1;
    
        private static final BlockingQueue<Runnable> sWorkQueue =
                new LinkedBlockingQueue<Runnable>(10);
    
        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());
            }
        };
    
        private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
                MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
        ......
    }    
    

    ThreadPoolExecutor,它的核心线程数是5个,线程池允许创建的最大线程数为 128,非核心线程空闲等待新任务的最长时间为 1s。采用的阻塞队列是LinkedBlockingQueue,它的容量为10。

    3.0版之前的AsyncTask有一个缺点,就是线程池最大的线程数为128,加上阻塞队列的10个任务,所以 AsyncTask最多能同时容纳138个任务,当提交第139个任务时就会执行饱和策略,默认抛出 RejectedExecutionException异常。

    Android 7.0版本的AsyncTask

    Android 7.0版本的AsyncTask的代码如下所示:

    public abstract class AsyncTask<Params, Progress, Result> {
        private static final String LOG_TAG = "AsyncTask";
        // CPU的个数
        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;
    
        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());
            }
        };
    
        private static final BlockingQueue<Runnable> sPoolWorkQueue =
                new LinkedBlockingQueue<Runnable>(128);
    
        /**
         * An {@link Executor} that can be used to execute tasks in parallel.
         */
        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;
        }
    }    
    

    ThreadPoolExecutor,它的核心线程数最少有2个,最多是4个。线程池允许创建的最大线程数是根据CPU数量来决定的。阻塞队列仍旧是LinkedBlockingQueue,容量为128。

    1. 首先来看AsyncTask的构造方法,代码如下所示
    public AsyncTask() {
        // 实现了Callable接口,并实现call方法
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
    
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                // 在call中调用doInBackground(mParams)来处理任务并得到结果
                Result result = doInBackground(mParams);
                Binder.flushPendingCommands();
                // 将结果投递出去
                return postResult(result);
            }
        };
    	// FutureTask是一个可管理的异步任务,它实现了Runnable和Futrue这两个接口
        // 所以,FutureTask可以包装 Runnable和Callable,并提供给Executor执行
        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);
                }
            }
        };
    }
    

    WorkerRunnable作为参数传递给了FutureTask,这两个变量会暂时保存在内存中,稍后会用到它们。

    当要执行 AsyncTask 时,需要调用它的 execute方法,代码如下所示:

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

    execute方法又调用了executeOnExecutor方法,代码如下所示:

    @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();
        // 从前面我们知道WorkerRunnable作为参数传递给了FutureTask
        mWorker.mParams = params;
        // 将mFuture也就是前面讲到的FutureTask传进去
        exec.execute(mFuture);
        return this;
    }
    

    这里exec是传进来的参数sDefaultExecutor,它是一个串行的线程池 SerialExecutor,其代码如下所示:

    class SerialExecutor implements Executor {
        final Queue<Runnable> tasks = new ArrayDeque<>();
        final Executor executor;
        Runnable active;
        SerialExecutor(Executor executor) {
            this.executor = executor;
        }
        public synchronized void execute(final Runnable r) {
            // 将FutureTask加入到mTasks 中
            tasks.add(new Runnable() {
                public void run() {
                    try {
                        // 最终会调用WorkerRunnable的call方法。
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (active == null) {
                // 当任务执行完或者当前没有活动的任务时都会执行scheduleNext方法
                scheduleNext();
            }
        }
        
    	// 从mTasks取出 FutureTask任务并交由 THREAD_POOL_EXECUTOR 处理
        protected synchronized void scheduleNext() {
            if ((active = tasks.poll()) != null) {
                executor.execute(active);
            }
        }
    }}
    

    前面我们提到call方法最终会调用postResult方法将结果投递出去,postResult 方法的代码如下所示:

    private Result postResult(Result result) {
      // 创建消息,并通过Handler将消息发送出去  
      @SuppressWarnings("unchecked")
      Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
              new AsyncTaskResult<Result>(this, result));
      message.sendToTarget();
      return result;
    }
    

    从这里可以看出,AsyncTask中消息的发送是使用Handler,getHandler方法如下所示:

    private static Handler getHandler() {
      synchronized (AsyncTask.class) {
        if (sHandler == null) {
          sHandler = new InternalHandler();
        }
        return sHandler;
      }
    }
    

    在getHandler方法中创建了InternalHandler,InternalHandler的定义如下所示:

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

    在接收到MESSAGE_POST_RESULT消息后会调用AsyncTask的finish方法,代码如下所示:

    private void finish(Result result) {
      if (isCancelled()) {	// 如果AsyncTask任务被取消了,则执行onCancelled方法
        onCancelled(result);
      } else {	// 否则就调用onPostExecute方法
        onPostExecute(result);
      }
      mStatus = Status.FINISHED;
    }
    

    接着回头来看SerialExecutor,线程池 SerialExecutor主要用来处理排队,将任务串行处理。

    在SerialExecutor中调用 scheduleNext 方法时,将任务交给THREAD_POOL_EXECUTOR。它同样是一个线程池,用来处理任务,代码如下所示:

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

    THREAD_POOL_EXECUTOR 指的就是 threadPoolExecutor,其核心线程和线程池允许创建的最大线程数都是由CPU的核数来计算出来的。它采用的阻塞队列仍旧是LinkedBlockingQueue,容量为128。

    至此,AsyncTask原理分析完毕。

    Android 3.0及以上版本用 SerialExecutor作为默认的线程,它将任务串行地处理,保证一个时间段只有一个任务执行;而Android 3.0之前的版本是并行处理的。所以,在7.0之后不会出现任务超标而执行饱和策略的情况。

    如果想要在3.0以上版本使用并行的线程处理,可以使用如下代码:

    asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");
    

    executeOnExecutor方法的源码如下:

    @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;
      exec.execute(mFuture);
      return this;
    }
    

    其中第一个参数不但可以传入基础的线程池外,还可以传入自定义的线程池,代码如下:

    Executor executor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 0L,
          TimeUnit.MILLISECONDS, new LinkedBlockingDeque<Runnable>());
    asyncTask.executeOnExecutor(executor, "");
    
  • 相关阅读:
    Windows JScript 在 游览器 中运行 调试 Shell 文件系统
    autohotkey 符号链接 软连接 symbolink
    软链接 硬链接 测试
    SolidWorks 修改 基准面 标准坐标系
    手机 路径 WebDAV 映射 驱动器
    Win10上手机路径
    explorer 命令行
    单位公司 网络 封锁 屏蔽 深信 AC
    cobbler自动化部署原理篇
    Docker四种网络模式
  • 原文地址:https://www.cnblogs.com/pengjingya/p/14948021.html
Copyright © 2011-2022 走看看