个人博客:

http://www.milovetingting.cn

AsyncTask可以让我们更容易地使用UI线程。它允许执行后台操作,并把结果发布到UI线程上,而不需要操作线程或Handler。AsyncTask被设计成一个和Thread、Handler相关的一个帮助类。AsyncTask用于短时(最多是几秒)的操作。

AsyncTask使用需要注意以下几点:

  • AsyncTask类必须在UI线程上加载。AsyncTask必须在UI线程实例化。execute()方法也必须在UI线程调用。

  • 不要手动调用onPreExecute()、onPostExecute()、doInBackground()、onProgressUpdate()方法。

  • 每个AsyncTask实例只能调用一次execute,如果再次调用,则会抛出异常。

AsyncTask首次引入时,AsyncTask中的任务是串行的。从Android1.6之后,AsyncTask被设计成并行的。从Android3.0后,AsyncTask被重新设计成串行。如果在3.0后的版本需要并行,则可以调用AsyncTask的executeOnExecutor(java.util.concurrent.Executor, Object[])方法,手动传入Executor。

在AsyncTask类加载时,会初始化ThreadPoolExecutor:

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

其中,核心线程数,最小为2个,最大为4个:

private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));

最大线程数CPU数量*2+1:

private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;

KeepAlive时间为30s:

private static final int KEEP_ALIVE_SECONDS = 30;

任务队列最大是128:

private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);

AsyncTask的基本使用:

1、定义一个类,继承自AsyncTask,根据需要重写doInBackground()、onProgressUpdate()、onPostExecute()方法,一般doInBackground()、onPostExecute()方法是需要重写的,在这里实现自己的业务。doInBackground()方法运行在子线程中。onProgressUpdate()和onPostExecute()运行在UI线程。

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]);
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");
}
}

2、创建DownloadFilesTask的实例,并执行execute()方法:

new DownloadFilesTask().execute(url1, url2, url3);

下面,从源码角度来分析下AsyncTask的原理。

AsyncTask的执行入口是execute方法:

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

execute()方法必须在UI线程调用。在方法内部调用了executeOnExecutor()方法。

@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
//检查AsyncTask状态,不是未执行状态(如任务正在运行或已完成),则会抛出相应异常
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)");
}
} //将状态置为RUNNING
mStatus = Status.RUNNING; onPreExecute(); mWorker.mParams = params;
exec.execute(mFuture); return this;
}

executeOnExecutor()方法也必须在UI线程调用。在方法开始时,会检查AsyncTask状态,不是未执行状态(如任务正在运行或已完成),则会抛出相应异常。然后,将任务状态置为RUNNING状态,调用onPreExecute()方法,这个方法需要自己重写,可以做一些UI提示。然后,将参数设置为mWorker,调用Executor的execute()方法。

如果使用默认的Executor,则为串行。

@MainThread
public static void execute(Runnable runnable) {
sDefaultExecutor.execute(runnable);
}

接下来,看看sDefaultExecutor的定义:

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

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

mWorker的定义:

mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
//将线程设置为后台线程
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
//调用doInBackground方法
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
//发送结果
postResult(result);
}
return result;
}
};

当执行execute()方法,会调用mWorker的call()方法,在此方法中,会将线程设置为后台线程,然后调用doInBackground()方法,并在执行完成后调用postResult()方法。在doInBackground()方法中,可以调用publishProgress()方法,将进度信息发送到UI线程中。

postResult()方法:

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

发送一个Message到Handler中.

private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
} @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;
}
}
}

在Handler的handleMessage()方法中处理消息。如果已经执行完成,则会调用AsyncTask的finish()方法,如果是更新进度,则会调用AsyncTask的onProgressUpdate()方法:

private void finish(Result result) {
if (isCancelled()) {
//如果是取消任务,则回调onCancelled()方法。
onCancelled(result);
} else {
//回调onPostExecute()方法
onPostExecute(result);
}
//设置状态为FINISHED
mStatus = Status.FINISHED;
} @MainThread
protected void onProgressUpdate(Progress... values) {
}

publishProgress()方法:

@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}

AsyncTask机制的更多相关文章

  1. 源码篇——AsyncTask机制

    AsyncTask new AsyncTask<String,String,String>(){ // 运行在主线程中,做预备工作 onPreExecute(){ } // 运行在子线程中 ...

  2. AsyncTask机制学习

    其内容可以参考http://blog.csdn.net/webgeek/article/details/17298237 ,首先创建一个AsyncTask类 class GetFaceDetectTa ...

  3. Android多线程通信机制

    掌握Android的多线程通信机制,我们首先应该掌握Android中进程与线程是什么. 1. 进程 在Android中,一个应用程序就是一个独立的进程(应用运行在一个独立的环境中,可以避免其他应用程序 ...

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

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

  5. Android多线程----异步消息处理机制之Handler详解

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  6. Android 多线程----AsyncTask异步任务详解

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3 ...

  7. Android Learning:多线程与异步消息处理机制

    在最近学习Android项目源码的过程中,遇到了很多多线程以及异步消息处理的机制.由于之前对这块的知识只是浅尝辄止,并没有系统的理解.但是工程中反复出现让我意识到这个知识的重要性.所以我整理出这篇博客 ...

  8. Android菜鸟成长记14 -- AsnyTask

    本篇随笔将讲解一下Android的多线程的知识,以及如何通过AsyncTask机制来实现线程之间的通信. 一.Android当中的多线程 在Android当中,当一个应用程序的组件启动的时候,并且没有 ...

  9. Android-AsyncTask异步任务(获取手机联系人)

    本篇随笔将讲解一下Android的多线程的知识,以及如何通过AsyncTask机制来实现线程之间的通信. 一.Android当中的多线程 在Android当中,当一个应用程序的组件启动的时候,并且没有 ...

随机推荐

  1. Element-ui使用技巧

    使用第三方字体包 把下载后的*.zip字体包放到项目中在main.js中引用. import "@/assets/font/iconfont.css"; 注意一定要放到elemen ...

  2. 面向对象之三个基本特征(javaScript)

    1. 前言 2. 封装 3. 继承 4. 多态 5. 总结 1. 前言 了解过面向对象的同学应该都知道,面向对象三个基本特征是:封装.继承.多态,但是对于这三个词具体可能不太了解. 2. 封装 在说封 ...

  3. 第13章 Base64 URL编码 - IdentityModel 中文文档(v1.0.0)

    JWT令牌使用Base64 URL编码进行序列化. IdentityModel包括Base64Url帮助编码/解码的类: var text = "hello"; var b64ur ...

  4. 结合JDK源码看设计模式——单例模式

    定义: 保证一个类仅有一个实例,并提供一个全局访问点 适用场景: 确保任何情况下这个对象只有一个实例 详解: 私有构造器 单利模式中的线程安全+延时加载 序列化和反序列化安全, 防止反射攻击 结合JD ...

  5. Android之应用市场排行榜、上架、首发

    文章大纲 一.应用市场排行榜介绍二.应用市场上架介绍三.应用市场首发介绍四.参考文档   一.应用市场排行榜介绍   iiMedia Research(艾媒咨询)权威发布<2017-2018中国 ...

  6. 记录一些flutter学习网址

    字体图标生成 http://fluttericon.com/Flutter中文网 https://flutterchina.club Flutter官网 https://flutter.ioFlutt ...

  7. Core文件简单介绍及生成设置方法

    Core文件简单介绍及生成设置方法 Core文件其实就是内存的映像,当程序崩溃时,存储内存的相应信息,主用用于对程序进行调试.当程序崩溃时便会产生core文件,其实准确的应该说是core dump 文 ...

  8. 阿里云SLB出现502 Bad Gateway 错误排查解决方法

    502 Bad Gateway The proxy server received an invalid response from an upstream server. 原本系统是通过一个SLB转 ...

  9. CMake简介

    目录 一.CMake简介 二.CMake典型示例 源代码 demo.cpp cmake脚本 CMakeLists.txt 编译流程 三.CMake常用命令 常用命令介绍 设置编译目标类型 指定编译包含 ...

  10. 借助Chrome和插件爬取数据

    工具 Chrome浏览器 TamperMonkey ReRes Chrome浏览器 chrome浏览器是目前最受欢迎的浏览器,没有之一,它兼容大部分的w3c标准和ecma标准,对于前端工程师在开发过程 ...