美文网首页
AsyncTask 使用及分析

AsyncTask 使用及分析

作者: 安静的蓝孩子 | 来源:发表于2019-01-28 17:43 被阅读0次

AsyncTask

为了能更加方便的在子线程完成一些耗时操作,然后把结果带到 UI 线程更新页面,Google 使用 ThreadHandler 封装了 AsyncTask 类,方便开发者调用。

AsyncTask 是一个封装好的轻量级的异步类, 适用于轻量级(几秒内最好)的后台操作,如果运行时间比较长的,建议使用线程池 (ThreadPoolExecutor)。

接口

public abstract class AsyncTask<Params, Progress, Result> {
        // 运行的线程取决于调用execute()方法的线程
        // 在执行线程任务前(doInBackground())的调用,一般用来做一些初始化的操作
        // 可选择是否重写此方法
        @Override
        protected void onPreExecute() {
        }

        // 在子线程中执行
        // 接收输入的参数,执行任务中的耗时操作,最后返回线程任务执行的结果
        // 必须重写此方法
        @Override
        protected Result doInBackground(Params... params) {
            return null;
        }

        // 在主线程中执行
        // 回调显示线程任务执行的进度,需在doInBackground方法中调用publishProgress方法
        // 可选择是否重写此方法
        @Override
        protected void onProgressUpdate(Progress... progresses) {
        }

        // 在主线程中执行
        // 接收线程任务执行完后返回的结果
        // 必须复写
        @Override
        protected void onPostExecute(Result result) {
        }
    }

基本使用

AsyncTask 是一个抽象类,所以需要实现一个继承它的子类。

使用步骤:

  1. 继承 AsyncTask 实现一个子类
  2. 替换参数
    AsyncTask<Params, Progress, Result> 的三个参数替换成具体的参数类型,如:AsyncTask<String, Integer, String>
  3. 重写相应的方法
  4. 创建一个子类的对象
  5. 调用对象的 execute() 开始执行异步线程任务
// 自定义AsyncTask,static 是为了防止内存泄漏
private static class MyAsyncTask extends AsyncTask<String, Integer, String> {

        // 运行的线程取决于调用execute()方法的线程
        // 在执行线程任务前(doInBackground())的调用,一般用来做一些初始化的操作
        // 可选择是否重写此方法
        @Override
        protected void onPreExecute() {
            System.out.println("onPreExecute thread:" + Thread.currentThread());
        }

        // 在子线程中执行
        // 接收输入的参数,执行任务中的耗时操作,最后返回线程任务执行的结果
        // 必须重写此方法
        @Override
        protected String doInBackground(String... params) {
            System.out.println("doInBackground thread:" + Thread.currentThread());
            for (int i = 1; i <= 10; i ++) {
                publishProgress(i * 10);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return "result";
        }

        // 在主线程中执行
        // 回调显示线程任务执行的进度,需在doInBackground方法中调用publishProgress方法
        // 可选择是否重写此方法
        @Override
        protected void onProgressUpdate(Integer... progresses) {
            System.out.println("onProgressUpdate progress:" + progresses[0] + ", thread:" + Thread.currentThread());
        }

        // 在主线程中执行
        // 接收线程任务执行完后返回的结果
        // 必须复写
        @Override
        protected void onPostExecute(String result) {
            System.out.println("onPostExecute result:" + result + ", thread:" + Thread.currentThread());
        }

        // 将异步任务设置为取消时调用
        // 可选择是否重写此方法
        @Override
        protected void onCancelled() {
            System.out.println("onCancelled thread:" + Thread.currentThread());
        }
    }
    
private MyAsyncTask mAsyncTask;
mAsyncTask = new MyAsyncTask();

//调用execute方法开始执行
mAsyncTask.execute("MyAsyncTask");

Log输出

I/System.out: onPreExecute thread:Thread[MyHandlerThread,5,main]
I/System.out: doInBackground thread:Thread[AsyncTask #1,5,main]
I/System.out: onProgressUpdate progress:10, thread:Thread[main,5,main]
I/System.out: onProgressUpdate progress:20, thread:Thread[main,5,main]
I/System.out: onProgressUpdate progress:30, thread:Thread[main,5,main]
I/System.out: onProgressUpdate progress:40, thread:Thread[main,5,main]
I/System.out: onProgressUpdate progress:50, thread:Thread[main,5,main]
I/System.out: onProgressUpdate progress:60, thread:Thread[main,5,main]
I/System.out: onProgressUpdate progress:70, thread:Thread[main,5,main]
I/System.out: onProgressUpdate progress:80, thread:Thread[main,5,main]
I/System.out: onProgressUpdate progress:90, thread:Thread[main,5,main]
I/System.out: onProgressUpdate progress:100, thread:Thread[main,5,main]
I/System.out: onPostExecute result:result, thread:Thread[main,5,main]

源码分析

AsyncTask 是对 Handler 和线程池的封装,所以后台任务是通过线程池实现的,然后通过 Handler 把数据带到 UI 线程。

源码分析会结合上面的示例调用的顺序跟进。

1. 初始化流程

mAsyncTask = new MyAsyncTask();

在创建 AsyncTask 时,会调用 AsyncTask 构造方法。

public AsyncTask() {
        this((Looper) null);
    }
    
public AsyncTask(@Nullable Looper callbackLooper) {
        //由传入的callbackLooper为空,所以mHandler是用的getMainHandler()返回的Handler,是一个UI线程的Handler
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

        //初始化一个工作Runnable
        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;
            }
        };

        // 把工作 runnable 封装成 future
        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);
                }
            }
        };
    }

getMainHandler() 的具体实现:

private static Handler getMainHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                // 这里Looper指定使用的MainLooper 
                sHandler = new InternalHandler(Looper.getMainLooper());
            }
            return sHandler;
        }
    }
    
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
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }

由上面源码可以看到,初始化时,主要初始化了 Handler 对象,初始化了派生自 WorkRunnable 类的对象 mWorker,然后把 mWorker 封装成一个 Future 对象。

而线程池的初始化,这里使用的是一个静态块。

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;
    }
    
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    
    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);
            }
        }
    }

2. 执行任务

mAsyncTask.execute("MyAsyncTask");

在初始化工作完成后,调用 execute() 开始执行任务。

先看一下 execute() 代码:

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        // 这里的sDefaultExecutor就是线程池,params是我们传入的参数,如上面的 "MyAsyncTask"
        return executeOnExecutor(sDefaultExecutor, params);
    }

然后继续往下看一下 executeOnExecutor() 方法:

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        // 会先判断一下状态,如果正在执行任务或者任务已经执行完了,会抛出异常,这也是为什么execute()方法只能执行一次的原因
        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)");
            }
        }

        // 把任务的状态设置为 RUNNING
        mStatus = Status.RUNNING;

        // 后台任务开始前,先调用onPreExecute()方法
        onPreExecute();

        // 把传入的参数设置给初始化好的工作Runnable
        mWorker.mParams = params;
        // 把mFuture交给线程池执行任务
        exec.execute(mFuture);

        return this;
    }

exec.execute(mFuture); 之后,会调用到 mWorkerCall() 方法:

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 {
                    // 处理doInBackground() 执行后台任务得到的结果
                    postResult(result);
                }
                return result;
            }
        };

postResult(result) 方法:

private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        // getHandler() 得到的是初始化的 mHandler,这里直接把结果交给 Handler 处理
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

Handler 中消息的处理:

public void handleMessage(Message msg) {
            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
            // 这里的result.mTask就是我们的AsyncTask
            switch (msg.what) {
                // 任务执行完后,结果处理,进一步调用 finish() 方法
                case MESSAGE_POST_RESULT:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;
                // 调用 onProgressUpdate() 方法更新进度
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }

finish() 方法:

private void finish(Result result) {
        if (isCancelled()) {
            // 如果任务已经调用了 cancel 方法结束掉了,会调用 onCancelled 方法
            onCancelled(result);
        } else {
            // 如果任务正常执行完,调用 onPostExecute() 方法
            onPostExecute(result);
        }
        // 最后把状态设置为 FINISHED
        mStatus = Status.FINISHED;
    }

对于在 doInBackground() 中调用 publishProgress() 方法更新进度,可以看一下 AsyncTask 中的 publishProgress() 方法:

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

可见,调用 publishProgress() 后,也是通过 Handler 来处理的。

到此,整个调用过程就结束了。

怎么合理取消任务

AsyncTask 提供了 cancel() 方法来取消任务,但是从这个方法的注释中,可以看出几点问题:

  1. 调用了 cancel() 方法后,会尝试去关闭任务,但是不一定会成功的。
    如果任务还未开始执行,取消能成功。
    如果任务已经开始执行,能否取消成功取决于线程池。
  2. 调用 cancel() 后,doInBackground() 方法执行完后会调用 onCancelled() 方法,而不再调用 onPostExecute()。

为了能尽快尽可能地取消掉任务,应该:

  1. 尽可能早的调用 cancel() 方法。
  2. 在 doInBackground() 方法中尽可能多的去调用 sCancelled() 判断是否已经 cancel() 任务了,如果是,break 掉后面的执行,直接返回。

总结

  1. AsyncTask 不会随着 Activity 的销毁而销毁,直到 doInBackground() 方法执行完毕。
    所以,我们需要在销毁 Activity 前取消任务。

  2. 非静态内部类会持有外部类的引用,也就是在 Activity 中实现的非静态内部类 AsyncTask 会持有 Activity 的引用。如果 Activity 被销毁了,AsyncTask 的后台任务还在执行,它将继续在内存里保留这个引用,导致 Activity 无法被回收,引起内存泄露。
    所以,AsyncTask 应尽量声明为静态的内部类,防止内存泄漏。

相关文章

网友评论

      本文标题:AsyncTask 使用及分析

      本文链接:https://www.haomeiwen.com/subject/uvxzjqtx.html