深入学习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;
}
相关文章推荐
- Android学习笔记(十三)
- 配置使用Android数据库开源框架GreenDao
- Android学习0819<三>(Activity的操作)
- Android Api Demos登顶之路(三十九)Fragment-->show hide
- Android高手速成1--第一部分 个性化控件(View) - Aways.Online
- android ListView 及adapterView的使用
- mediarecorder学习,android4.0后mediarecorder start failed的原因
- Android 事件分发机制
- Android SDK Download List
- Android内存优化
- Android Resources
- 在Android上用AChartEngine轻松绘制图表
- Android-所有权限说明
- 文章标题
- Android SQLite的创建以及增删查改的实现
- mac下配置Qt for Android+iOS
- Android Studio Toast/Notification中文乱码解决办法
- Android ListView 的优化
- Android性能优化(一),总纲
- Android-拨打电话自动添加IP地址(BroadcastReceiver)