AsyncTask的简单理解(源码级)
来源:互联网 发布:淘宝网店计划 编辑:程序博客网 时间:2024/06/06 09:13
AsyncTask的简单理解
AsyncTask里面有两个线程池ThreadPoolExecutor
和SerialExecutor
还有一个Handler
。,其中SerialExecutor
用来给线程排队,真正执行的是ThreadPoolExecutor
,Handler
用于线程之间的切换。给AsyncTask排队的容器是一个单向队列ArrayDeque<Runnable>
,他保存了所有将要执行的线程。先来看一下熟悉的execute
方法
@MainThread public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
他调用了executeOnExecutor方法,同时把用于排队的线程池和在doInBackground需要用到的参数传进去。
@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()
,所以说onPreExecute()
在主线程调用。然后他使用了exec.execute(mFuture);
来排队,这里的exec就是上面传过来的sDefaultExecutor
,也就是用于排队的线程池。那么他的参数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() { ...... } }; }
上面代码中WorkerRunnable
是一个抽象类,他封装了Params[],WorkerRunnable
也实现了Callable<Result>
接口,用于把这条线程放到FutureTask
里面进行执行。FutureTask
会自动调用WorkerRunnable
里面重写的call()
方法,而在这个call()
正有我们熟悉的doInBackground(mParams);
doInBackground();
如何处理结果
当运行结束后,返回一个result,由于他运行在子线程里面,需要把结果提交到主线程来显示,所以他会调用postResult(result);
来显示结果。线程之间的切换用的是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如果处理结果。运行到result.mTask.finish(result.mData[0]);
他会执行
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
看到onPostExecute(result)
了吧,他就是用于接受结果的回调方法。由于用到了Handler切换线程,所以他运行在主线程。
如何更新进度
我们都知道在子线程里面更新进度需要调用publishProgress
方法。
@WorkerThread protected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); } }
首先在消息池里面获取到MESSAGE_POST_PROGRESS
消息。然后把AsyncTaskResult<Progress>
的实例放到里面。这个AsyncTaskResult<Progress>
是什么呢?
private static class AsyncTaskResult<Data> { final AsyncTask mTask; final Data[] mData; AsyncTaskResult(AsyncTask task, Data... data) { mTask = task; mData = data; } }
他是一个静态类,构造器里面封装的AsyncTask和需要被更新的值。
然后Handler
会把它发送到what为MESSAGE_POST_PROGRESS
的消息中,用来更新进度。
线程池是如何工作的。
1.排队线程池,先看代码
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); } } }
他也是一个静态类,实现了Executor
,并重写了execute方法。里面维护这一个ArrayDeque
他是一个单向的队列。这里用到了他的两个方法。offer()
和poll()
,其中offer()
方法是向队列最后面插入一条数据mTasks,poll()
是从队列的最前面取出一条数据并将其删除。
他在插入的同时新建一个Runable
同时执行了传入这条线程的run()
方法。这里你也许要问,为什么一Runable
要套一个Runable
呢,既然是排队那么为什么要运行run()
方法呢?
1、如果这个Runable
如果不包含一个Runable
,那么这个传进来的Runable
就会直接执行的,注意,是执行在主线程。另外一个线程池没有起到作用。
2、这里虽然运行了run()
方法真的线程也没有执行,里面线程虽然调用了run()
方法,仅仅是调用而已,外面的Runable没有执行,里面的run()
方法就不会执行。
排队之后他会执行scheduleNext();
方法,这个方法是启动分线程的关键。他先从队列中取出Runable
,然后调用ThreadPoolExecutor
的execute()
方法来真正执行线程。
线程池的参数
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); private static final int CORE_POOL_SIZE = CPU_COUNT + 1; private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; private static final int KEEP_ALIVE = 1; 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);
自己看吧,谷歌写的很明白
- AsyncTask的简单理解(源码级)
- AsyncTask源码的理解
- AsyncTask源码理解
- 从源码理解AsyncTask
- 关于AsyncTask-异步任务的简单理解
- 异步任务AsyncTask的简单理解
- AsyncTask的理解(一)
- Android AsyncTask源码简单分析
- AsyncTask源码解析,简单使用
- 理解Android的AsyncTask
- Android AsyncTask的理解
- 关于AsyncTask的理解
- AsyncTask的理解
- AsyncTask的使用&&理解
- AsyncTask的源码解析(一)
- AsyncTask的简单使用
- AsyncTask的简单用法
- AsyncTask的简单使用
- opencv3.0.0 for android .判断两张图片是否一致
- HTML5初学者路线图
- liftweb整合ckfinder进行文件上传与管理
- 在线预览 模仿百度文库
- 分布式服务的Trace——Google Dapper & Twitter Zipkin
- AsyncTask的简单理解(源码级)
- iOS网络之多线程
- mina 字节数组编解码器的写法
- 测试oracle存储过程,光标,连接等的java代码
- Meta http-equiv属性详解
- C++轻量级日志类CLogger的使用(更新)
- rom isim仿真
- iOS小技巧-UITableView禁止上下滑动超出顶部或者底部的内容
- windows下 android jdk sdk环境配置