【Android】AsyncTask原理应用及源码关键部分解析

来源:互联网 发布:测评软件 编辑:程序博客网 时间:2024/05/17 01:25

为了更加方便我们在子线程中更新UI元素,Android从1.5版本就引入了一个AsyncTask类,使用它就可以非常灵活方便地从子线程切换到UI线程。AsyncTask是android提供的轻量级的异步类,自定义的异步功能类可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的进度,最后反馈执行的结果给UI主线程

AsyncTask的简单使用示例

使用AsyncTask的时候经常需要覆写的四个方法:

  1. onPreExecute()
    这个方法会在后台任务开始执行之间调用,用于进行一些界面上的初始化操作,比如显示一个进度条对话框等。

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

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

  4. onPostExecute(Result)
    当后台任务执行完毕并通过return语句进行返回时,这个方法就很快会被调用。返回的数据会作为参数传递到此方法中,可以利用返回的数据来进行一些UI操作,比如说提醒任务执行的结果,以及关闭掉进度条对话框等

简单的AsyncTask的使用示例代码:

    /*     * 异步任务AsyncTask使用示例     */    public class MainActivity extends Activity {        private ProgressDialog pd;        private int downloadProgress = 0;        private static final String TAG = "AsyncTaskDemo";        @Override        protected void onCreate(Bundle savedInstanceState) {            super.onCreate(savedInstanceState);            setContentView(R.layout.activity_main);            pd = new ProgressDialog(this);            pd.setTitle(TAG);            // 开启一个后台下载任务并执行            new DownloadTask().execute();        }        /**         * 继承抽象类AsyncTask的一个下载示例类         * AsyncTask<Params, Progress, Result>         * Params:是执行后台任务所需要的参数,此处设置为空         * Progress:如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位,此处为整型         * Boolean:任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型,此处设置为布尔型         *         */        class DownloadTask extends AsyncTask<Void, Integer, Boolean> {            /*             * 做一些界面上的初始化操作,例如初始化view             * (non-Javadoc)             * @see android.os.AsyncTask#onPreExecute()             */            @Override            protected void onPreExecute() {                super.onPreExecute();                pd.show();            }            /*              * 执行任务的逻辑代码,该方法中的所有代码都会在子线程中运行,处理所有的耗时任务             * (non-Javadoc)             * @see android.os.AsyncTask#doInBackground(Params[])             */            @Override            protected Boolean doInBackground(Void... params) {                try {                    while (true) {                        int progress = doDownload();                        publishProgress(progress); // 从任务线程切换到UI线程更新执行进度                        if (progress >= 100)                            break;                    }                } catch (Exception e) {                    Log.e(TAG, "doInBackground Exception");                    return false;                }                return true;            }            /*             * 在这个方法中可以对UI进行操作,更新任务执行进度             * (non-Javadoc)             * @see android.os.AsyncTask#onProgressUpdate(Progress[])             */            @Override            protected void onProgressUpdate(Integer... values) {                super.onProgressUpdate(values);                pd.setMessage("当前下载进度:" + values[0] + "%");            }            /*             *  显示任务执行结果:成功或者失败             *  (non-Javadoc)             * @see android.os.AsyncTask#onPostExecute(java.lang.Object)             */            @Override            protected void onPostExecute(Boolean result) {                super.onPostExecute(result);                pd.dismiss();                if (result) {                    Toast.makeText(getApplicationContext(), "下载成功",                            Toast.LENGTH_LONG).show();                } else {                    Toast.makeText(getApplicationContext(), "下载失败",                            Toast.LENGTH_LONG).show();                }            }            /*             *  模拟下载功能的函数进度加1,睡眠0.05秒             */            private int doDownload() {                downloadProgress++;                try {                    Thread.sleep(50);                } catch (InterruptedException e) {                    Log.e(TAG, "doDownload Thread.sleep(1000) Exception");                    e.printStackTrace();                }                return downloadProgress;            }        }    }

AsyncTask源码分析

源码分析涉及到的文件和类

  1. 文件:AsyncTask.class
    FutureTask.class
  2. 类以及变量:AsyncTask
    FutureTask<V> implements RunnableFuture<V> mFuture
  3. 其中用到AsyncTask的内部类:
    WorkerRunnable<Params, Result> implements Callable<Result> mWorker SerialExecutor implements Executor sDefaultExecutor
    InternalHandler extends Handler

执行流程

先调用构造函数构造一个异步任务
构造函数中会初始化两个变量,一个是mWorker一个是mFuture,两个变量的类型如上分析。

接着执行execute()方法,execute方法会调用executeOnExecutor()方法。
executeOnExecutor()完成两个工作:
(1)执行onPreExecute()
(2)执行exec.execute(mFuture)。
其中doInbackground()和onProgressUpdate()都是在(2)的执行过程中执行的。具体分析见源码解释

最后在后台任务执行完成之后,执行return 返回之后会调用onPostExecute(Result)方法,该方法会发送异步消息更新UI

按执行流程进行的源码分析

类型原型:
public abstract class AsyncTask<Params, Progress, Result>
构造函数:

        // 初始化了两个变量,mWorker和mFuture,并在初始化mFuture的时候将mWorker作为参数传入        // mWorker是一个Callable对象,mFuture是一个FutureTask对象        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);                    }                }            };        }

mWorker的类型,该类型实现了public interface Callable<V> {}接口,在初始化mWorker的时候重载了该接口中唯一的call()方法

    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {            Params[] mParams;        }

在初始化mFuture的时候,重载了 FutureTask类的protected void done() { }方法

构造之后,会调用其execute()方法,该方法的源码如下

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

该方法仅仅执行了AsyncTask类的executeOnExecutor()方法,该方法的源码如下:

        @MainThread        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是前一段代码中executeOnExecutor()方法的第一个参数sDefaultExecutor(在源码的210行,4.3的源码),该参数类型为SerialExecutorexec.execute(mFuture)的参数是mFuturemFuture是一个FutureTask<Result>类型的变量。下面分别分析代码exec.execute(mFuture)的调用者和参数的源代码

调用者execSerialExecutor类型变量,该类型是AsyncTask的一个内部类,源码如下:

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

参数mFuture类型FutureTask<Result>的run方法如下:

    public void run() {            if (state != NEW ||                !U.compareAndSwapObject(this, RUNNER, 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);            }        }

run方法又会调用一个call()方法,而调用的call()的是mWorkermWorker是在FutureTask对象mFuture初始化的时候传递进去的(见AsyncTask的构造函数)。

mWorker的类型为实现了Callable接口的WorkRunnable内部类

    private static abstract class WorkerRunnable<Params, Result> implements   Callable<Result> {              Params[] mParams;          }  

FutureTask类型如下:

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

AsyncTask构造函数中,mFuture的初始化中,mWorker作为参数构造了一个FutureTask类型的mFuture

构造函数中的mWorker对象初始化代码如下,其中调用了doInBackground()方法。

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

此时的代码仍然是运行在子线程当中的,所以这也就是为什么我们可以在doInBackground()方法中去处理耗时的逻辑。接着将doInBackground()方法返回的结果传递给了postResult()方法并将其作为Result类型结果返回。

返回结果方法postResult()的源码如下:

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

postResult()中便将结果信息以异步消息的形式将消息

    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,                        new AsyncTaskResult<Result>(this, result));  

发送给Handler进行处理

更新进度方法publishProgress源码如下,就是在调用的时候发送一条MESSAGE_POST_PROGRESS消息:

    // 发出更新消息的方法publishProgress()        @WorkerThread        protected final void publishProgress(Progress... values) {            if (!isCancelled()) {                getHandler().obtainMessage(MESSAGE_POST_PROGRESS,                        new AsyncTaskResult<Progress>(this, values)).sendToTarget();            }        }

消息处理类InternalHandler根据消息类型分别执行finish()方法或者执行onProgressUpdate()方法。也就是示例代码中的更新进度或者下载完成关闭进度条的效果。该类是AsyncTask的内部类,实现源码如下:

    // 进行进度更新或者结束更新        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;                }            }        }

涉及的类型和方法比较多,所以叙述起来比较乱,还好大多数都是内部类,基本上也就仅仅是在AsyncTask源码文件中,对照这个流程看看源码注释再跑一跑示例代码就会有更加深入的理解。

1 0
原创粉丝点击