1、简介
是android为开发者封装好的,异步轻量级任务执行框架;
如果你因为可能的内存泄漏问题而不使用,我想说大可不必,自己封装基本并比不上系统的;再者说,如果使用了线程都可能造成内存泄漏问题,这个是由gc清除对象时处理造成的,使用线程的场景到处都是
从代码角度来看其实现,内部是使用了线程池+FutureTask+Handle来实现的;所以我们就来看看它对线程池、FutureTask使用的处理
2、线程池使用
2.1 SERIAL_EXECUTOR线程池
公有静态常量,就是顺序执行线程池对象;其顺序执行阈值为Runnable mActive,其并不是线程安全的,所以,只能保证单线程中顺序执行,多线程也是可能并发执行的;mActive == null条件表示队列中没有可执行的任务
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);
}
}
}
}
线程执行流程:
- 第一次执行任务时,直接调用THREAD_POOL_EXECUTOR线程池直接执行
- 非首次执行任务时,会查看已经执行过任务从队列中取出任务是否为空,来决定是否执行;
也就是说,队列中任务执行,可能是上次任务执行完毕后继续执行,或者任务队列为空直接执行
2.2 THREAD_POOL_EXECUTOR线程池
公有静态常量,特点:
- 单核心,多个可缓存线程的线程池;可用线程最大数为20
- 可存活时间3s
- 任务队列使用容器为0的SynchronousQueue队列
- 线程名字打上AsyncTask标签
- 任务拒绝策略由sBackupExecutor来执行;sBackupExecutor是仅有5个核心线程的线程池,队列个数整数最大,核心线程可销毁,线程仍然线程名字打上AsyncTask标签
private static final int CORE_POOL_SIZE = 1;
private static final int MAXIMUM_POOL_SIZE = 20;
private static final int BACKUP_POOL_SIZE = 5;
private static final int KEEP_ALIVE_SECONDS = 3;
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 RejectedExecutionHandler sRunOnSerialPolicy =
new RejectedExecutionHandler() {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
android.util.Log.w(LOG_TAG, "Exceeded ThreadPoolExecutor pool size");
synchronized (this) {
if (sBackupExecutor == null) {
sBackupExecutorQueue = new LinkedBlockingQueue<Runnable>();
sBackupExecutor = new ThreadPoolExecutor(
BACKUP_POOL_SIZE, BACKUP_POOL_SIZE, KEEP_ALIVE_SECONDS,
TimeUnit.SECONDS, sBackupExecutorQueue, sThreadFactory);
sBackupExecutor.allowCoreThreadTimeOut(true);
}
}
sBackupExecutor.execute(r);
}
};
public static final Executor THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), sThreadFactory);
threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
直白点说
- 如果一直在主线程使用,那么任务是一个顺序执行的
- 顺序执行线程池使用代理的使用,由一个由1个核心,19个可缓存,队列容量为0的线程池代理
- 如果发生并发的话,最多同时执行任务25个,多余的任务在拒绝策略中处理
- 拒绝策略由5个存活时间有限的核心线程,且队列无界的线程池来执行;基本不会抛弃任务
3、源码分析
介绍一些主要方法和流程,其余的方法,如果有兴趣可以执行了解
3.1 构造器
public AsyncTask() {
this((Looper) null);
}
public AsyncTask(@Nullable Handler handler) {
this(handler != null ? handler.getLooper() : null);
}
public AsyncTask(@Nullable Looper callbackLooper) {
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);
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);
}
}
};
}
- 消息传播handler对象,默认是主handler,也可以自由传入;自由传入无视了下面消息
private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
- mWorker 是线程具体执行,执行doInBackground(mParams),并用postResult发布结果
- mFuture 中done方法,无论线程执行的什么样,都会调用,确保调用postResult发布结果
postResult方法
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
消息 what = MESSAGE_POST_RESULT,obj为AsyncTaskResult对象,其包含AsynTask当前对象和doInBackground(mParams)执行结果
3.2 主线程消息处理
主线程消息,是内部类InternalHandler对象
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:
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
- MESSAGE_POST_RESULT消息:任务执行完毕发送此消息
- MESSAGE_POST_PROGRESS消息:publishProgress方法被调用时发出此消息
消息具体执行动作
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
- MESSAGE_POST_RESULT消息:如果用户取消了任务,回调onCancelled,否则回调onPostExecute方法
- MESSAGE_POST_PROGRESS消息:回调onProgressUpdate方法,空方法,需要继承实现
3.3 执行任务
可以分为三种情况:使用默认线程池(顺序执行)执行异步任务、自定义线程池执行异步任务、默认线程池执行任何Runnable任务;三种任务中,我们经常使用默认线程池执行异步任务;
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
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();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
public static void execute(Runnable runnable) {
sDefaultExecutor.execute(runnable);
}
异步任务流程:
- 判断状态,如果已经运行或者结束,则抛出异常;状态有三种,由内部类Status定义:未运行,正在运行,运行结束
public enum Status {
PENDING,
RUNNING,
FINISHED,
}
- 首先执行onPreExecute方法,空方法,可以自定义实现,在调用线程中执行
- 然后才使用线程池执行任务
4、原理总结
- 这个是特意为主线程设计的轻量级、异步执行主线程获取结果的框架;为何这么说,最简单的原因,非主线程不能获取消息,不能处理进度信息,其结果获取也得通过get方法获取,这和FutureTask使用的没有太大区别
- 异步中涉及的一些方法执行:这些都是空实现,如有需要需要自实现
- onPreExecute 执行任务前方法,在调用方法的线程中执行,并不一定是主线程
- doInBackground 线程池中执行方法,异步执行任务
- onPostExecute 结果回传方法;只有构造器传入handler不为主looper的handler对象,才会处理
- onPreExecute 执行取消方法;只有构造器传入handler不为主looper的handler对象,才会处理
- onProgressUpdate 需要用户主动在异步任务执行中,也就是doInBackground方法中,调用publishProgress,才会回调;只有构造器传入handler不为主looper的handler对象,才会处理
- 由于在主线程获取回调结果,而用户在主线程并不一定停留很久,所以,不适合执行很耗时的任务,不然,任务执行就没有意义了;如果这是你需要的意义也可以这么用
- 由于gc的原因,AsyncTask对象被线程池持有,那么AsyncTask持有的对象也不可被回收,除非任务运行完毕;所以实现AsyncTask的类不适合作为android 四大组件的内部类
- AsyncTask执行异步任务只能执行一次
- AsyncTask,中还有一些其它辅助小功能,比如获取主线程handler,直接执行线程
- AsyncTask中的线程池是进程中公有的,一个界面多个异步肯定会相互阻塞的
技术变化都很快,但基础技术、理论知识永远都是那些;作者希望在余后的生活中,对常用技术点进行基础知识分享;如果你觉得文章写的不错,请给与关注和点赞;如果文章存在错误,也请多多指教!