Android - AsyncTask 使用及原理
定义
AsyncTask 为android 封装好的轻量级异步任务类,可用来处理耗时任务 I/O 网络访问 等
使用
使用步骤:
1. 自定义StormAsyncTask extends AsyncTask
2. 根据需求重写方法,其中doInbackground 必须重写,否则报错
3. 调用AsyncTask.execute(参数)
//AsyncTask 为抽象类,所以在使用时,需继承其使用
public abstract class AsyncTask<Params, Progress, Result> {
//为抽象方法,必须重写
protected abstract Result doInBackground(Params... params);
private void useAsyncTask() {
StormAsyncTask mStormAs = new StormAsyncTask();
mStormAs.execute("stormxz");
mStormAs.cancel(true);
}
自定义AsyncTask
三个泛型:
第一个为开发传入数据的类型 / doInBackgroudn 参数类型
第二个为onProcess 的类型 / onProgressUpdate 参数类型 / doInbackground 的publishProgress 参数类型
第三个为result 的类型 / onPostExecute 参数类型 / doInbackground 的返回值类型
private class StormAsyncTask extends AsyncTask<String,Integer,Boolean>{
/**
* 准备操作
* main thread
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.d("stormxzAs", "onPreExecute ThreadName = " + Thread.currentThread().getName());
}
/**
* 后台处理
* asynctask thread 线程池
*/
@Override
protected Boolean doInBackground(String... params) {
Log.d("stormxzAs", "doInBackground ThreadName = " + Thread.currentThread().getName());
publishProgress(333);
return false;
}
/**
* 过程数据更新
* main thread
*/
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
Log.d("stormxzAs", "onProgressUpdate = " + values[0] + " ThreadName = " + Thread.currentThread().getName());
}
/**
* 结果返回
* main thread
*/
@Override
protected void onPostExecute(Boolean bool) {
super.onPostExecute(bool);
Log.d("stormxzAs", "onPostExecute = " + bool + " ThreadName = " + Thread.currentThread().getName());
}
/**
* 取消
* main thread
*/
@Override
protected void onCancelled() {
super.onCancelled();
}
}
运行流程:execute -> onPreExecute -> doInBackground -> publishProgress -> onProgressUpdate -> onPostExecute
D stormxzAs: onPreExecute
D stormxzAs: doInBackground
D stormxzAs: onProgressUpdate + 333
D stormxzAs: onPostExecute
注意:
1. 一个AsyncTask对象,只执行一次,否则会报一下错误
java.lang.IllegalStateException: Cannot execute task: the task is already running
2. 调用cancel 方法后,会调用onCancelled,不会调用onPostExecute,但是 doInBackground 中的方法是不会停止的,此时需要用isCancelled 中断doInBackground中的循环操作才行
BitmapFactory.decodeStream()的IO操作,调用cancle方法是无效的
3. 只有doInbackground 在 AsyncTask 的线程中,其他三个方法在main 线程中,可更新UI
原理
“2 个线程池” + Handler
此处为什么加引号呢,SerialExecutor仅仅是实现了Executor 接口,不能算作线程池
SerialExecutor :添加任务到队列中并触发第二个线程池
THREAD_POOL_EXECUTOR:真正执行任务的线程池
Handler:子线程与UI线程通信
标志位状态
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,
}
如果RUNNING 以及 FINISHED ,此时无法继续运行,保证了一个AsyncTask 对象只能运行一次execute
构造方法 初始化变量
创建Handler、WorkerRunnable、FutureTask对象
public AsyncTask(@Nullable Looper callbackLooper) {
//初始化Handler 用来子线程和UI 线程通信
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
//初始化具体任务行为 doInBackground
//重写call 方法,在FutureTask run方法中运行
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;
}
};
//初始化工作任务
//将WorkerRunnable 作为参数传入进去 最终会在此处调用THREAD_POOL_EXECUTOR.execute(mActive);
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
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
//执行AsyncTask 中的finish方法,实际就是调用的onPostExecute
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
//当在doInbackground中执行 publishProgress,此时调用上层的onProgressUpdate
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
private void finish(Result result) {
//判断是否取消,如果取消则返回结果到onCancelled方法;否则返回到onPostExecute
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
@MainThread
protected void onProgressUpdate(Progress... values) {
}
FutureTask
FutureTask 实际extends Runnable,在构造方法中传递参数WorkerRunnable
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable; //传递的workerrunnable
this.state = NEW; // ensure visibility of callable
}
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
//此处调用WorkerRunnable 中的call方法,从而调用到doInbackground
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
WorkerRunnable
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
内部静态抽象类 实现Callable接口,重写call方法
从上面方法中可以看出,mWorker对象的call方法是在FutureTask的run方法中执行
execute
程序执行入口
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
//判断当前AsyncTask能否运行,如果状态为正在运行或者已经运行结束,则返回;这就是为什么一个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)");
}
}
//标记正在运行状态
mStatus = Status.RUNNING;
//准备方法,执行继承类的onPreExecute 方法,所以是第一个执行
onPreExecute();
//赋值参数
mWorker.mParams = params;
//将任务放入线程池中
exec.execute(mFuture);
return this;
}
- 判断该AsyncTask是否可以运行
- 执行onPreExecute方法
- 将值赋值到mWorker中
- 将任务FutureTask 添加到线程池SerialExecutor 中
线程池
变量SERIAL_EXECUTOR 以及 THREAD_POOL_EXECUTOR static修饰,保证实例后的所有对象共享此线程池
(1) SerialExecutor 创建对象为静态变量,所以只要继承了AsyncTask,同一个进程中使用的都是同一个SerialExecutor 对象
SerialExecutor 中包含一个队列用来存储FutureTask
每次将队列的头部取出来,放入THREAD_POOL_EXECUTOR 线程池中运行,调用FutureTask的run 方法,从而调用到WorkerRunnable的call方法
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
//其实就是从队列中获取首端的FutureTask
Runnable mActive;
public synchronized void execute(final Runnable r) {
//将任务添加到ArrayDeque 队列中,这里只存,不运行runnable;在第二个线程池中运行
mTasks.offer(new Runnable() {
public void run() {
try {
//执行FutureTask中的run方法,调用call
r.run();
} finally {
//查询下一个任务
scheduleNext();
}
}
});
if (mActive == null) {
//查询下一个任务
scheduleNext();
}
}
//此线程池会执行FutureTask的run 方法
protected synchronized void scheduleNext() {
//获取队列首端数据,将其放入第二个线程池中
if ((mActive = mTasks.poll()) != null) {
//再执行run方法
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
通过synchronized 同步方法,保证了其有序同步运行
(2)创建线程池 THREAD_POOL_EXECUTOR 参数与CPU相关
初始化线程池
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;
}
AsyncTaskResult
可以看到在Handler中使用到
@SuppressWarnings({"RawUseOfParameterizedType"})
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task; //AsyncTask 本身
mData = data; //数据,result 或者 progress的数据
}
}
cancel
通过mCancel 来记录是否取消,并通知FutureTask 中断线程
public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}
调用cancel 方法后,会调用onCancelled,不会调用onPostExecute,但是 doInBackground 中的方法是不会停止的,此时需要用isCancelled 中断doInBackground中的循环操作才行
BitmapFactory.decodeStream()的IO操作,调用cancle方法是无效的
内存泄漏
在Android 开发中 代码稍加不规范,就会导致内存泄露。
我使用的工具为LeakCanary 来检测的
产生原因:
非静态内部类/匿名类会隐式的持有外部类的引用
如果AsyncTask写在 Activity 中,会持有Activity的引用,当Acitivity 销毁后,doInbackground 实际还是运行的,所以导致Activity 无法正确回收
解决方法:
1. 静态内部类
2. 使用弱引用来调用外部类方法或变量
3. doInBackgroud 中如果有循环操作 那么 onDestory 中需要进行cancel 同时与isCancelled(),阻止循环继续运行
private static class StormAsyncTask extends AsyncTask<String,Integer,Boolean>{
private WeakReference<MainActivity> mWeak ;
public StormAsyncTask(MainActivity activity) {
super();
mWeak = new WeakReference<MainActivity>(activity);
}
/**
* 准备操作
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
}
/**
* 后台处理
*/
@Override
protected Boolean doInBackground(String... params) {
for (int i = 0; i < 1000000; i++) {
if (isCancelled()) {
return false;
}
Log.d("stormll", "meile i = " + i);
}
publishProgress(333);
return false;
}
/**
* 过程数据更新
*/
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
/**
* 结果返回
*/
@Override
protected void onPostExecute(Boolean bool) {
super.onPostExecute(bool);
MainActivity activity = mWeak.get();
if (activity == null
|| activity.isFinishing()
|| activity.isDestroyed()) {
// activity没了,就结束可以了
Log.d("stormlls", "activity null");
return;
} else {
Log.d("stormlls", "activity not null");
}
// 继续更新ui
activity.mStopButton.setVisibility(View.VISIBLE);
}
@Override
protected void onCancelled() {
super.onCancelled();
}
}
看到新问题会继续补充~~
上一篇: commons-pool对象池实现原理及使用(二)
下一篇: AsyncTask使用及实现原理
推荐阅读
-
使用css创建三角形 使用CSS3创建3d四面体原理及代码(html5实践)
-
Android 7.0及以上使用OpenCL
-
Android Kotlin的使用及简单实例
-
Android下拉阻尼效果实现原理及简单实例
-
Android WebView的使用方法及与JS 相互调用
-
Android中使用AsyncTask实现下载文件动态更新进度条功能
-
Android HandlerThread的使用及原理详解
-
Android开发中使用Intent打开第三方应用及验证可用性的方法详解
-
彻底理解cookie,session,token的使用及原理
-
Android编程实现全局获取Context及使用Intent传递对象的方法详解