AsyncTask是什么鬼
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是什么鬼相关推荐
- android asynctask源码分析,Android通过Handler与AsyncTask两种方式动态更新ListView(附源码)...
本文实例讲述了Android通过Handler与AsyncTask两种方式动态更新ListView的方法.分享给大家供大家参考,具体如下: 有时候我们需要修改已经生成的列表,添加或者修改数据,noti ...
- 【Android】AsyncTask异步类
一.关于AysncTask AsyncTask使得多线程编程更加简单,AsyncTask能在后台线程执行异步任务,并且在UI线程更新界面,而不再需要用户去操作Thread和Handler.AysncT ...
- [译] Bob,函数式编程是什么鬼?
原文地址:Intro to Swift Functional Programming with Bob 原文作者:Bob Lee 译文出自:掘金翻译计划 译者:Deepmissea 校对者:thank ...
- Asynctask源码分析
首先我们使用AsyncTask时,一般是: new AsyncTask(...).execute() 复制代码 我们看new AsyncTask(),它走的是: public AsyncTask( ...
- Android 多线程-----AsyncTask详解
您可以通过点击 右下角 的按钮 来对文章内容作出评价, 也可以通过左下方的 关注按钮 来关注我的博客的最新动态. 如果文章内容对您有帮助, 不要忘记点击右下角的 推荐按钮 来支持一下哦 如果您对文章内 ...
- android一个简单的异步AsyncTask下载数示例,简单下载(07)
2019独角兽企业重金招聘Python工程师标准>>> public class MainActivity extends Activity {private ImageView i ...
- 前端测试 karma mocha should 都是什么鬼?
测试TDD和BDD的区别 TDD是测试驱动开发,通过用测试用例来规范约束开发者,编写出质量更高的代码 BDD是行为驱动开发,描述行为路径,就像描述故事,产品和前线业务人员可参与到开发流程中,减轻测试和 ...
- Python的GIL是什么鬼,多线程性能究竟如何
2019独角兽企业重金招聘Python工程师标准>>> #Python的GIL是什么鬼,多线程性能究竟如何 前言:博主在刚接触Python的时候时常听到GIL这个词,并且发现这个词经 ...
- CTF---Web入门第一题 what a fuck!这是什么鬼东西?
what a fuck!这是什么鬼东西?分值:10 来源: DUTCTF 难度:易 参与人数:7942人 Get Flag:3358人 答题人数:3475人 解题通过率:97% what a fuck ...
最新文章
- hdu 1208(简单dp)
- redis事务及watch使用示例
- 典型用户分析及用户场景分析
- vue 中 created 和 mounted 钩子生命周期 问题
- 从今天开始学习iOS开发(iOS 7版)-- 概论 (一)
- 原版英文书籍《Linux命令行》阅读记录7 | 原版英文书籍《Linux命令行》阅读记录7 | 一些键盘按键技巧...
- h5 uniapp history模式下刷新页面404
- HL7数据类型分析(1)
- LeetCode(908)——最小差值 I(JavaScript)
- Linux shell笔记5 基本文本处理
- 在计算机网络中vc是,计算机网络——第一章 体系
- 【预测模型】基于matlab GUI AR模型线性预测【含Matlab源码 942期】
- 层次分析matlab例题,层次分析法例题
- 微信小程序--Todos案例
- 超小白教程之快速排序
- POJ 3233 Matrix Power Series(java)
- 2020家用千兆路由器哪款好_家用路由器哪个牌子好穿墙2020
- 2012年那些大败局
- 【Android】@GuardedBy注解
- python常用的正则符号汇总
热门文章
- ae连续流动的线条_摄影师的300㎡极简豪宅,全是黑白线条,却美到炸?
- 操作系统免驱设备实现调研
- 如果网页内容需要支持多语言,你会怎么做?在设计和开发多语言网站时,有哪些问题你必须要考虑?
- 解决VUE自定义拖拽指令时 onmouseup 与 click事件冲突
- 湖科大教学匠计网微课堂思维导图
- 最新云盘网盘PHP源码系统源码+对接云存储/附安装教程
- 学习记录565@ElGamal公钥体系及其解密证明
- 数据库基础(基本概念、关系数据库、数据库标准语言SQL)
- 马斯克要干翻人工智能,“神经蕾丝”能让每个人都能当钢铁侠
- 拓嘉启远:想更改拼多多主营类目,可以吗