AsyncTask 源码分析
来源:互联网 发布:安卓软件交易平台 编辑:程序博客网 时间:2024/06/05 00:27
AsyncTask
异步网络请求。内部封装了Thread和handler,将任务放到子线程执行,在获得结果后通过handler将结果发送给主线程,更新UI。
内部使用了线程池。在比较早的版本(1.6版)中,使用并行执行,考虑到并行执行可能引发的问题,3.0以后改为默认使用串行执行,即调用execute执行。若要并行执行需要调用.ExecuteOnExecutor()方法执行。
主要注意的是,不能用来执行特别耗时的任务,一般最长执行时间最多是几毫秒。耗时的任务,推荐用Executor、ThreadPoolExecutor、FutureTask来实现(官方文档)
使用方式
创建子类,一般需要实现这四个方法:
onPreExecute:在doInBackground之前执行,运行在主线程,一般用来更新进度条及做一些初始化;
doInBackground:在子线程执行耗时任务,执行完成后会通过handler将消息发送给主线程;
onProgressUpdate:当调用了publishProgress此方法才会被调用,用来获取任务执行进度,以更新进度条;
onPostExecute:doInBackground执行完,会执行此方法。在主线程执行,可用来更新UI。
官方实例:
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)); * 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三种泛型:Params, Progress, Result 其中,Params是参数类型,Progress是进度类型, Result是结果类型 如果不使用,对应可用void代替。public abstract class AsyncTask<Params, Progress, Result> { private static final String LOG_TAG = "AsyncTask"; private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); //核心线程数量为cpu核心数+1 private static final int CORE_POOL_SIZE = CPU_COUNT + 1; //最大线程数为2倍cpu核心数+1 private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; //超时时间1s private static final int KEEP_ALIVE = 1; //使用ThreadFactory来创建线程 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 BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(128);//创建一个并行执行的线程池对象 public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);//创建一个串行执行的线程池对象 public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); private static final int MESSAGE_POST_RESULT = 0x1; private static final int MESSAGE_POST_PROGRESS = 0x2;//默认串行执行 private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; //定义一个静态handler用于和主线程通信 private static InternalHandler sHandler; private final WorkerRunnable<Params, Result> mWorker; private final FutureTask<Result> mFuture; private volatile Status mStatus = Status.PENDING; private final AtomicBoolean mCancelled = new AtomicBoolean(); private final AtomicBoolean mTaskInvoked = new AtomicBoolean();//串行执行 内部调用 THREAD_POOL_EXECUTOR.execute方法 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); } } }//指定任务的当前状态,在每个任务的生命周期内只会执行一次 public enum Status { /** * 标识任务还没执行时的状态 */ PENDING, /** * 标识任务正在执行时的状态 */ RUNNING, /** * 标识任务执行完成的状态 */ FINISHED, } private static Handler getHandler() { synchronized (AsyncTask.class) { if (sHandler == null) { sHandler = new InternalHandler(); } return sHandler; } } /** @hide */ public static void setDefaultExecutor(Executor exec) { sDefaultExecutor = exec; } /** * 构造 asyncTask的实例必须在主线程创建,且只能执行一次,再次调用会报异常 */ 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); } } }; }
已上代码,定义了一个串行执行的线程池和一个并行执行的线程池。并定义了线程池的细节。以及AsyncTask实例的要求。
接下来继续看下面代码:
//将结果封住成Result对象,通过handler发送给主线程
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result;}
public final Status getStatus() {
return mStatus;
}
//在后台执行 需要实现该方法
protected abstract Result doInBackground(Params… params);
//在后台执行 在doInBackground之前会被调用,可以用来初始化进度条等
protected void onPreExecute() {
}
//在主线程执行 ,在doInBackground之后会被调用,如果中间调用了cancel()则此方法不会被执行,结果会丢失
protected void onPostExecute(Result result) {
}
//在主线程执行 用于更新进度条 当调用了publishProgress会执行此方法
protected void onProgressUpdate(Progress… values) {}
//当调用cancel方法时会调用onCancelled,则onPostExecutor则不会执行
@MainThread
protected void onCancelled(Result result) {
onCancelled();
}
@MainThread
protected void onCancelled() {
}
public final boolean isCancelled() {
return mCancelled.get();
}
public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}
//可以看出是最终是调用executeOnExecutor方法执行的,且默认是串行执行的
public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }//并行执行 只能被调用一次,否则会抛出异常 @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; }//运行在主线程 处理进度 当外部调用了publishProgress,onProgressUpdate会被调用 将进度通过handler发送给主线程 protected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); } }//doInBackGround执行完会调用此方法 private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }//定义一个静态的handler对象,并获取主线程的Looper对象 private static class InternalHandler extends Handler { public InternalHandler() { super(Looper.getMainLooper()); } @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; } } } private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { Params[] mParams; } //将结果封装成AsyncTaskResult对象 private static class AsyncTaskResult<Data> { final AsyncTask mTask; final Data[] mData; AsyncTaskResult(AsyncTask task, Data... data) { mTask = task; mData = data; } }
流程分析
当在主线程构造子类实例后,调用executor方法执行,最终是执行的executorOnexecutor方法,内部有两种线程,一种是THREAD_POOL_EXECUTOR(并行) ,一种是SERIAL_EXECUTOR(串行);默认使用串行执行。
在使用线程执行任务之前,会先调用
onPreExecute,一般用来更新进度条及做一些初始化; 接着对调用
doInBackground,在子线程执行耗时任务,执行完成后会通过handler将消息发送给主线程;
若调用了publishProgress, onProgressUpdate会被调用,用来获取任务执行进度,通过handler发送给主线程以更新进度条;任务执行完后会将结果封装成Result对象发送给主线程,然后调用
onPostExecute方法。在主线程执行,用来更新UI。
优缺点
优点:
封装了handler和Thread使执行耗时任务并更新UI变得简便;
缺点:
不能执行太耗时任务,适用于几秒内能完成的任务;
外部不能单独调用里面的方法,否则会抛异常;
只能在主线程创建子类实例,否则会抛异常;
外部调用cancel方法并不总是有用;
旋转屏幕时造成Activity重建,之前对AsyncTask的引用无效,OnPostExecute无法更新页面;
Activity销毁时,AsyncTask必须取消,否则可能造成AsyncTask crash,以及内存泄露。
有待完善
- AsyncTask 源码分析
- AsyncTask源码分析
- Android AsyncTask源码分析
- Android源码分析--AsyncTask
- 源码分析Android AsyncTask
- Android AsyncTask源码分析
- AsyncTask源码分析
- Android-AsyncTask源码分析
- 源码分析--AsyncTask
- AsyncTask源码分析
- AsyncTask源码分析
- AsyncTask源码分析
- AsyncTask源码分析
- Android AsyncTask 源码分析
- AsyncTask源码分析
- AsyncTask源码分析
- AsyncTask源码分析
- AsyncTask源码分析
- 分布式服务框架设计笔记一
- 计算机网络之面试常考
- poj 1258 Agri-net
- C#中在 64 位系统注册 DSOFramer
- C++中 引用&与取地址&的区别
- AsyncTask 源码分析
- 【线段树】HDU 5493 Queue (2015 ACM/ICPC Asia Regional Hefei Online)
- Linux,你了解多少!
- 如何准备BAT技术面试答案(中)——Java研发方向
- Android LruCache简单分析
- CentOS 6.5 下安装ettercap
- JVM中稳定与震荡的堆
- Debian 7 安装metasploit
- C#字符串格式化 ->string.Format