AsyncTask源码解析
package com.example.demo.activity.net; import java.util.ArrayDeque;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.os.Process; public abstract class MyAsyncTask<Params, Progress, Result> {
private static final String LOG_TAG = "AsyncTask";
// 返回cpu的数目
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// 设置核心线程数量
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
// 设置最大线程数量
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
// 设置活跃时间
private static final int KEEP_ALIVE = 1;
// 创建线程的工厂
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 BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(128); // 创建了一个线程池,传入参数为核心线程2,最多线程3,休息时间1秒,容纳128个线程对象的队列,线程工厂
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
// 创建一个串行执行任务对象
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
// handler接受码
private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
// handler对象
private static final InternalHandler sHandler = new InternalHandler();
// 默认使用串行执行
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
// 继承了一个泛型的回掉接口,在mFuture的run方法中会调用mWorker的call回调方法
private final WorkerRunnable<Params, Result> mWorker;
// 线程对象,实现了RunnableFuture接口
private final FutureTask<Result> mFuture; private volatile Status mStatus = Status.PENDING;
// 判断是否已经主动取消执行中的任务
private final AtomicBoolean mCancelled = new AtomicBoolean();
// 判断
private final AtomicBoolean mTaskInvoked = new AtomicBoolean(); // 判断是否正常调用postResult(doInBackground(mParams))
private static class SerialExecutor implements Executor {
// 维护的队列,每execute一次就offer进来一个mFuture线程对象
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive; public synchronized void execute(final Runnable r) {
// 默认的execute提交就是把封装的mFuture用该方法提交,所有提交的线程对象都先存放在该队列中
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
// 队列中所有线程对象都执行完之后,mActive = mTasks.poll()就会等于null
// 然后新加入的任务又会重新启动执行
if (mActive == null) {
scheduleNext();
}
} // 从队列中获取一个线程对象,将他放到线程池中执行,执行完之后就会接着调用scheduleNext()来执行队列中的下一个线程对象
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
} /**
* Indicates the current status of the task. Each status will be set only once during the lifetime of a task.
*/
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,
} /** @hide Used to force static handler to be created. */
public static void init() {
sHandler.getLooper();
} /**
* 设置默认的线程池
*
* @param exec
*/
public static void setDefaultExecutor(Executor exec) {
sDefaultExecutor = exec;
} /**
* 构造函数,初始化了mFuture线程对象,并封装了mWorker回调接口
*/
public MyAsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true); Process.setThreadPriority(10);
// noinspection unchecked
return postResult(doInBackground(mParams));
}
};
// 被强行打断,出异常,或者正常结束都会调用下面的done(),
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 occured while executing doInBackground()", e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
} // 正常结束,出异常,被强行打断就会调用下面的方法
// 但是正常结束不会调用里面的postResult(result)。因为他已经在call()中调用
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
} /**
* 使用handler往主线程中发送返回结果
*
* @param result
* @return
*/
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
} /**
* Returns the current status of this task.
*
* @return The current status.
*/
public final Status getStatus() {
return mStatus;
} /**
* Override this method to perform a computation on a background thread. The specified parameters are the parameters passed to {@link #execute} by the caller of this task.
*
* This method can call {@link #publishProgress} to publish updates on the UI thread.
*
* @param params
* The parameters of the task.
*
* @return A result, defined by the subclass of this task.
*
* @see #onPreExecute()
* @see #onPostExecute
* @see #publishProgress
*/
protected abstract Result doInBackground(Params... params); /**
* Runs on the UI thread before {@link #doInBackground}.
*
* @see #onPostExecute
* @see #doInBackground
*/
protected void onPreExecute() {
} /**
* <p>
* Runs on the UI thread after {@link #doInBackground}. The specified result is the value returned by {@link #doInBackground}.
* </p>
*
* <p>
* This method won't be invoked if the task was cancelled.
* </p>
*
* @param result
* The result of the operation computed by {@link #doInBackground}.
*
* @see #onPreExecute
* @see #doInBackground
* @see #onCancelled(Object)
*/
@SuppressWarnings({ "UnusedDeclaration" })
protected void onPostExecute(Result result) {
} /**
* Runs on the UI thread after {@link #publishProgress} is invoked. The specified values are the values passed to {@link #publishProgress}.
*
* @param values
* The values indicating progress.
*
* @see #publishProgress
* @see #doInBackground
*/
@SuppressWarnings({ "UnusedDeclaration" })
protected void onProgressUpdate(Progress... values) {
} /**
* <p>
* Runs on the UI thread after {@link #cancel(boolean)} is invoked and {@link #doInBackground(Object[])} has finished.
* </p>
*
* <p>
* The default implementation simply invokes {@link #onCancelled()} and ignores the result. If you write your own implementation, do not call <code>super.onCancelled(result)</code>.
* </p>
*
* @param result
* The result, if any, computed in {@link #doInBackground(Object[])}, can be null
*
* @see #cancel(boolean)
* @see #isCancelled()
*/
@SuppressWarnings({ "UnusedParameters" })
protected void onCancelled(Result result) {
onCancelled();
} /**
* <p>
* Applications should preferably override {@link #onCancelled(Object)}. This method is invoked by the default implementation of {@link #onCancelled(Object)}.
* </p>
*
* <p>
* Runs on the UI thread after {@link #cancel(boolean)} is invoked and {@link #doInBackground(Object[])} has finished.
* </p>
*
* @see #onCancelled(Object)
* @see #cancel(boolean)
* @see #isCancelled()
*/
protected void onCancelled() {
} /**
* Returns <tt>true</tt> if this task was cancelled before it completed normally. If you are calling {@link #cancel(boolean)} on the task, the value returned by this method should be checked
* periodically from {@link #doInBackground(Object[])} to end the task as soon as possible.
*
* @return <tt>true</tt> if task was cancelled before it completed
*
* @see #cancel(boolean)
*/
public final boolean isCancelled() {
return mCancelled.get();
} /**
* <p>
* Attempts to cancel execution of this task. This attempt will fail if the task has already completed, already been cancelled, or could not be cancelled for some other reason. If successful, and
* this task has not started when <tt>cancel</tt> is called, this task should never run. If the task has already started, then the <tt>mayInterruptIfRunning</tt> parameter determines whether the
* thread executing this task should be interrupted in an attempt to stop the task.
* </p>
*
* <p>
* Calling this method will result in {@link #onCancelled(Object)} being invoked on the UI thread after {@link #doInBackground(Object[])} returns. Calling this method guarantees that
* {@link #onPostExecute(Object)} is never invoked. After invoking this method, you should check the value returned by {@link #isCancelled()} periodically from {@link #doInBackground(Object[])} to
* finish the task as early as possible.
* </p>
*
* @param mayInterruptIfRunning
* <tt>true</tt> if the thread executing this task should be interrupted; otherwise, in-progress tasks are allowed to complete.
*
* @return <tt>false</tt> if the task could not be cancelled, typically because it has already completed normally; <tt>true</tt> otherwise
*
* @see #isCancelled()
* @see #onCancelled(Object)
*/
/**
* 外部强行打断任务执行的时候调用,正常结束不用调用
*
* @param mayInterruptIfRunning
* @return
*/
public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
} /**
* Waits if necessary for the computation to complete, and then retrieves its result.
*
* @return The computed result.
*
* @throws CancellationException
* If the computation was cancelled.
* @throws ExecutionException
* If the computation threw an exception.
* @throws InterruptedException
* If the current thread was interrupted while waiting.
*/
public final Result get() throws InterruptedException, ExecutionException {
return mFuture.get();
} /**
* Waits if necessary for at most the given time for the computation to complete, and then retrieves its result.
*
* @param timeout
* Time to wait before cancelling the operation.
* @param unit
* The time unit for the timeout.
*
* @return The computed result.
*
* @throws CancellationException
* If the computation was cancelled.
* @throws ExecutionException
* If the computation threw an exception.
* @throws InterruptedException
* If the current thread was interrupted while waiting.
* @throws TimeoutException
* If the wait timed out.
*/
public final Result get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return mFuture.get(timeout, unit);
} /**
* Executes the task with the specified parameters. The task returns itself (this) so that the caller can keep a reference to it.
*
* <p>
* Note: this function schedules the task on a queue for a single background thread or pool of threads depending on the platform version. When first introduced, AsyncTasks were executed serially
* on a single background thread. Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed to a pool of threads allowing multiple tasks to operate in parallel. Starting
* {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are back to being executed on a single thread to avoid common application errors caused by parallel execution. If you truly want parallel
* execution, you can use the {@link #executeOnExecutor} version of this method with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings on its use.
*
* <p>
* This method must be invoked on the UI thread.
*
* @param params
* The parameters of the task.
*
* @return This instance of AsyncTask.
*
* @throws IllegalStateException
* If {@link #getStatus()} returns either {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
*
* @see #executeOnExecutor(java.util.concurrent.Executor, Object[])
* @see #execute(Runnable)
*/
/**
* 使用默认的串行执行
*
* @param params
* @return
*/
public final MyAsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
} /**
* Executes the task with the specified parameters. The task returns itself (this) so that the caller can keep a reference to it.
*
* <p>
* This method is typically used with {@link #THREAD_POOL_EXECUTOR} to allow multiple tasks to run in parallel on a pool of threads managed by AsyncTask, however you can also use your own
* {@link Executor} for custom behavior.
*
* <p>
* <em>Warning:</em> Allowing multiple tasks to run in parallel from a thread pool is generally <em>not</em> what one wants, because the order of their operation is not defined. For example, if
* these tasks are used to modify any state in common (such as writing a file due to a button click), there are no guarantees on the order of the modifications. Without careful work it is possible
* in rare cases for the newer version of the data to be over-written by an older one, leading to obscure data loss and stability issues. Such changes are best executed in serial; to guarantee
* such work is serialized regardless of platform version you can use this function with {@link #SERIAL_EXECUTOR}.
*
* <p>
* This method must be invoked on the UI thread.
*
* @param exec
* The executor to use. {@link #THREAD_POOL_EXECUTOR} is available as a convenient process-wide thread pool for tasks that are loosely coupled.
* @param params
* The parameters of the task.
*
* @return This instance of AsyncTask.
*
* @throws IllegalStateException
* If {@link #getStatus()} returns either {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
*
* @see #execute(Object[])
*/
/**
* 可以使用该类里面提供的线程池来执行任务
*
* @param exec
* @param params
* @return
*/
public final MyAsyncTask<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(); mWorker.mParams = params;
exec.execute(mFuture); return this;
} /**
* Convenience version of {@link #execute(Object...)} for use with a simple Runnable object. See {@link #execute(Object[])} for more information on the order of execution.
*
* @see #execute(Object[])
* @see #executeOnExecutor(java.util.concurrent.Executor, Object[])
*/
/**
* 使用默认的串行来执行线程对象
*
* @param runnable
*/
public static void execute(Runnable runnable) {
sDefaultExecutor.execute(runnable);
} /**
* This method can be invoked from {@link #doInBackground} to publish updates on the UI thread while the background computation is still running. Each call to this method will trigger the
* execution of {@link #onProgressUpdate} on the UI thread.
*
* {@link #onProgressUpdate} will not be called if the task has been canceled.
*
* @param values
* The progress values to update the UI with.
*
* @see #onProgressUpdate
* @see #doInBackground
*/
/**
* 如果已经被取消,就不会发送更新进度条
*
* @param values
*/
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
} /**
* 在handler中判断,如果已经被取消就调用onCancelled(result),正常结束调用onPostExecute(result)
*
* @param result
*/
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
} /**
* handler对象
*
* @author liulj
*
*/
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
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
} private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
} /**
* handler中传递的对象
*
* @author liulj
*
* @param <Data>
*/
@SuppressWarnings({ "RawUseOfParameterizedType" })
private static class AsyncTaskResult<Data> {
final MyAsyncTask mTask;
final Data[] mData; AsyncTaskResult(MyAsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
}
AsyncTask源码解析的更多相关文章
- Android AsyncTask 源码解析
1. 官方介绍 public abstract class AsyncTask extends Object java.lang.Object ↳ android.os.AsyncTask&l ...
- Android -- AsyncTask源码解析
1,前段时间换工作的时候,关于AsyncTask源码这个点基本上大一点的公司都会问,所以今天就和大家一起来总结总结.本来早就想写这篇文章的,当时写<Android -- 从源码解析Handle+ ...
- Android开发——AsyncTask的使用以及源码解析
.AsyncTask使用介绍 转载请标明出处:http://blog.csdn.net/seu_calvin/article/details/52172248 AsyncTask封装了Thread和 ...
- Android源码解析——AsyncTask
简介 AsyncTask 在Android API 3引入,是为了使UI线程能被正确和容易地使用.它允许你在后台进行一些操作,并且把结果带到UI线程中,而不用自己去操纵Thread或Handler.它 ...
- 小白挑战:AsyncTask源码分析
//AsyncTask从本质上讲,是对ThreadPool和handler的封装. 在学习线程池相关的知识时,看到书中提到AsyncTask的实现中使用到了ThreadPool,于是把源码翻了出来, ...
- Android Asynctask与Handler的比较,优缺点区别,Asynctask源码
1 AsyncTask实现的原理,和适用的优缺点 AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以 ...
- 【转载】Xutils3源码解析
Github源码地址:https://github.com/wyouflf/xUtils3 原文地址 :http://www.codekk.com/blogs/detail/54cfab086c476 ...
- Android源码解析系列
转载请标明出处:一片枫叶的专栏 知乎上看了一篇非常不错的博文:有没有必要阅读Android源码 看完之后痛定思过,平时所学往往是知其然然不知其所以然,所以为了更好的深入Android体系,决定学习an ...
- 还怕问源码?Github上神级Android三方源码解析手册,已有7.6 KStar
或许对于许多Android开发者来说,所谓的Android工程师的工作"不过就是用XML实现设计师的美术图,用JSON解析服务器的数据,再把数据显示到界面上"就好了,源码什么的,看 ...
随机推荐
- iis中限制访问某个文件或某个类型的文件配置方法
Note:此处不是权限设置问题,此处不是权限设置问题,此处不是权限设置问题!只是出于数据或者网络安全,禁止扫描工具直接扫描到某些包含敏感信息的文件,尤其比如日志.配置等 默认ASP.NET已经考虑到了 ...
- 从MVC框架看MVC架构的设计
尽管MVC早已不是什么新鲜话题了,但是从近些年一些优秀MVC框架的设计上,我们还是会发现MVC在架构设计上的一些新亮点.本文将对传统MVC架构中的一些弊病进行解读,了解一些优秀MVC框架是如何化解这些 ...
- Javascript之旅——第九站:吐槽function
说到funciton,也是我对js非常吐槽的一点,封装的让我眼瞎,马蛋的,哥只能大眼睁着去黑盒的使用,简直只有完完全全的听各类图书对 function的道听图说,完全没有做到一点点的眼见为实. 一:f ...
- python中set集合
一.set集合的特性 访问速度快 天生解决重复问题 二.set变量申明 s1 = set() s2 = set([1,2,3]) 备注:第二种方式在set类中直接传入一个序列. 三.set类中方法大全 ...
- 【JSP】JSP基础学习记录(一)—— 基础介绍以及3个编译指令
序: 从实现到现在一直是以.net为主,但偶尔也会参与一些其他语言的项目.最近需要对一个Java Web项目进行二次开发,一直没学习过JSP所以买了几本书自学试试.参考资料为<轻量级Java E ...
- HDFS
1.HDFS shell 1.0查看帮助 hadoop fs -help <cmd> 1.1上传 hadoop fs -put <linux上文件> <hdfs上的路径& ...
- FFMPEG ./configure 参数及意义
FFMPEG版本:2.6.2,编译环境:ubuntu 14.4. 不同版本的FFMPEG参数可能不同,可在FFMPEG目录下使用以下命令查看 ./configure --help --help pri ...
- 命令行选项解析函数(C语言):getopt()和getopt_long()
命令行选项解析函数(C语言):getopt()和getopt_long() 上午在看源码项目webbench时,刚开始就被一个似乎挺陌生函数getopt_long()给卡住了,说实话这函数没怎么见过, ...
- Java文件选择对话框(文件选择器JFileChooser)的使用:以一个文件加密器为例
文件加密器,操作过程肯定涉及到文件选择器的使用,所以这里以文件加密器为例.下例为我自己写的一个文件加密器,没什么特别的加密算法,只为演示文件选择器JFileChooser的使用. 加密器界面如图: 项 ...
- 白话debounce和throttle
遇到的问题 在开发过程中会遇到频率很高的事件或者连续的事件,如果不进行性能的优化,就可能会出现页面卡顿的现象,比如: 鼠标事件:mousemove(拖曳)/mouseover(划过)/mouseWhe ...