1. 官方介绍

public abstract class AsyncTask 
extends Object 

java.lang.Object
   ↳ android.os.AsyncTask<Params, Progress, Result>

AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.

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 the java.util.concurrent package such as ExecutorThreadPoolExecutor and FutureTask.

An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task is defined by 3 generic types, called ParamsProgress and Result, and 4 steps, called onPreExecutedoInBackgroundonProgressUpdate andonPostExecute.

翻译

  • AsyncTask使适当的和容易使用的UI线程。这类允许执行后台操作和发布的结果在UI线程上无需操纵线程和/或处理程序。AsyncTask被设计成一个助手类线程和处理程序和不构成通用线程框架。理想情况下应使用asynctask简称操作(最多几秒钟)。如果你需要保持线程运行很长一段时间,强烈建议你使用各种java.util提供的api。并发包如遗嘱执行人,ThreadPoolExecutor FutureTask。异步任务被定义为一个计算,运行在一个后台线程,其结果发表在UI线程上。异步任务被定义为3泛型类型,称为Params,进展和结果,和4个步骤,称为onPreExecute,doInBackground,onProgressUpdate,onPostExecute。
  • 简单来说AsyncTasck是用来处理耗时的操作(如:网络请求/下载图片等等...),说白了就是相当于对Thread+Handler的一种封装,封装了ThreadPool, 比直接使用Thread效率要高,使用它更编码更简洁,更高效.

2.使用方法

  • 举一个列子给大家看看

    •  

      package com.edwin.demoasynctask;
      
      import android.app.ProgressDialog;
      import android.os.AsyncTask;
      import android.os.Bundle;
      import android.support.v7.app.AppCompatActivity;
      import android.util.Log;
      import android.widget.Toast; public class MainActivity extends AppCompatActivity {
      private String TAG = "Edwin";
      private ProgressDialog mProgressDialog; @Override
      protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main); new MyAsyncTask().execute("网址地址", "请求参数");
      } /**
      * AsyncTask<Params, Progress, Result>三个参数分别介绍一下
      * Params 启动任务执行的输入参数,比如HTTP请求的URL。
      * Progress 后台任务执行的百分比,比如下载的进度值。
      * Result 后台执行任务最终返回的结果,比如String。
      * <p/>
      * GO
      * 这里我做一个模拟下载文件的操作
      */
      private class MyAsyncTask extends AsyncTask<String, Integer, String> {
      /**
      * 1.在分线程工作开始之前在UI线程中执行,初始化进度条视图
      */
      @Override
      protected void onPreExecute() {
      //TODO 准备初始化View
      mProgressDialog = new ProgressDialog(MainActivity.this);
      mProgressDialog.setMax(100);
      mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
      mProgressDialog.setCancelable(false);
      mProgressDialog.show();
      Log.e(TAG, "onPreExecute");
      } /**
      * 2.在分线程中执行,完成任务的主要工作,通常需要较长的时间
      *
      * @param params url请求参数等等..
      * @return 请求之后得到的结果
      */
      @Override
      protected String doInBackground(String... params) {
      //TODO 做一些耗时的操作
      String url = params[0];//获取url参数进行网络请求操作 Log.e(TAG, "doInBackground");
      int i = 0;
      // 下面我们模拟数据的加载,耗时的任务
      for (i = 0; i < 100; i++) {
      try {
      Thread.sleep(100);
      } catch (InterruptedException e) {
      e.printStackTrace();
      }
      //在分线程中, 发布当前进度
      publishProgress(i);
      }
      //返回结果
      return "结果:" + i;
      } /**
      * 3.在主线程中更新进度
      *
      * @param values 进度值
      */
      @Override
      protected void onProgressUpdate(Integer... values) {
      //TODO 获取进度值,更新View
      mProgressDialog.setProgress(values[0]);
      Log.e(TAG, "onProgressUpdate values[0] = " + values[0]); } /**
      * 4.执行完之后的结果
      *
      * @param result 结果
      */
      @Override
      protected void onPostExecute(String result) {
      //TODO 获取结果,关闭View
      mProgressDialog.dismiss();
      Log.e(TAG, "onPostExecute result = " + result);
      Toast.makeText(MainActivity.this, "文件下载成功", Toast.LENGTH_SHORT).show();
      }
      }
      }
  • 效果图

3. 源码解析

  • AsyncTask初始化操作分析
    •  /**
      * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
      */
      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);
      }
      }
      };
      }
      • 第5行是初始化的一些参数,用于存放我们传入的参数execute(Params... params),源码点进去看WorkerRunnable是一个抽象类实现了Callable

        •   

           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;
          }
          }
      • 第17行是初始化FutureTask而穿进去的参数又是mWorker重写done方法,在完成的时候调用onCancelled()或者onPostExecute()。看源码追踪
        •   通过源码postResultfNotInvoked(get()),postResultfNotInvoked(null);点进入如下
          private void postResultIfNotInvoked(Result result) {
          final boolean wasTaskInvoked = mTaskInvoked.get(); //如果不为true就执行,因在初始化的时候已经设为了true,所以不会执行
          if (!wasTaskInvoked) {
          postResult(result);
          }
          }
  • AsyncTask .execute操作分析

    •   

       public final AsyncTask<Params, Progress, Result> execute(Params... params) {
      return executeOnExecutor(sDefaultExecutor, params);
      } 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;
      }
      • 先看第7行一个switch语句先判断当前的状态,Status是一个枚举类型共三种情况(等待PENDING/运行RUNNING/完成FINISHED),
      • 哈哈,看执行到21行代码,很熟悉了吧onPreExecute()初始化的操作,在UI线程做一些准备工作啦!
      • 接走执行到23行,刚才我们一进来就讲啦mWorker初始化操作了,他是一个抽象类,这时候我们把我们传入进来的参数赋值给它。
      • 最好第24行执行一个异步操作。mFuture参数在初始化的地方讲到了,下面我们之间深入看源码。
    • 好,我们在此回过去看FutureTask初始化后done方法里的方法postResultIfNotInvoked(get())和postResultIfNotInvoked(null)
      •   

         private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
        postResult(result); //慢慢深入
        }
        } 8
        private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
        new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
        }
        • 第11行代码,哇靠!通过Handler发送消息给UI线程,那就去看看Handler的初始化操作

          •   

             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]);//源码跟踪进入调用的是onPostExecute()
            break;
            case MESSAGE_POST_PROGRESS:
            result.mTask.onProgressUpdate(result.mData); //调用onProgressUpdate熟悉吧。
            break;
            }
            }
            }
    • 我们在回过头来看看,调用execute方法,最终调用的是executeOnExecutor方法,他里面有一个设置好的参数sDefaultExecutor,好对他下手拨开皮看看
      •   逆向分析—颜色一一对应

          public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
        } private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); 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);
        }
        }
        } public static final Executor THREAD_POOL_EXECUTOR
        = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
        TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();//可用的CPU个数
        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;//维持时间

4. AsyncTask曾经缺陷

  • API11以前的源码
    •   

       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 ThreadPoolExecutor sExecutor =
      new ThreadPoolExecutor(CORE_POOL_SIZE,MAXIMUM_POOL_SIZE, KEEP_ALIVE,
      TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
  • API11以后的源码 
    •   

           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;
      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
      = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
      TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); /**
      * An {@link Executor} that executes tasks one at a time in serial
      * order. This serialization is global to a particular process.
      * 一个串行执行,一次完成一项任务秩序。这个序列化是全球性的一个特定的过程。单线程模式
      */
      public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
  • 结论
    • 在3.0以前,最大支持128个线程的并发,10个任务的等待。
    • 在3.0以后,无论有多少任务,都会在其内部单线程执行;

Android AsyncTask 源码解析的更多相关文章

  1. Android -- AsyncTask源码解析

    1,前段时间换工作的时候,关于AsyncTask源码这个点基本上大一点的公司都会问,所以今天就和大家一起来总结总结.本来早就想写这篇文章的,当时写<Android -- 从源码解析Handle+ ...

  2. 还怕问源码?Github上神级Android三方源码解析手册,已有7.6 KStar

    或许对于许多Android开发者来说,所谓的Android工程师的工作"不过就是用XML实现设计师的美术图,用JSON解析服务器的数据,再把数据显示到界面上"就好了,源码什么的,看 ...

  3. Android EventBus源码解析 带你深入理解EventBus

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40920453,本文出自:[张鸿洋的博客] 上一篇带大家初步了解了EventBus ...

  4. Android -- 从源码解析Handle+Looper+MessageQueue机制

    1,今天和大家一起从底层看看Handle的工作机制是什么样的,那么在引入之前我们先来了解Handle是用来干什么的 handler通俗一点讲就是用来在各个线程之间发送数据的处理对象.在任何线程中,只要 ...

  5. Android LayoutInflater源码解析:你真的能正确使用吗?

    版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 好久没写博客了,最近忙着换工作,没时间写,工作刚定下来.稍后有时间会写一下换工作经历.接下来进入本篇主题,本来没想写LayoutInflater的 ...

  6. Android HandlerThread源码解析

    在上一章Handler源码解析文章中,我们知道App的主线程通过Handler机制完成了一个线程的消息循环.那么我们自己也可以新建一个线程,在线程里面创建一个Looper,完成消息循环,可以做一些定时 ...

  7. Android——LruCache源码解析

    以下针对 Android API 26 版本的源码进行分析. 在了解LruCache之前,最好对LinkedHashMap有初步的了解,LruCache的实现主要借助LinkedHashMap.Lin ...

  8. Android DiskLruCache 源码解析 硬盘缓存的绝佳方案

    一.概述 依旧是整理东西,所以近期的博客涉及的东西可能会比较老一点,会分析一些经典的框架,我觉得可能也是每个优秀的开发者必须掌握的东西:那么对于Disk Cache,DiskLruCache可以算佼佼 ...

  9. Android EventBus源码解析

    项目地址 :https://github.com/greenrobot/EventBus 这个项目个人感觉就是为了解决回调事件过多的,比方说A函数在做完以后 要调用b类的c函数,那我们通常的做法就是 ...

随机推荐

  1. 绘制SVG内容到Canvas的HTML5应用

    SVG与Canvas是HTML5上绘制图形应用的两种完全不同模式的技术,两种绘制图形方式各有优缺点,但两者并非水火不容,尤其是SVG内容可直接绘制在Canvas上的功能,使得两者可以完美的融合在一起, ...

  2. 我们一起来动手开发一个Orm框架,开源发布

    我们追求的方向 1)高性能. 这也是架构创建的目的之一,已经将它的性能提升到了极致.大家可以自己测试.我可以说其性能是数一数二的.连接地址:Moon洗冤录 2)易用性强 我想,用过Moon.ORM的应 ...

  3. Auto Mapper04(MVC中的配置)

    学习如何在MVC项目中配置AutoMapper. 一:首先在MVC项目中引用AutoMapper的DLL文件,接着创建一个接口,这里面我们需要定义两个方法,接口里面的方法只能定义不能实现,也没有什么修 ...

  4. C# 目录(文件夹)复制实现

    private static void CopyDir(DirectoryInfo origin, string target) { if (!target.EndsWith("\\&quo ...

  5. Emit学习(2) - IL - 对象的创建过程

    上一篇的介绍中, 并没有介绍到对象的创建过程, 这一篇主要就介绍一下, 对象的创建过程. 其实熟悉了IL语法之后, 完全可以用Reflector反编译代码去查看. 而且正因为有这个工具, 可以对照着R ...

  6. Spring @Transactional propagation 各个属性值的含义

    REQUIRED:业务方法需要在一个容器里运行.如果方法运行时,已经处在一个事务中,那么加入到这个事务,否则自己新建一个新的事务. NOT_SUPPORTED:声明方法不需要事务.如果方法没有关联到一 ...

  7. 基于<MediaElement>的WPF视频播放器(可拖拽进度条播放)【1】

    一.前言       前两天上峰要求做一个软件使用向导,使用WPF制作.这不,这两天从一张白纸开始学起,做一个播放演示视频的使用向导.以下是粗设计的原型代码: 二.效果图 三.代码 前台代码: < ...

  8. 会员管理系统的设计和开发(2)-- RDLC报表的设计及动态加载

    在上篇<会员管理系统的设计和开发(1)>介绍了关于会员系统的一些总体设计思路和要点,经过一段时间开发,软件终于完成并发布.在这期间,碰到了不少技术难点,并积累了不少开发心得和经验,本篇继续 ...

  9. asp.net中Ajax控件的用途(二)

    1.个人觉得对于新手最为实用的PopupControlExtender,弹出层载体,在实例中可以弹出登录框,百度的登陆页面基本都用的这种形式,可以把浮动的panel宽高都设置为100%,以屏蔽底层操作 ...

  10. 介绍开源的.net通信框架NetworkComms框架 源码分析(四)Packet

    原文网址: http://www.cnblogs.com/csdev Networkcomms 是一款C# 语言编写的TCP/UDP通信框架  作者是英国人  以前是收费的 目前作者已经开源  许可是 ...