AsyncTask学习
在学习Android的时候,我们用到比较多的异步处理的类大概就是AsyncTask,但是很多时候只知道调用,却不知道思考一些东西。
本文就简单的总结和分析了一些AsyncTask的知识。
一、AsyncTask使用
直接继承AsyncTask,它一共有3个泛型参数Params, Progress, Result.
public abstract class AsyncTask<Params, Progress, Result>
- Params表示AsyncTask执行任务的参数的类型(传入的参数的类型,在doInBackground用到的,使用execute方法中传入)
- Progress表示在后台线程处理的过程中,可以阶段性地发布结果的数据类型(在onProgressUpdate中用到,使用publicProgress中传入)
- Result表示任务全部完成后所返回的数据类型(doInBackground方法的返回值)
必须实现的方法有一个:
protected abstract Result doInBackground(Params... params);
这个方法是在异步线程中执行的,我们主要操作和实现的就是这个方法。
有3个方法需要熟悉:
#异步执行之前也就是doInBackground之前执行
protected void onPreExecute()
#异步执行之后也就是doInBackground之后执行
protected void onPostExecute(Result result)
#执行过程中执行
protected void onProgressUpdate(Progress... values)
这3个方法都是在UI线程中,所以可以直接更新UI。
执行的方法有两个:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
execute方法,每次只能执行一个线程,不支持并发。
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
executeOnExecutor可以添加自己的线程池,是可以支持并发的。
AsyncTask使用的注意事项:
AsyncTask的实例必须在主线程中创建。
AsyncTask的execute方法必须在主线程中调用。
onPreExecute()、onPostExecute(Result),、doInBackground(Params…) 和 onProgressUpdate(Progress…)这四个方法都是回调方法,Android会自动调用,我们不要自己调用。
对于一个AsyncTack的实例,只能执行一次execute,在该实例上第二次执行execute时就会抛出异常。
前两条基本是一个意思,就是使用AsyncTask的时候在UI线程中创建/执行。4个主要的方法不能在外部去调用,一个AsyncTask执行一次。
二、源码分析
AsyncTask主要是通过线程池+handler来实现。
线程池:
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
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; /**
* 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创建一个线程池,这线程池的核心线程是动态的,根据cpu的数量来定(2-4)个,在4.4之前的核心线程数是5。
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);
}
}
}
把Runnable放入双端队列末尾,交给线程池去处理。(java.util.ArrayDeque.offer(E e) 方法将指定元素E在此deque队列的末尾。
java.util.ArrayDeque.poll() 检索并移除此queue队列表示的队列的头部,如果此queue队列为空,返回null)
具体的线程:
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
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return 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);
}
}
};
主要就是这个FutureTask+Callable实现了异步线程,WorkerRunnable 实现了Callable接口。
(实现多线程的方式有几种?可能现在需要多记一种Callable)
主要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;
}
}
}
在实例化AsyncTask的时候会去准备好线程池、线程和handler,在execute执行的时候把线程扔到线程池中执行,执行中可以发送数据给handler(publishProgress),结束后发消息给handler(postResult)。
根据源代码可以总结出:
- execute方法会调用executeOnExecutor方法,使用的线程池还是默认的
- executeOnExecutor和execute在UI线程执行,那么里面调用的所有方法也是在UI线程中,所以onPreExecute()方法在UI线程中
- handler使用的是UI线程的looper = Looper.getMainLooper(),那么Handler的handleMessage方法在UI线程中,所以onPostExecute和onProgressUpdate在UI线程中。
AsyncTask学习的更多相关文章
- Android AsyncTask学习
Android程序有UI进程和后台进程,在执行一些耗时的操作时,如果在UI进程中,很可能出现假死的情况,用户体验会受到影响,因此,那些耗时进程往往就放在了后台进程中,用户体验能更好一些.网络情况不稳定 ...
- 如何自学Android--转
原文地址:http://blog.csdn.net/lavor_zl/article/details/51217319 1. Java知识储备 本知识点不做重点讲解: 对于有基础的同学推荐看<J ...
- 如何自学 Android 的?
http://android.jobbole.com/83380/ 1. Java知识储备 本知识点不做重点讲解:对于有基础的同学推荐看<Java编程思想>,巩固基础,查漏补全,了解并熟悉 ...
- 我是怎样自学 Android 的?
1. Java知识储备 本知识点不做重点解说: 对于有基础的同学推荐看<Java编程思想>,巩固基础,查漏补全,了解并熟悉很多其它细节知识点. 对于没有基础的同学推荐看一本Java基础的书 ...
- AsyncTask官方学习
异步任务学习 这两天使用到特别多的AsyncTask类,一块来学习一下吧 AsyncTask允许更方便和简单使用UI线程,这个类允许你在UI线程中进行后台操作和展示结果,而无需操作Thread或者ha ...
- Android学习之AsyncTask
我们在<Android学习之Handler消息传递机制>(http://www.cnblogs.com/zhouhb/p/5812447.html)已提到过,Android只允许UI线程修 ...
- Android 学习笔记多媒体技术之 AsyncTask+实现音频播放...
PS:今天搞了一下如何实现音频播放...结果被坑了,看书上写的代码是挺简单的,但是有个函数就是死活没看懂,这真是受不了...最后才弄明白,原来是一个实现异步任务的一个类...这个类使用java.uti ...
- Android应用开发学习笔记之AsyncTask
作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz 在上一篇文章中我们学习了多线程和Handler消息处理机制,如果有计算量比较大的任务,可以创建一个新线程执行计算工作 ...
- Android开发学习之路--异步消息Handler,Message,Looper和AsyncTask之初体验
在简易音乐播放器中,用了Handler,也没有过多地去研究学习,这里再学习下android下的异步消息处理机制.这里用了Handler主要是在线程中不能更新UI,而需要通过Handler才可以.关于异 ...
随机推荐
- Oracle存储过程经典入门
ok基本就这些介绍
- linux 命令随笔 ls cd pwd mkdir rm mv cp cat nl
Linux 命令练习 ls命令 ls就是list的简写,目的是打印当前目录下的清单 格式 ls[选项][目录名] 常用参数 -a –all 列出目录下的所有文件,包括以 . 开头的隐含文件 -l 除了 ...
- apriori关联规则
挖掘数据集:贩物篮数据 频繁模式:频繁地出现在数据集中的模式,例如项集,子结构,子序列等 挖掘目标:频繁模式,频繁项集,关联规则等 关联规则:牛奶=>鸡蛋[支持度=2%,置信度=60%] ...
- Angularjs –– Expressions(表达式)
点击查看AngularJS系列目录 转载请注明出处:http://www.cnblogs.com/leosx/ Angular的表达式 Angular的表达式和JavaScript代码很像,不过通常A ...
- 调试 ASP.NET Core 2.0 源代码
在Visual Studio 2017中可以通过符号以及源链接,非常方便对 ASP.NET Core 2.0中源代码进行调试.在这篇文章中,我们将重点介绍如何使用源链接对ASP.NET Core源进行 ...
- TCP/IP(八)之总结ICP/IP四层模型
前言 在这里有一个问题,有的书上说TCP/IP是四层有的却说是五层.其实这个问题我也上网查了一下资料. tcp/ip是事实标准,分4层.osi模型是国际标准,分7层.讲课的时候,一般把他们综合起来讲, ...
- Angular JS的正确打开姿势——简单实用(上)
前 言 絮叨絮叨 在分享了JS和JQuery之后,今天再给大家分享一个好玩并且特别好用JS框架--AngularJS. 一. AngularJS简介 AngularJS 诞生于2009年,由 ...
- Collecting Bugs poj2096 概率DP
Collecting Bugs Time Limit: 10000MS Me ...
- webservice部署到服务器报错
System.Net.WebException: 基础连接已经关闭: 发送时发生错误. ---> System.IO.IOException: 从传输流收到意外的 EOF 或 0 个字节. 在 ...
- @htmlhepler dropdownlistfor 报错
说系统的字段不匹配. 是因为ViewData,没有赋值.