AsyncTask 有助于应用 UI 线程。这个类能让你不被动应用多线程或 Handler,在子线程种执行耗时工作,并在UI线程公布后果。

AsyncTask 是一个在不须要开发者间接操作多线程和 Handler 的状况下的帮忙类,实用于短时间的操作(最多几秒)。 如需长时间的线程操作,倡议应用多线程包 java.util.concurrent 中的性能,比方线程池。

假如咱们有个须要在后盾线程中运行的异步计算工作,并且后果须要更新 ui。 那咱们须要关注3个范型参数:Params, Progress 和 Result
再关注4个步骤办法:
onPreExecutedoInBackgroundonProgressUpdate 和 onPostExecute

属性介绍

应用 AsyncTask 之前,咱们先看一下它的三个类型。

AsyncTask<Params, Progress, Result>
属性形容
Params 执行工作前,传入的参数的类型
Progress 后盾线程执行的时候,用来示意进度的类型
Result 示意执行后果的类型

这 3 个类型须要开发者本人指定。比方指定 String, Integer 等。这 3 个类型在前面的办法里会用到。

不必的泛型能够用Void示意。例如

private class MyTask extends AsyncTask<Void, Void, Void> { ... }

办法介绍

要应用 AsyncTask ,必须新建一个类来继承它,并且重写 doInBackground 办法。通常也会重写 onPostExecute 办法。 执行异步工作的时候,咱们次要关怀上面这4个办法。

办法形容
onPreExecute() 执行工作前在ui线程调用。通用用来设置工作,比方在界面上显示一个进度条。
Result doInBackground(Params... params) onPreExecute() 完结后立刻调用这个办法。耗时的异步工作就在这里操作。执行工作时传入的参数会被传到这里。异步工作的两头后果在这里能够用 publishProgress 发送到主线程。
onProgressUpdate(Progress... values) 在 ui 线程中执行。后台任务还在进行的时候,这里负责解决进度信息。比方在这显示进度条动画,批改文字显示等。
onPostExecute(Result result) 后台任务完结了调这个办法。它在 ui 线程执行。最初的后果会传到这。

AsyncTask 的三种状态

每个状态在一个工作的生命周期中只会被执行一次。

状态形容
PENDING期待(还没有开始执行工作)
RUNNING执行中
FINSHED实现

用法示例

虚构一个计算工作

/** * 虚构的计算工作 */private class CalculationTask extends AsyncTask<Float, Integer, Float> {    protected Float doInBackground(Float... inputs) {        Log.d(TAG, "doInBackground thread ID = " + Thread.currentThread().getId());        long step = 0;        float result = 0;        for (float f : inputs) {            // 假如这里有一些耗时的操作            result += f;        }        while (step < 5) {            result += step;            step++;            publishProgress((int) step);        }        return result;    }    protected void onProgressUpdate(Integer... progress) {        Log.d(TAG, "onProgressUpdate thread ID = " + Thread.currentThread().getId());        Log.d(TAG, "onProgressUpdate: " + progress[0]);    }    protected void onPostExecute(Float result) {        Log.d(TAG, "onPostExecute thread ID = " + Thread.currentThread().getId());        Log.d(TAG, "工作执行结束");    }}// 执行工作new CalculationTask().execute(1.2f, 2.3f, 6.3f);

勾销工作

调用 cancel(boolean) 可随时勾销工作。勾销工作后 isCancelled() 会返回true。

调用这个办法后,后台任务 doInBackground(Object[]) 执行结束后会调用 onCancelled(Object) 而不再是 onPostExecute(Object)。 为保障工作能被及时地勾销,在 doInBackground(Object[]) 中应该常常查看 isCancelled() 返回值

线程规定 Threading rules

  • 异步工作必须从UI线程启动
  • 必须在UI线程实例化AsyncTask类
  • 必须在UI线程调用execute(Params...)
  • 不要手动调用onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...)
  • 同一个异步工作实例只能被执行一次。反复执行同一个异步工作实例会抛出异样(IllegalStateException)。

AsyncTask 相干面试题

1. AsyncTask 是什么?能解决什么问题

2. 谈谈 AsyncTask 的三个泛型参数作⽤

3. 说说AsyncTask的原理

结构⽅法中创立了⼀个 WorkRunnable 和⼀个 FutureTask 对象,

在 WorkRunnable的Call ⽅法中调⽤ doInBackground ⽅法,并获取 Result 返回值,而后返回调⽤postResult ⽅法的返回值,创立 FutureTask 时传⼊了 WorkRunnable 对象。

public AsyncTask() {    mWorker = new WorkerRunnable<Params, Result>() {        public Result call() throws Exception {            mTaskInvoked.set(true);            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);            //noinspection unchecked            Result result = doInBackground(mParams);            Binder.flushPendingCommands();            return postResult(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);            }        }    };}

postResult ⽅法

getHandler⽅法获取⾃带Handler对象,来获取Message

private Result postResult(Result result) {     @SuppressWarnings("unchecked")     Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, newAsyncTaskResult<Result>(this, result));     message.sendToTarget();     return result;}

这个外部⾃带InternalHandler结构⽅法中传⼊getMainLooper()返回值,即主线程Looper,

而后在handlerMessage⾥⾯针对msg.what别离执⾏了finish和onProgressUpdate⽅法,其中finish⽅法令是调⽤onCancelled或onPostExecute⽅法

private static final InternalHandler sHandler = new InternalHandler();private static class InternalHandler extends Handler {     public InternalHandler() {          super(Looper.getMainLooper());     }     @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;               }          }}
private void finish(Result result) {     if (isCancelled()) {          onCancelled(result);     } else {          onPostExecute(result);     }     mStatus = Status.FINISHED; }

看看 AsyncTask 的 execute ⽅法,返回了 executeOnExecutor 的⽅法,并传⼊sDefaultExecutor 和 params 为参数,params 即 AsyncTask 的 doInBackground中传⼊的 params ,

⽽ sDefaultExecutor 是默认的串⾏执⾏器(线程池),⼀个SerialExecutor 再看看executeOnExecutor ⽅法,先判断了工作状态,如果是 RUNNING 或FINISHED,则会抛出异样,

而后会把以后状态从 PENDING 改为 RUNNING,把⼊参 params 传到WorkRunnable 对象中,再调⽤传⼊的 sDefaultExecutor 的 execute ⽅法,传⼊mFuture 为参数

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executorexec, 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; }

execute ⽅法中调⽤ mTasks 的 offer ⽅法增加⼀个工作到缓存队列中,在 run ⽅法中就调⽤了前⾯传⼊的 mFuture 的 run ⽅法,

而后执⾏ THREAD_POOL_EXECUTOR 的 execute ⽅法,工作的理论执⾏就在这,THREAD_POOL_EXECUTOR 就是⼀个线程池

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);          }      }}

4. 你感觉AsyncTask有不⾜之处吗?

AsyncTask 使⽤起来⽐较轻量,然而⾃身也存在⼀些问题。

次要体现在:

  • cancel ⽅法实现不是很好。如果你调⽤了 AsyncTask 的 cancel(false) ⽅法, doInBackground() 依然会执⾏到⽅法完结,只是不会去调⽤ onPostExecute() ⽅法,然而实际上也是让程序执⾏了没有意义的操作。如果调⽤cancel(true),mayInterruptIfRunning 设置为 true,会使工作尽早完结,然而如果 doInBackground() 有不可被打断的⽅法,就会生效,⽐如 BitmapFactory.decodeStream() 操作。
  • 内存泄露,在 Activity 中使⽤⾮动态匿名外部类 AsyncTask 类,因为 Java 外部类的特点,外部类持有外部类引⽤,⽽因为 AsyncTask ⽣命周期可能⽐ Activity 的,当 Activity 销毁时,AsyncTask 还在执⾏,因为AsyncTask 持有 Activity 的引⽤,导致 Activity 对象⽆法回收,进⽽产⽣内存泄露。
  • 后果失落,当屏幕旋转等造成 Activity 新创建时 AsyncTask 数据失落的问题。当 Actviity 销毁并创立新的收,还在运⾏的 AsyncTask 会持有⼀个 Activity 的⾮法引⽤,即之前 Activity 的实例,导致onPostExecute() ⽅法⽆效。
  • 串⾏,并⾏多版本不⼀致.1.6之前为串⾏,1.6-2.3为并⾏,3.0之后⼜改为串⾏,然而能够通过executeOnExecutor() 实现并⾏解决

Android零根底入门教程视频参考