AsyncTask简单介绍:
AsyncTask,即异步任务,是Android给我们提供的一个处理异步任务的类.为了将Handler、静态Thread等封装为一个异步执行框架,方便调用。主要目的是为了“在其他线程中执行一个耗时操作,并随时报告执行进度给UI线程,执行完成后将结果报告给UI线程”。通过此类,可以实现UI线程和后台线程进行通讯,后台线程执行异步任务,并把结果返回给UI线程.。
我们知道,Android中只有主线程才能进行对UI的更新操作,其他线程是不能直接操作UI的。但总不能把所有的任务都放在主线程中进行实现,所以就出现了AsyncTask。
在AsyncTask中可以执行一些耗时操作,网络请求,可以很好的避免ANR错误。反之全部放到主线程去执行,就可能会造成后面任务的阻塞。当阻塞时间太长的时候,就会抛出Application Not Responsed(ANR)错误.所以我们需要将这些耗时操作放在非主线程中去执行.这样既避免了Android的单线程模型,又避免了ANR.
源码详细:https://blog.csdn.net/m0_37700275/article/details/83546140
AsyncTask具体介绍:
继承AsyncTask的类指定了三个泛型参数:
- Params:启动任务时输入的参数类型.
- Progress:后台任务执行中返回进度值的类型.
- Result:后台任务执行完成后返回结果的类型.
AsyncTask中有三个方法:
- doInBackground:必须重写,异步执行后台线程要完成的任务,耗时操作将在此方法中完成.
- onPreExecute:执行后台耗时操作前被调用,通常用于进行初始化操作.
- onPostExecute:当doInBackground方法完成后,系统将自动调用此方法,并将doInBackground方法返回的值传入此方法.通过此方法进行UI的更新.
- onProgressUpdate:当在doInBackground方法中调用publishProgress方法更新任务执行进度后,将调用此方法.通过此方法我们可以知晓任务的完成进度.
class MyAsyncTask extends AsyncTask<Integer, Integer, Integer> {
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.i(TAG, "onPreExecute...(开始执行后台任务之前)");
}
@Override
protected void onPostExecute(Integer i) {
super.onPostExecute(i);
Log.i("TAG", "onPostExecute...(开始执行后台任务之后)");
}
@Override
protected Integer doInBackground(Integer... params) {
Log.i(TAG, "doInBackground...(开始执行后台任务)");
return 0;
}
}
开始执行异步方法:
new MyAsyncTask().execute();
AsyncTask机制原理:
我们先从他Execute方法,其中有一个ExecuteOnExcuteor的方法,通过Status.Pending来判断当前的任务状态。如果为正在执行这个任务,或者是已经完成任务的情况下,就会出现异常,只有是未完成的情况下,开始执行OnPerExecute()的方法。以及把我们的params赋值给mworker.mparams(),并执行execute方法,把mFurture方法传过去!
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;
}
AsyncTask中有两个线程池,和一个Handler,其中有一个SerialExector()的方法是用来任务排队,THREAD_POLL_EXECUTOR的方法是用来真正的执行任务!
那么接下来就用SerialExector()的方法来看看其中是如何排队的?那么这里用了锁来限制,首先它实现了ExeCutor的接口,实现了接口中的Call()方法。
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;
}
};
接下来在SerialExector类中实现runnable方法,用一个r.run(),间接的调用了Call方法中的DoInBackground(),再调用其中的oScheduleNext()方法,判断当前任务是否为空,不为空则执行THREAD_POLL_EXECUTOR方法,处理任务!
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
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);
}
}
}
处理完后,就要用到Handler来将线程环境转换为主线程也就是要执行onPostExecute()方法
AsyncTask和Handler对比:
1.AsyncTask:使用的优点: 简单,快捷、过程可控.
- 使用的缺点: 在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.
- 使用AsyncTask类,以下是几条必须遵守的准则:
- Task的实例必须在UI thread中创建;
- execute方法必须在UI thread中调用;
- 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法;
- 该task只能被执行一次,否则多次调用时将会出现异常;
- AsyncTask注意事项:
- 注意内存泄漏
- 生命周期:AsyncTask生命周期不随着Activity,必须把它在onDestory()方法中finish掉,才会销毁掉。
- 结果丢失:当发生屏幕旋转等问题,会重新构造Activity,所以AsyncTask持有的也是之前Activity的引用,所以引用无效,只能用AsyncTask中的onPostExcute()方法更新界面就不会失效了,数据也就不会对视
2.Handler:
源码了解:https://blog.csdn.net/LoverLeslie/article/details/85267367
- 使用的优点:结构清晰,功能定义明确、 对于多个后台任务时,简单,清晰
- 使用的缺点:在单个后台异步处理时,显得代码过多,结构过于复杂(相对性)
AsyncTask和Handler内存泄漏处理方法:
1.AsyncTask:
解决办法:将AsyncTask设置为静态内部类、在Activity的onDestory()方法中finish掉 (AsyncTask.cancle() )、将内部改为持有外部类的弱引用。
2.Handler:
原因:handler如果是是非静态内部类 ,那么就会引用外部类的匿名引用,导致Activity无法释放
解决办法:将Handler设置为静态内部类、在Activity的onDestory()方法中remove掉( handler.removeCallback() )、将内部改为持有外部类的弱引用。