源码分析Android AsyncTask

Android UI操作是线程不安全的,若想在子线程红进行UI操作,需要借助Android提供的Handler。Android提供的AsyncTask其实是对Handler的封装,方便我们在子线程中更新UI元素。AsyncTask是一个泛型类,书写格式为: AsyncTask<Params, Progress, Result>。这三个参数的用途如下:

1. Params

这三个参数的用途如下:

1. Params

在执行AsyncTask时需要传入的参数,可用于在后台任务中使用。

2. Progress

后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。

3. Result

当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。

Android SDK中给出的一个AsyncTask用法如下:

 private class DownloadFilesTask extends AsyncTask(URL, Integer, Long) {
      protected Long doInBackground(URL... urls) {
          int count = urls.length;
          long totalSize = 0;
          for (int i = 0; i < count; i++) {
              totalSize += Downloader.downloadFile(urls[i]);
              publishProgress((int) ((i / (float) count)  100));
              // Escape early if cancel() is called
              if (isCancelled()) break;
          }
          return totalSize;
      }

      protected void onProgressUpdate(Integer... progress) {
          setProgressPercent(progress[0]);
      }

      protected void onPostExecute(Long result) {
          showDialog("Downloaded " + result + " bytes");
      }
  }

 new DownloadFilesTask().execute(url1, url2, url3);

AsyncTask是个抽象类,有四个方法需要被重写,这四个方法的的调用过程如下:

第1步. onPreExecute()方法会在后台任务开始执行之间调用,用于进行一些界面上的初始化操作。

第2步. doInBackground(Params...)方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务。任务一旦完成就可以通过return语句来将任务的执行结果进行返回。如果需要更新UI元素,比如说反馈当前任务的执行进度,可以调用publishProgress(Progress...)方法来完成。

第3步. 当在后台任务中调用了publishProgress(Progress...)方法后,onProgressUpdate(Progress...)方法就很快会被调用,方法中携带的参数就是在后台任务中传递过来的。在这个方法中可以对UI进行操作,利用参数中的数值就可以对界面元素进行相应的更新。

第4步. 当后台任务执行完毕并通过return语句进行返回时,onPostExecute(Result)很快会被调用。此处可以

进行UI操作。

AsyncTask的源码

当初使用AsyncTask的时候,一直不明白onProcessUpdate为何会定期被调用。后来在工作中要实现一个定时更新任务进度的功能,我们用的是一个Handler给自己发送消息来进行定时刷新。现在研究了一下AsyncTask的实现原理,发现它也是使用Handler给自己发送消息的原理来实现定时刷新。当我选用的是Android 4.4的源码,若大家能搞懂AsyncTask的实现原理,也能自己写一个简单的AsyncTask。

首先看看构造函数:注意,构造函数一定要在UI中调用。

   /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                return postResult(doInBackground(mParams));
            }
        };

        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 occured while executing doInBackground

()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
    }

这个函数初试化了两个变量:mWorker和mFuture。mWorker是一个Callable对象,mFuture是一个实现了Runnable和Future的对象。启动AsyncTask调用的是execute(Params)

    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

该方法调用了executeOnExecutor()方法,代码如下:

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

该方法先设置运行状态,然后调用onPreExecute,最后调用exec.execute(mFuture).传入的exec是sDefaultExecutor, sDefaultExecutor是一个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);
            }
        }
    }

当调用sDefaultExecutor.execute(runnable),该方法用一个ArrayDeque来保存runnable,runnable会在合适的时候被调用。第一次运行mActivity等于null了,于是会调用scheduleNext()方法。在这个方法中会从队列的头部取值,并赋值给mActive对象,然后调用THREAD_POOL_EXECUTOR去执行取出的取出的Runnable对象。这里使用了一个try finally代码块,并在finally中调用了scheduleNext()方法,每次当一个任务执行完毕后,下一个任务才会得到执行,SerialExecutor模仿的是单一线程池的效果,如果我们快速地启动了很多任务,同一时刻只会有一个线程正在执行,其余的均处于等待状态。

sDefaultExecutor.execute(Runnable)传入的对象是mFuture,mFuture是一个FutureTask对象,其构造函数如下所示:

 public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

由AsyncTask的构造函数可知,FutureTask中的callable是mWorkder对象。FutureTask的run()代码如下所示:

    public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    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);
        }
    }

因此,最终会调用mWorker的call()。mWorker的call()位于AsyncTask的构造函数中,大家可以发现其先调用doInBackgroud(Params),然后调用postResult().postResult(Result)的源代码如下:

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

sHandler是一个InternalHandler,代码如下:

 private static class InternalHandler extends Handler {
        @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;
            }
        }
    }

当传入的是一条MESSAGE_POST_RESULT消息,就会去执行AsyncTask.finish()方法,如果这是一条MESSAGE_POST_PROGRESS消息,就会去执行onProgressUpdate()方法。当我们在doInBackgroud(Params)中利用for循环来调用publishProgress(Progress... values),就会模拟出

定时调用onProgressUpdate(Progress... values)的效果。publishProgress(Progress... values)的源码如下:

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

它首先会判断线程是否已经结束,若没结束,则sHandler给自己发送一个消息,消息的类型为MESSAGE_POST_PROGRESS,sHandler.handleMessage(Message)则会调用onProgressUpdate(Progress... values)。

由上可知sDefaultExecutor先调用mFuture的run(), 而mFuture的run()又会调用mWorker的call()。当执行完一个任务后,mFuture的done()会被回调。done()会调用ppostResultIfNotInvoked(Result result),源码如下:

    private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }

postResult(Result)已经在前面有过讲解,在此不再赘述。

源码分析Android AsyncTask

时间: 2024-08-06 16:00:34

源码分析Android AsyncTask的相关文章

android源码分析 android toast使用详解 toast自定义

在安卓开发过程中,toast使我们经常使用的一个类,当我们需要向用户传达一些信息,但是不需要和用户交互时,该方式就是一种十分恰当的途径. 我们习惯了这样使用toast:Toast.makeText(Context context, String info, int duration).show();该方法是 系统为我们提供的一个方便的创建toast对象的静态方法,其内部依然是调用toast的相关方法完成.下面 就从其源码对该类的实现做一个分析 在toast类中,最重要的用于显示该toast的sh

Android源码分析之AsyncTask

AsyncTask相信从事Android开发的同学都不陌生,基本都应该用到了,和以前一样我们还是先来看看此类的summary.AsyncTask 可以确保更合理.容易的使用UI线程.这个类是设计用来执行一个后台操作然后将结果发布到UI线程,但却使你不必直接操作Thread 和Handler(其实内部已经为你封装好了而已).AsyncTask是围绕Thread和Handler而设计的一个Helper类,它的目标并不是提供 一个generic的Thread框架.AsyncTask的理想使用情况是针对

Android Launcher2源码分析

Android   Launcher2源码分析 Android源码程序程序中有一个应用程序入口,官方给出的中文翻译为"启动器".我们一下统称Launcher. Launcher源码分析,我们还是从AndroidManifest.xml开始: <application android:name="com.android.launcher2.LauncherApplication" android:label="@string/application_n

Android中AsyncTask基本用法与源码分析(API 23)

原文链接 http://sparkyuan.github.io/2016/03/23/AsyncTask源码剖析(API 23)/ 转载请注明出处 Android的UI是线程不安全的,想在子线程中更新UI就必须使用Android的异步操作机制,直接在主线程中更新UI会导致程序崩溃. Android的异步操作主要有两种,AsyncTask和Handler.AsyncTask是一个轻量的异步类,简单.可控.本文主要结合API 23的源码讲解一下AsyncTask到底是什么. 基本用法 声明:Andr

Android异步任务处理框架AsyncTask源码分析

[转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树] 引言 在平时项目开发中难免会遇到异步耗时的任务(比如最常见的网络请求).遇到这种问题,我们可以自己通过Handler+Message+Thread/ThreadPool来构造一个异步耗时任务框架.当你下次项目中又遇到一个网络请求,你又不得不重写异步耗时任务处理框架.出于避免开发者重复搬砖工作,Google工程师给开发者搭建了一个通用的异步耗时任务处理框架--AsyncTask. Asyn

Android应用AsyncTask处理机制详解及源码分析

[工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处,尊重分享成果] 1 背景 Android异步处理机制一直都是Android的一个核心,也是应用工程师面试的一个知识点.前面我们分析了Handler异步机制原理(不了解的可以阅读我的<Android异步消息处理机制详解及源码分析>文章),这里继续分析Android的另一个异步机制AsyncTask的原理. 当使用线程和Handler组合实现异步处理时,当每次执行耗时操作都创建一条新线程进行处理,性能开销会比

Android异步消息传递机制源码分析&amp;&amp;相关知识常被问的面试题

1.Android异步消息传递机制有以下两个方式:(异步消息传递来解决线程通信问题) handler 和 AsyncTask 2.handler官方解释的用途: 1).定时任务:通过handler.postDelay(Runnable r, time)来在指定时间执行msg. 2).线程间通信:在执行较为耗时操作的时候,在子线程中执行耗时任务,然后handler(主线程的)把执行的结果通过sendmessage的方式发送给UI线程去执行用于更新UI. 3.handler源码分析 一.在Activ

Android 源码解析之AsyncTask

AsyncTask相信大家都不陌生,它是为了简化异步请求.更新UI操作而诞生的.使用它不仅可以完成我们的网络耗时操作,而且还可以在完成耗时操作后直接的更新我们所需要的UI组件.这使得它在android开发中成为炙手可热的网络请求工具类. 而今天我们就以源码分析的形式来彻底的学习下它的实现过程. 首先,我们先看看AsyncTask的定义形式: public abstract class AsyncTask<Params, Progress, Result> { } 首先AsyncTask它是一个

Android IntentService 源码分析

IntentService简介: IntentService是一个通过Context.startService(Intent)启动可以处理异步请求的Service,使用时你只需要继承IntentService和重写其中的onHandleIntent(Intent)方法接收一个Intent对象,该服务会在异步任务完成时自动停止服务. 所有的请求的处理都在IntentService内部工作线程中完成,它们会顺序执行任务(但不会阻塞主线程的执行),某一时刻只能执行一个异步请求. IntnetServi