AsyncTask的使用以及源码分析
AsyncTask详解
引言: 在Android的实际开发中,经常会涉及到线程的通讯,例如我们获取一张图片,先从网络获取成功之后再页面中,像网络操作是需要在后台线程中进行的,但是展示的时候需要将数据发送到主线程中,这期间就涉及到线程的通讯,当然线程的通讯有很多种,例如谷歌推出的Handler,当然常见的进程通讯中的Binde机制也是可以的,谷歌为了更好的实现线程通讯也提供了一个比较好用的类,这就是AsyncTask.
这篇文章不只是讲述AsyncTask的使用,为了更好的理解AsyncTask机制,也会对源码进行一定的分析.
在此之前需要了解以下内容
Handler
:
谷歌为解决不同线程之间的通讯问题而推出的一个类,开发中经常用到 ThreadFactory
:
线程工厂,用于统一创建指定线程 AtomicInteger
:
用于获取自增Integer的类,可以指定初始化的种子 AtomicBoolean
:
用于获取自增Booleanr的类,可以指定初始化的种子 Executor
:
线程池的统一实现接口,在该类中自定义实现了一个线程池SerialExecutor
Callable
:
有返回值的线程,常用的创建方式有直接创建Thread和通过Runnable的方式创建Thread,但是这两种方式没有返回值 FutureTask
:
该类用于包裹callable或者runnable,用于异步的获取执行结果,可以通过get()
方法获取返回值 ArrayDeque
:
通过数组实现的循环队列,传统的队列是先进先出,该队列可以通过两端获取数据,这篇文章写的挺好的,可以看一下
https://www.cnblogs.com/wxd0108/p/7366234.html
使用方法
使用方法的话不是很复杂,常用重写的方法有
doInBackground()
,onProgressUpdate()
,onPostExecute()
,onCancelled()
分别表示后台数据的处理,进度的更新,完成的结果以及取消
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");
}
//当取消之后调用的方法
@Override
protected void onCancelled() {
super.onCancelled();
}
}
//使用方法
DownloadFilesTask task = new DownloadFilesTask();
//消息的发送
task.execute();
//消息的取消
task.cancel(true);
开头静态代码块
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;
}
在静态代码快中主要是创建了一个线程池,线程池的最大线程大小根据cpu的核心数计算,最大值为4,最小值为2
SerialExecutor
内部类,最终执行
execute()
的时候,会调用该类的execute()
方法
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
//插入runnable到队列的尾部
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 AsyncTask(@Nullable Looper callbackLooper) {
//获取一个Handler,该Handler主要是主线程Hnadler,因为有两个构造方法是隐藏的QAQ
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
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 {
//将获取的结果通过Handler发送出去
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);
}
}
};
}
我们可以看到在构造方法主要是创建了两个对象,分别是WorkerRunnable
和FutureTask
,这两个方法
主要是线程的管理,根据线程获取的值进行相应的的操作,取消,发送进度或者是完成发送结果
postResult(),postResultIfNotInvoked()
消息的发送,会在InternalHandler中处理相关的消息
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
postResult(),postResultIfNotInvoked()
消息进度的发送,会在InternalHandler中处理相关的消息,有用户主动调用,回调结果在onProgressUpdate中,用户可以根据不同进度进行相关的显示
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
//发送进度消息
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
executeOnExecutor()
当用户调用execute()方法的时候会走该方法,通常情况下只能走一次,因为里面有判断,但是如果调用的是
execute(Runnable runnable)
则不会限制
@MainThread
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();
//执行任务,默认的是```SerialExecutor```中的方法,前面介绍过
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
总结
AsyncTask是谷歌为了方便不同线程的通讯而做的一个类,适合简单的线程通讯,可以很方便的在UI线程和子线程之间进行消息的传递而无需创建Handler或者是多余的线程,但是不适合做耗时的操作如果需要耗时操作可以用Executor,ThreadPoolExecutor或者FutureTask
上一篇: easyui tree修改图标
下一篇: 日志系列--行车轨迹日志的统计分析
推荐阅读
-
AsyncTask的使用以及源码分析
-
YuvImage源码分析以及使用
-
(八)JobSchedule 的使用以及源码分析
-
带你从源码一步步分析Android View面试中的事件分发流程
-
SpringMvc的执行流程(从源码的角度分析)
-
从源码角度分析Volley的请求流程
-
这一次,binder真正理解了(一) -----跨进程通信以及AIDL的使用
-
Vue基础精讲 —— 规范代码三步走?关于eslint和editorconfig以及precommit的安装和使用
-
alibaba fastjson的使用总结和心得 博客分类: 开源分析系统使用 fastjsonjson
-
解决jenkins产生的日志过大以及一些衍生问题 博客分类: 开源分析系统使用Linux jenkins