飞道的博客

Android面试09-异步任务AsyncTask

184人阅读  评论(0)

AsyncTask是啥?

在介绍AsyncTask之前,得先再回顾一下Handler。

众所周知,我们的ui操作需要在主线程,所以一般会先创建一个子线程,然后把耗时操作放到子线程,然后通过handler发送消息到主线程,通知主线程进行ui操作。

所以handler的步骤是:

1.主线程创建handler(接收消息)

2.创建线程(进行耗时操作)

3.子线程发送消息

4.主线程进行ui操作

而AsyncTask就像是对上述过程的一个封装。

Android提供了AsyncTask异步任务,AsyncTask对线程和handler进行了封装,使得我们可以直接在AsyncTask进行ui操作,就好像是在子线程进行ui操作一样

AsyncTask的步骤是:

1.创建子线程(进行耗时操作)

2.创建AsyncTask子类

3.在activity传入参数

AsyncTask怎么用?

在用AsyncTask之前,我们得先创建一个AsyncTask的子类继承AsyncTask(抽象类),然后在子类中 完成具体的业务逻辑操作。

AsyncTask抽象类指定了三个泛型。

public abstract class AsyncTask<Params, Progress, Result>{ ... }

Params:开始异步任务执行时传入的参数类型,–>doInBackground()方法中的参数类型;

Progress:异步任务执行过程中,返回下载进度值的类型,–>doInBackground中调用publishProgress()(ui操作)时传入的参数类型;

Result:异步任务执行完成后,返回的结果类型,–>doInBackground()方法的返回值类型;

AsyncTask的回调方法

(1)onPreExecute(): 在执行后台下载操作之前调用, 运行在主线程中

(2)doInBackground():核心方法,执行后台下载操作的方法,必须实现的一个方法, 运行在子线程中;
(3)onPostExecute():后台下载操作完成后调用,运行在主线程中

AsyncTask的基本生命周期过程为: onPreExecute() --> doInBackground() --> onPostExecute()

(4)onProgressUpdate():在下载操作 doInBackground()中调用publishProgress()时的回调方法,用于更新下载进度,运行在主线程中

因此,在需要更新进度值时, AsyncTask的基本生命周期过程为:onPreExecute() --> doInBackground() --> publishProgress() --> onProgressUpdate()–> onPostExecute()。

Mainactivity核心代码

  asyncTask = new MyAsyncTask(mProgressBar, mImageView);
        asyncTask.execute(url);

AsyncTask内部使用的是线程池,相当于里面有一个线程队列,执行一次execute时会将一个下载任务加入到线程队列,只有前一个任务完成了,下一个下载任务才会开始执行

为了达到我们想要的效果,我们自然想到把上一个任务给取消掉。的确,AsyncTask为我们提供了**cancel()**方法来取消一个任务的执行,但是要注意的是, cancel方法并没有能力真正去取消一个任务,其实只是设置这个任务的状态为取消状态,我们需要在doInBackground()下载中进行检测,一旦检测到该任务被用户取消了,立即停止doInBackground()方法的执行。

AsyncTask原理

在AsyncTask中需要handler的地方其实就是两个地方,一个是doInBackground()在运行过程中,需要更新进度值的时候;一个是doInBackground()运行完成后,需要回到到UI线程中的onPostExecute()方法的时候。

**对于一:**我们在doInBackground()中调用publicProgress()进行进度值的更新,因此在publicProgress()中肯定会有handler的身影,如下:

protected final void publishProgress(Progress... values) {
    if (!isCancelled()) {
        getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                new AsyncTaskResult<Progress>(this, values)).sendToTarget();
    }
}

对于二:其实就是一个异步任务执行完后后的返回处理,而FutureTask正是处理处理Runnable运行返回结果的。
在2.1部分的executeOnExecutor方法中第四步,我们在执行execute(mFuture),传入了一个mFuture,mFuture是在初始化AsyncTask的时候进行构建的,如下:

mFuture = new FutureTask<Result>(mWorker) {
    @Override
    protected void done() {
        try {
            postResultIfNotInvoked(get());//这里面通过handler往UI线程发送消息
        } 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);
        }
    }
};

小结:

AsyncTask主要是对异步任务handler的封装,在处理异步任务时,AsyncTask内部使用了两个线程池,

一个线程池 sDefaultExecutor是用来处理用户提交(执行AsyncTask的execute时)过来的异步任务,这个线程池中有一个Runnable异步任务队列 ArrayDeque mTasks ,把提交过来的异步任务放到这个队列中;

另一个线程池 THREAD_POOL_EXECUTOR, 用来真正执行异步任务的。在处理handler时,自定义了一个InternalHandler,在publicProgress()和doInBackground()运行完成后,会通过这个handler往UI线程发送Message。

AsyncTask在使用中的一个特殊情况

我们在使用AsyncTask的时候,一般会在onPreExecute()和onPostExecute()中进行UI的更新,比如等待图片的显示、进度条的显示…当我们一个Activity中正在使用AsyncTask进行文件的下载时,

如果此时屏幕发生了旋转,Activity会进行re-onCreate,又会创建一个AsyncTask进行文件的下载,这个正是我们前面将取消任务的时候谈到的第二个现象,我们只需要在onPause()中进行取消cancel()即可。但是这样仅仅是解决了发生等待的情况,因为Activity再次进入了onCreate()方法,还是会进行文件的下载,

为了解决这个问题,一种方案是通过判断onCreate(Bundle savedInstanceState)方法参数中的savedInstanceState== null?来判断是哪种情况,只有savedInstanceState== null时才去创建新的AsyncTask。

AsyncTask和Handler的比较

AsyncTask:
优点:AsyncTask是一个轻量级的异步任务处理类,轻量级体现在,使用方便、代码简洁上,而且整个异步任务的过程可以通过cancel()进行控制;
缺点:不适用于处理长时间的异步任务,一般这个异步任务的过程最好控制在几秒以内,如果是长时间的异步任务就需要考虑多线程的控制问题;当处理多个异步任务时,UI更新变得困难。
Handler:
优点:代码结构清晰,容易处理多个异步任务;
缺点:当有多个异步任务时,由于要配合Thread或Runnable,代码可能会稍显冗余。

总之,AsyncTask不失为一个非常好用的异步任务处理类,只要不是频繁对大量UI进行更新,可以考虑使用;而Handler在处理大量UI更新时可以考虑使用。


转载:https://blog.csdn.net/qq_46526828/article/details/116480232
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场