您的位置:首页 > 移动开发 > Android开发

深入学习Android异步任务-AsyncTask

2015-08-19 22:40 621 查看

一、AsyncTask的介绍与使用

AsyncTask可以让程序进行异步工作,它在一个线程中执行某些操作,之后将结果返回给UI线程。使用AsyncTask类时,需要继承AsyncTask类并实现doInBackground()回调方法。要更新UI界面,需要实现onPostExecute(),并从doInBackground()方法中获得结果,最后,可以在UI线程中调用execute()方法来执行操作,这样就可以安全的更新UI界面。以下贴了谷歌官方的代码,涉及到AsyncTask的简单使用:

public void onClick(View v) {
    new DownloadImageTask().execute("http://example.com/image.png");
}

private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
    /** The system calls this to perform work in a worker thread and
      * delivers it the parameters given to AsyncTask.execute() */
    protected Bitmap doInBackground(String... urls) {
        return loadImageFromNetwork(urls[0]);
    }

    /** The system calls this to perform work in the UI thread and delivers
      * the result from doInBackground() */
    protected void onPostExecute(Bitmap result) {
        mImageView.setImageBitmap(result);
    }
}


从上面的例子可以看出,AsyncTask的使用非常简单,不用我们去处理Handler和Thread。但是需要注意的是,AsyncTask适用于短时间的操作,最多几秒。如果想要线程长时间在后台运行的话,应该考虑使用Executor,ThreadPoolExecutor和FutureTask。另外,AsyncTask必须在UI线程中加载,AsyncTask的实例要在UI线程中创建,execute方法必须在UI线程中调用。

二、AsyncTask的结构组成

先一句话概括,三个泛型参数,四个方法。

三个参数:

Params, 任务执行传入参数的类型

Progress, 线程中用于进度更新的单位

Result, 线程执行完成后返回结果的类型

四个方法:

onPreExecute():在UI线程里面调用,在任务执行之前调用,主要做些初始化操作,如弹出ProgressDialog。

doInBackground():在后台线程中调用,处理耗时操作,在这个方法里面,可以调用publishProgress()传递执行的进度值到UI线程,最终在onProgressUpdate()使用。

onProgressUpdate():在UI线程中调用,用于更新进度条。

onPostExecute():在UI线程中调用,在任务执行完成后调用,将得到doInBackground处理得到的结果,用于更新UI。

三、取消任务

调用AsyncTask实例的boolean cancel(boolean mayInterruptIfRunning)方法,可以取消任务,会有下面几种情况:

1、如果任务已经完成或者任务已经被取消,那么取消任务失败,返回false。

2、如果任务还没有开始,那么取消成功,这个任务将不会再被执行。

3、如果任务已经在执行,如果ayInterruptIfRunning参数传的是true,那么任务将被中断,如果传的是false,那么任务将继续执行直到完成。调用了这个方法之后,当doInBackground()执行完成后,在UI线程中onPostExecute(Object)将不会再被调用,取而代之的是onCancelled(Object)。

if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;


如果想要尽快结束任务,那么可以考虑在doInBackground()中写一个循环,定期的检查isCancelled()返回的值,效果图如下:



四、任务的串行执行和并行执行

在Android 3.0之前,异步任务是允许多个线程并行执行的,Android 3.0开始,默认所有的任务放到一个线程中执行,官方的说法是为了避免并行执行引起的错误。

如果想要并行执行的话,需要设置AsyncTask中sDefaultExecutor为THREAD_POOL_EXECUTOR,这样就支持并行执行任务了,对比图:



/**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);


/** @hide */
    public static void setDefaultExecutor(Executor exec) {
        sDefaultExecutor = exec;
    }


五、任务的执行流程

1、在使用时需要得到异步任务的实例,在构造函数中,构造callable对象,重写call方法,构造FutureTask对象,重写done方法,该方法会在FutureTask执行完成后调用。

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


2、调用AsyncTask的execute方法 :

先执行onPreExcute方法,紧接着,调用线程池的execute方法,执行上面构造的FutureTask对象,线程开始执行。

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


线程执行开始执行,先调用doInBackground(mParams)方法,执行耗时任务,在执行过程中,可以调用

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


把执行的进度通过Handler传给onProgressUpdate。执行完成后,得到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方法里面,把得到的Result放到Message中,通过Handler,发送给主线程:

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


Handler处理消息时,会调用finish方法,调用重写的onPostExecute(Result result),整个过程结束。

    private void finish(Result result) {
if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: