首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > Android >

小弟我的Android进阶之旅->Android中AsyncTask源码分析

2013-10-08 
我的Android进阶之旅------Android中AsyncTask源码分析在我的《我的Android进阶之旅------android异步加

我的Android进阶之旅------>Android中AsyncTask源码分析

在我的《我的Android进阶之旅------>android异步加载图片显示,并且对图片进行缓存实例》文章中,先后使用了Handler和AsyncTask两种方式实现异步任务机制。

下面先来看一段代码,这段代码是用来显示条目时候调用的方法。

查看一下AsyncTask的定义,如下所示:

    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;                case MESSAGE_POST_CANCEL:                    result.mTask.onCancelled();                    break;            }        }    }

通过上面的代码可以发现,在处理消息时,

遇到“MESSAGE_POST_RESULT”时,它会调用AsyncTask中的finish()方法;

遇到“MESSAGE_POST_PROGRESS”时,它会调用AsyncTask中的onProgressUpdate()方法;

遇到“MESSAGE_POST_CANCLE”时,它会调用AsyncTask中的onCancelled()方法。

现在我们来看看finish()方法,通过查看代码可以发现原来finish()方法是负责调用onPostExecute(Result result)方法显示结果并改变任务状态为FINISHED。

    private void finish(Result result) {        if (isCancelled()) result = null;        onPostExecute(result);        mStatus = Status.FINISHED;    }


==================================================================================================

  作者:欧阳鹏  欢迎转载,与人分享是进步的源泉!

  转载请保留原文地址:http://blog.csdn.net/ouyang_peng

==================================================================================================

附录:AsyncTask源代码:

/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package android.os;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;import java.util.concurrent.BlockingQueue;import java.util.concurrent.LinkedBlockingQueue;import java.util.concurrent.ThreadFactory;import java.util.concurrent.Callable;import java.util.concurrent.FutureTask;import java.util.concurrent.ExecutionException;import java.util.concurrent.TimeoutException;import java.util.concurrent.CancellationException;import java.util.concurrent.atomic.AtomicInteger;/** * <p>AsyncTask enables proper and easy use of the UI thread. This class allows to * perform background operations and publish results on the UI thread without * having to manipulate threads and/or handlers.</p> * * <p>An asynchronous task is defined by a computation that runs on a background thread and * whose result is published on the UI thread. An asynchronous task is defined by 3 generic * types, called <code>Params</code>, <code>Progress</code> and <code>Result</code>, * and 4 steps, called <code>begin</code>, <code>doInBackground</code>, * <code>processProgress</code> and <code>end</code>.</p> * * <h2>Usage</h2> * <p>AsyncTask must be subclassed to be used. The subclass will override at least * one method ({@link #doInBackground}), and most often will override a * second one ({@link #onPostExecute}.)</p> * * <p>Here is an example of subclassing:</p> * <pre class="prettyprint"> * 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)); *         } *         return totalSize; *     } * *     protected void onProgressUpdate(Integer... progress) { *         setProgressPercent(progress[0]); *     } * *     protected void onPostExecute(Long result) { *         showDialog("Downloaded " + result + " bytes"); *     } * } * </pre> * * <p>Once created, a task is executed very simply:</p> * <pre class="prettyprint"> * new DownloadFilesTask().execute(url1, url2, url3); * </pre> * * <h2>AsyncTask's generic types</h2> * <p>The three types used by an asynchronous task are the following:</p> * <ol> *     <li><code>Params</code>, the type of the parameters sent to the task upon *     execution.</li> *     <li><code>Progress</code>, the type of the progress units published during *     the background computation.</li> *     <li><code>Result</code>, the type of the result of the background *     computation.</li> * </ol> * <p>Not all types are always used by an asynchronous task. To mark a type as unused, * simply use the type {@link Void}:</p> * <pre> * private class MyTask extends AsyncTask<Void, Void, Void> { ... } * </pre> * * <h2>The 4 steps</h2> * <p>When an asynchronous task is executed, the task goes through 4 steps:</p> * <ol> *     <li>{@link #onPreExecute()}, invoked on the UI thread immediately after the task *     is executed. This step is normally used to setup the task, for instance by *     showing a progress bar in the user interface.</li> *     <li>{@link #doInBackground}, invoked on the background thread *     immediately after {@link #onPreExecute()} finishes executing. This step is used *     to perform background computation that can take a long time. The parameters *     of the asynchronous task are passed to this step. The result of the computation must *     be returned by this step and will be passed back to the last step. This step *     can also use {@link #publishProgress} to publish one or more units *     of progress. These values are published on the UI thread, in the *     {@link #onProgressUpdate} step.</li> *     <li>{@link #onProgressUpdate}, invoked on the UI thread after a *     call to {@link #publishProgress}. The timing of the execution is *     undefined. This method is used to display any form of progress in the user *     interface while the background computation is still executing. For instance, *     it can be used to animate a progress bar or show logs in a text field.</li> *     <li>{@link #onPostExecute}, invoked on the UI thread after the background *     computation finishes. The result of the background computation is passed to *     this step as a parameter.</li> * </ol> * * <h2>Threading rules</h2> * <p>There are a few threading rules that must be followed for this class to * work properly:</p> * <ul> *     <li>The task instance must be created on the UI thread.</li> *     <li>{@link #execute} must be invoked on the UI thread.</li> *     <li>Do not call {@link #onPreExecute()}, {@link #onPostExecute}, *     {@link #doInBackground}, {@link #onProgressUpdate} manually.</li> *     <li>The task can be executed only once (an exception will be thrown if *     a second execution is attempted.)</li> * </ul> */public abstract class AsyncTask<Params, Progress, Result> {    private static final String LOG_TAG = "AsyncTask";    private static final int CORE_POOL_SIZE = 5;    private static final int MAXIMUM_POOL_SIZE = 128;    private static final int KEEP_ALIVE = 10;    private static final BlockingQueue<Runnable> sWorkQueue =            new LinkedBlockingQueue<Runnable>(10);    private static final ThreadFactory sThreadFactory = new ThreadFactory() {        private final AtomicInteger mCount = new AtomicInteger(1);        public Thread newThread(Runnable r) {            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());        }    };    private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,            MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);    private static final int MESSAGE_POST_RESULT = 0x1;    private static final int MESSAGE_POST_PROGRESS = 0x2;    private static final int MESSAGE_POST_CANCEL = 0x3;    private static final InternalHandler sHandler = new InternalHandler();    private final WorkerRunnable<Params, Result> mWorker;    private final FutureTask<Result> mFuture;    private volatile Status mStatus = Status.PENDING;    /**     * Indicates the current status of the task. Each status will be set only once     * during the lifetime of a task.     */    public enum Status {        /**         * Indicates that the task has not been executed yet.         */        PENDING,        /**         * Indicates that the task is running.         */        RUNNING,        /**         * Indicates that {@link AsyncTask#onPostExecute} has finished.         */        FINISHED,    }    /**     * 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 {                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                return doInBackground(mParams);            }        };        mFuture = new FutureTask<Result>(mWorker) {            @Override            protected void done() {                Message message;                Result result = null;                try {                    result = 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) {                    message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,                            new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null));                    message.sendToTarget();                    return;                } catch (Throwable t) {                    throw new RuntimeException("An error occured while executing "                            + "doInBackground()", t);                }                message = sHandler.obtainMessage(MESSAGE_POST_RESULT,                        new AsyncTaskResult<Result>(AsyncTask.this, result));                message.sendToTarget();            }        };    }    /**     * Returns the current status of this task.     *     * @return The current status.     */    public final Status getStatus() {        return mStatus;    }    /**     * Override this method to perform a computation on a background thread. The     * specified parameters are the parameters passed to {@link #execute}     * by the caller of this task.     *     * This method can call {@link #publishProgress} to publish updates     * on the UI thread.     *     * @param params The parameters of the task.     *     * @return A result, defined by the subclass of this task.     *     * @see #onPreExecute()     * @see #onPostExecute     * @see #publishProgress     */    protected abstract Result doInBackground(Params... params);    /**     * Runs on the UI thread before {@link #doInBackground}.     *     * @see #onPostExecute     * @see #doInBackground     */    protected void onPreExecute() {    }    /**     * Runs on the UI thread after {@link #doInBackground}. The     * specified result is the value returned by {@link #doInBackground}     * or null if the task was cancelled or an exception occured.     *     * @param result The result of the operation computed by {@link #doInBackground}.     *     * @see #onPreExecute     * @see #doInBackground     */    @SuppressWarnings({"UnusedDeclaration"})    protected void onPostExecute(Result result) {    }    /**     * Runs on the UI thread after {@link #publishProgress} is invoked.     * The specified values are the values passed to {@link #publishProgress}.     *     * @param values The values indicating progress.     *     * @see #publishProgress     * @see #doInBackground     */    @SuppressWarnings({"UnusedDeclaration"})    protected void onProgressUpdate(Progress... values) {    }    /**     * Runs on the UI thread after {@link #cancel(boolean)} is invoked.     *     * @see #cancel(boolean)     * @see #isCancelled()     */    protected void onCancelled() {    }    /**     * Returns <tt>true</tt> if this task was cancelled before it completed     * normally.     *     * @return <tt>true</tt> if task was cancelled before it completed     *     * @see #cancel(boolean)     */    public final boolean isCancelled() {        return mFuture.isCancelled();    }    /**     * Attempts to cancel execution of this task.  This attempt will     * fail if the task has already completed, already been cancelled,     * or could not be cancelled for some other reason. If successful,     * and this task has not started when <tt>cancel</tt> is called,     * this task should never run.  If the task has already started,     * then the <tt>mayInterruptIfRunning</tt> parameter determines     * whether the thread executing this task should be interrupted in     * an attempt to stop the task.     *     * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this     *        task should be interrupted; otherwise, in-progress tasks are allowed     *        to complete.     *     * @return <tt>false</tt> if the task could not be cancelled,     *         typically because it has already completed normally;     *         <tt>true</tt> otherwise     *     * @see #isCancelled()     * @see #onCancelled()     */    public final boolean cancel(boolean mayInterruptIfRunning) {        return mFuture.cancel(mayInterruptIfRunning);    }    /**     * Waits if necessary for the computation to complete, and then     * retrieves its result.     *     * @return The computed result.     *     * @throws CancellationException If the computation was cancelled.     * @throws ExecutionException If the computation threw an exception.     * @throws InterruptedException If the current thread was interrupted     *         while waiting.     */    public final Result get() throws InterruptedException, ExecutionException {        return mFuture.get();    }    /**     * Waits if necessary for at most the given time for the computation     * to complete, and then retrieves its result.     *     * @param timeout Time to wait before cancelling the operation.     * @param unit The time unit for the timeout.     *     * @return The computed result.     *     * @throws CancellationException If the computation was cancelled.     * @throws ExecutionException If the computation threw an exception.     * @throws InterruptedException If the current thread was interrupted     *         while waiting.     * @throws TimeoutException If the wait timed out.     */    public final Result get(long timeout, TimeUnit unit) throws InterruptedException,            ExecutionException, TimeoutException {        return mFuture.get(timeout, unit);    }    /**     * Executes the task with the specified parameters. The task returns     * itself (this) so that the caller can keep a reference to it.     *     * This method must be invoked on the UI thread.     *     * @param params The parameters of the task.     *     * @return This instance of AsyncTask.     *     * @throws IllegalStateException If {@link #getStatus()} returns either     *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.     */    public final AsyncTask<Params, Progress, Result> execute(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;        sExecutor.execute(mFuture);        return this;    }    /**     * This method can be invoked from {@link #doInBackground} to     * publish updates on the UI thread while the background computation is     * still running. Each call to this method will trigger the execution of     * {@link #onProgressUpdate} on the UI thread.     *     * @param values The progress values to update the UI with.     *     * @see #onProgressUpdate     * @see #doInBackground     */    protected final void publishProgress(Progress... values) {        sHandler.obtainMessage(MESSAGE_POST_PROGRESS,                new AsyncTaskResult<Progress>(this, values)).sendToTarget();    }    private void finish(Result result) {        if (isCancelled()) result = null;        onPostExecute(result);        mStatus = Status.FINISHED;    }    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;                case MESSAGE_POST_CANCEL:                    result.mTask.onCancelled();                    break;            }        }    }    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {        Params[] mParams;    }    @SuppressWarnings({"RawUseOfParameterizedType"})    private static class AsyncTaskResult<Data> {        final AsyncTask mTask;        final Data[] mData;        AsyncTaskResult(AsyncTask task, Data... data) {            mTask = task;            mData = data;        }    }}

热点排行