Android UI是线程不安全的,如果想要在子线程里进行UI操作,就需要借助Android的异步消息处理机制,在Android中实现异步任务机制有两种方式,Handler和AsyncTask。Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更新,这种方式对于整个过程的控制比较精细,但也是有缺点的,例如代码相对臃肿,在多个任务同时执行时,不易对线程进行精确的控制,AsyncTask,它使创建异步任务变得更加简单,不再需要编写任务线程和Handler实例即可完成相同的任务。

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

有三个泛型参数:
三种泛型类型分别代表“启动任务执行的输入参数”、“后台任务执行的进度”、“后台计算结果的类型”。在特定场合下,并不是所有类型都被使用,如果没有被使用,可以用java.lang.Void类型代替。
一个异步任务的执行一般包括以下几个步骤:
1.execute(Params… params),执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。(手动调用)

2.onPreExecute(),在execute(Params… params)被调用后立即执行,一般用来在执行后台任务前对UI做一些标记。(进度条初始化)

3.doInBackground(Params… params),在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接收输入参数和返回计算结果。在执行过程中可以调用publishProgress(Progress… values)来更新进度信息。

4.onProgressUpdate(Progress… values),在调用publishProgress(Progress… values)时,此方法被执行,直接将进度信息更新到UI组件上。

5.onPostExecute(Result result),当后台操作结束时,此方法将会被调用,计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。

在使用的时候,有几点需要格外注意:
1.异步任务的实例必须在UI线程中创建。
2.execute(Params… params)方法必须在UI线程中调用。
3.不要手动调用onPreExecute(),doInBackground(Params… params),onProgressUpdate(Progress… values),onPostExecute(Result result)这几个方法.(会自定执行)
4.不能在doInBackground(Params… params)中更改UI组件的信息。
5.一个任务实例只能执行一次,如果执行第二次将会抛出异常。
看一个例子

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;public class MainActivity extends Activity {private ImageView imageView;private Button button;private String urlString = "http://images.china.cn/attachement/jpg/site1000/20150616/002564bb20a216e9add813.jpg";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);imageView = (ImageView) findViewById(R.id.imageView_main_show);button = (Button) findViewById(R.id.button_main_download);button.setOnClickListener(new View.OnClickListener() {  @Overridepublic void onClick(View v) {new DownloadImageTask(MainActivity.this).execute(urlString);}});}/** Params:输入任务的参数:doInBackground()方法的参数、execute()方法的参数* Progress:任务执行是的进度指示:onProgressUpdate()方法的参数、publishProgress()方法的参数* Result:任务执行的结果:doInBackground()方法的返回值、onPostExecute()方法的参数*/class DownloadImageTask extends AsyncTask<String, Integer, Bitmap> {    private ProgressDialog progressDialog;private Context context;public DownloadImageTask(Context context) {this.context = context;progressDialog = new ProgressDialog(context);       progressDialog.setIcon(R.drawable.ic_launcher);progressDialog.setTitle("提示信息");progressDialog.setMessage("正在努力为您加载...");       progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);progressDialog.setMax(100);     // 为Dialog添加取消监听progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {         @Overridepublic void onCancel(DialogInterface dialog) {              // 取消异步任务cancel(true);}});}// 该方法在主线程中调用@Overrideprotected void onPreExecute() {progressDialog.show();super.onPreExecute();}// 该方法在子线程中调用@Overrideprotected Bitmap doInBackground(String... params) {InputStream inStream = null;ByteArrayOutputStream outStream = new ByteArrayOutputStream();try {URL url = new URL(params[0]);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setReadTimeout(5000);conn.setDoInput(true);conn.setRequestMethod("GET");conn.connect();if (conn.getResponseCode() == 200) {inStream = conn.getInputStream();byte[] buffer = new byte[512];int length = 0;// 要下载文件的总长度int fileLength = conn.getContentLength();// 已经下载的文件长度int downloadLength = 0;while ((length = inStream.read(buffer)) != -1) {outStream.write(buffer, 0, length);// 计算的出当前的进度值downloadLength += length;int progress = (int) ((downloadLength / (float) fileLength) * 100);// 发布进度,引起onProgressUpdate()方法的调用publishProgress(progress);if (isCancelled()) {outStream = null;break;}}if (outStream != null) {byte[] imgData = outStream.toByteArray();Bitmap imgBitmap = BitmapFactory.decodeByteArray(imgData, 0, imgData.length);return imgBitmap;}}} catch (Exception e) {e.printStackTrace();} finally {if (inStream != null) {try {inStream.close();} catch (IOException e) {e.printStackTrace();}}}return null;}// 该方法在主线程中调用@Overrideprotected void onProgressUpdate(Integer... values) {// 使用ProgressDialog显示进度值progressDialog.setProgress(values[0]);super.onProgressUpdate(values);}// 该方法在主线程中调用@Overrideprotected void onPostExecute(Bitmap result) {progressDialog.dismiss();if(result != null) {imageView.setImageBitmap(result);} else {Toast.makeText(MainActivity.this, "获取图片失败", Toast.LENGTH_SHORT).show();}super.onPostExecute(result);}// 该方法在主线程中调用@Overrideprotected void onCancelled(Bitmap result) {Toast.makeText(context, "取消了下载", Toast.LENGTH_SHORT).show();super.onCancelled(result);}}}

AsyncTask是对Thread+Handler良好的封装,在android.os.AsyncTask代码里仍然可以看到Thread和Handler的踪迹

我们可以看到关键几个步骤的方法都在其中,doInBackground(Params… params)是一个抽象方法,我们继承AsyncTask时必须覆写此方法;onPreExecute()、onProgressUpdate(Progress… values)、onPostExecute(Result result)、onCancelled()这几个方法体都是空的,我们需要的时候可以选择性的覆写它们;publishProgress(Progress… values)是final修饰的,不能覆写,只能去调用,我们一般会在doInBackground(Params… params)中调用此方法;另外,我们可以看到有一个Status的枚举类和getStatus()方法,Status枚举类代码段如下:

      //初始状态  private volatile Status mStatus = Status.PENDING;  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. */  FINISHED,  }  /** * Returns the current status of this task. * * @return The current status. */  public final Status getStatus() {  return mStatus;  }  

根据静态代码块的执行顺序,AsyncTask的初始状态为PENDING,代表待定状态,RUNNING代表执行状态,FINISHED代表结束状态,这几种状态在AsyncTask一次生命周期内的很多地方被使用,非常重要。

介绍完大纲视图相关内容之后,接下来,我们会从execute(Params… params)作为入口,重点分析一下AsyncTask的执行流程,我们来看一下execute(Params… params)方法的代码段:

    public final AsyncTask<Params, Progress, Result> execute(Params... params) {  if (mStatus != Status.PENDING) {  switch (mStatus) {  case RUNNING:  //如果该任务正在被执行则抛出异常  //值得一提的是,在调用cancel取消任务后,状态仍未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)");  }  }  //改变状态为RUNNING  mStatus = Status.RUNNING;  //调用onPreExecute方法  onPreExecute();  mWorker.mParams = params;  sExecutor.execute(mFuture);  return this;  }  

三个陌生的变量:mWorker、sExecutor、mFuture,我们也会看一下他们的庐山真面目:

关于sExecutor,它是java.util.concurrent.ThreadPoolExecutor的实例,用于管理线程的执行。代码如下:

    private static final int CORE_POOL_SIZE = 5;  private static final int MAXIMUM_POOL_SIZE = 128;  private static final int KEEP_ALIVE = 10;  //新建一个队列用来存放线程  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);  

mWorker实际上是AsyncTask的一个的抽象内部类的实现对象实例,它实现了Callable接口中的call()方法,代码如下:

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

而mFuture实际上是java.util.concurrent.FutureTask的实例,下面是它的FutureTask类的相关信息:

  * A cancellable asynchronous computation. * ... */
public class FutureTask<V> implements RunnableFuture<V> {  }public interface RunnableFuture<V> extends Runnable, Future<V> {  /** * Sets this Future to the result of its computation * unless it has been cancelled. */  void run();  }  

可以看到FutureTask是一个可以中途取消的用于异步计算的类。下面是mWorker和mFuture实例在AsyncTask中的体现:

 private final WorkerRunnable<Params, Result> mWorker;  private final FutureTask<Result> mFuture;  public AsyncTask() {  mWorker = new WorkerRunnable<Params, Result>() {  //call方法被调用后,将设置优先级为后台级别,然后调用AsyncTask的doInBackground方法  public Result call() throws Exception {  Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  return doInBackground(mParams);  }  };  //在mFuture实例中,将会调用mWorker做后台任务,完成后会调用done方法  mFuture = new FutureTask<Result>(mWorker) {  @Override  protected void done() {  Message message;  Result result = null;  try {  result = get();  } catch (InterruptedException e) {  android.util.Log.w(LOG_TAG, e);  } catch (ExecutionException e) {  throw new RuntimeException("An error occured while executing doInBackground()",  e.getCause());  } catch (CancellationException e) {  //发送取消任务的消息  message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,  new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null));  message.sendToTarget();  return;  } catch (Throwable t) {  throw new RuntimeException("An error occured while executing "  + "doInBackground()", t);  }  //发送显示结果的消息  message = sHandler.obtainMessage(MESSAGE_POST_RESULT,  new AsyncTaskResult<Result>(AsyncTask.this, result));  message.sendToTarget();  }  };  }  

我们看到上面的代码中,mFuture实例对象的done()方法中,如果捕捉到了CancellationException类型的异常,则发送一条“MESSAGE_POST_CANCEL”的消息;如果顺利执行,则发送一条“MESSAGE_POST_RESULT”的消息,而消息都与一个sHandler对象关联。这个sHandler实例实际上是AsyncTask内部类InternalHandler的实例,而InternalHandler正是继承了Handler,下面我们来分析一下它的代码:

    private static final int MESSAGE_POST_RESULT = 0x1; //显示结果  private static final int MESSAGE_POST_PROGRESS = 0x2;    //更新进度  private static final int MESSAGE_POST_CANCEL = 0x3;  //取消任务  private static final InternalHandler sHandler = new InternalHandler();  private static class InternalHandler extends Handler {  @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  //调用AsyncTask.finish方法  result.mTask.finish(result.mData[0]);  break;  case MESSAGE_POST_PROGRESS:  //调用AsyncTask.onProgressUpdate方法  result.mTask.onProgressUpdate(result.mData);  break;  case MESSAGE_POST_CANCEL:  //调用AsyncTask.onCancelled方法  result.mTask.onCancelled();  break;  }  }  }  

我们看到,在处理消息时,遇到“MESSAGE_POST_RESULT”时,它会调用AsyncTask中的finish()方法,我们来看一下finish()方法的定义:

    private void finish(Result result) {  if (isCancelled()) result = null;  onPostExecute(result);  //调用onPostExecute显示结果  mStatus = Status.FINISHED;  //改变状态为FINISHED  }  

原来finish()方法是负责调用onPostExecute(Result result)方法显示结果并改变任务状态的啊。

概括来说,当我们调用execute(Params… params)方法后,execute方法会调用onPreExecute()方法,然后由ThreadPoolExecutor实例sExecutor执行一个FutureTask任务,这个过程中doInBackground(Params… params)将被调用,如果被开发者覆写的doInBackground(Params… params)方法中调用了publishProgress(Progress… values)方法,则通过InternalHandler实例sHandler发送一条MESSAGE_POST_PROGRESS消息,更新进度,sHandler处理消息时onProgressUpdate(Progress… values)方法将被调用;如果遇到异常,则发送一条MESSAGE_POST_CANCEL的消息,取消任务,sHandler处理消息时onCancelled()方法将被调用;如果执行成功,则发送一条MESSAGE_POST_RESULT的消息,显示结果,sHandler处理消息时onPostExecute(Result result)方法被调用。

AsyncTask是什么鬼相关推荐

  1. android asynctask源码分析,Android通过Handler与AsyncTask两种方式动态更新ListView(附源码)...

    本文实例讲述了Android通过Handler与AsyncTask两种方式动态更新ListView的方法.分享给大家供大家参考,具体如下: 有时候我们需要修改已经生成的列表,添加或者修改数据,noti ...

  2. 【Android】AsyncTask异步类

    一.关于AysncTask AsyncTask使得多线程编程更加简单,AsyncTask能在后台线程执行异步任务,并且在UI线程更新界面,而不再需要用户去操作Thread和Handler.AysncT ...

  3. [译] Bob,函数式编程是什么鬼?

    原文地址:Intro to Swift Functional Programming with Bob 原文作者:Bob Lee 译文出自:掘金翻译计划 译者:Deepmissea 校对者:thank ...

  4. Asynctask源码分析

    ​ 首先我们使用AsyncTask时,一般是: new AsyncTask(...).execute() 复制代码 我们看new AsyncTask(),它走的是: public AsyncTask( ...

  5. Android 多线程-----AsyncTask详解

    您可以通过点击 右下角 的按钮 来对文章内容作出评价, 也可以通过左下方的 关注按钮 来关注我的博客的最新动态. 如果文章内容对您有帮助, 不要忘记点击右下角的 推荐按钮 来支持一下哦 如果您对文章内 ...

  6. android一个简单的异步AsyncTask下载数示例,简单下载(07)

    2019独角兽企业重金招聘Python工程师标准>>> public class MainActivity extends Activity {private ImageView i ...

  7. 前端测试 karma mocha should 都是什么鬼?

    测试TDD和BDD的区别 TDD是测试驱动开发,通过用测试用例来规范约束开发者,编写出质量更高的代码 BDD是行为驱动开发,描述行为路径,就像描述故事,产品和前线业务人员可参与到开发流程中,减轻测试和 ...

  8. Python的GIL是什么鬼,多线程性能究竟如何

    2019独角兽企业重金招聘Python工程师标准>>> #Python的GIL是什么鬼,多线程性能究竟如何 前言:博主在刚接触Python的时候时常听到GIL这个词,并且发现这个词经 ...

  9. CTF---Web入门第一题 what a fuck!这是什么鬼东西?

    what a fuck!这是什么鬼东西?分值:10 来源: DUTCTF 难度:易 参与人数:7942人 Get Flag:3358人 答题人数:3475人 解题通过率:97% what a fuck ...

最新文章

  1. hdu 1208(简单dp)
  2. redis事务及watch使用示例
  3. 典型用户分析及用户场景分析
  4. vue 中 created 和 mounted 钩子生命周期 问题
  5. 从今天开始学习iOS开发(iOS 7版)-- 概论 (一)
  6. 原版英文书籍《Linux命令行》阅读记录7 | 原版英文书籍《Linux命令行》阅读记录7 | 一些键盘按键技巧...
  7. h5 uniapp history模式下刷新页面404
  8. HL7数据类型分析(1)
  9. LeetCode(908)——最小差值 I(JavaScript)
  10. Linux shell笔记5 基本文本处理
  11. 在计算机网络中vc是,计算机网络——第一章 体系
  12. 【预测模型】基于matlab GUI AR模型线性预测【含Matlab源码 942期】
  13. 层次分析matlab例题,层次分析法例题
  14. 微信小程序--Todos案例
  15. 超小白教程之快速排序
  16. POJ 3233 Matrix Power Series(java)
  17. 2020家用千兆路由器哪款好_家用路由器哪个牌子好穿墙2020
  18. 2012年那些大败局
  19. 【Android】@GuardedBy注解
  20. python常用的正则符号汇总

热门文章

  1. ae连续流动的线条_摄影师的300㎡极简豪宅,全是黑白线条,却美到炸?
  2. 操作系统免驱设备实现调研
  3. 如果网页内容需要支持多语言,你会怎么做?在设计和开发多语言网站时,有哪些问题你必须要考虑?
  4. 解决VUE自定义拖拽指令时 onmouseup 与 click事件冲突
  5. 湖科大教学匠计网微课堂思维导图
  6. 最新云盘网盘PHP源码系统源码+对接云存储/附安装教程
  7. 学习记录565@ElGamal公钥体系及其解密证明
  8. 数据库基础(基本概念、关系数据库、数据库标准语言SQL)
  9. 马斯克要干翻人工智能,“神经蕾丝”能让每个人都能当钢铁侠
  10. 拓嘉启远:想更改拼多多主营类目,可以吗