从应用角度看Android源码
来源:互联网 发布:linux运维项目 编辑:程序博客网 时间:2024/05/19 05:04
本想写一下源码的获取和编译的过程,无奈出租房的网络实在太差,没能把源码下完整,暂且跳过这一步,假设我已经写好了.这一篇就学习一下AsyncTask,这是一个比较简单的知识点,作为源码开发的热身小甜点.
AsyncTask是一个轻量级的异步操作类,我写了一个极其简单的Demo代码如下
public class MainActivity extends Activity { private final String TAG = "testlog"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //实例化一个AsyncTask new AsyncTask<Integer, Integer, Integer>() { //根据名字可以了解到这个函数可以在执行doInBackground函数之前做一些初始化的工作 @Override protected void onPreExecute() { super.onPreExecute(); log("onPreExecute: "); } //进行异步操作的函数,该函数不在主线程执行 @Override protected Integer doInBackground(Integer... integers) { log("doInBackground: init > " + integers[0]); int i = 5; while (i-- > 0) { log("doInBackground: " + i); //调用该函数可以更新进度条,会调用onProgressUpdate()函数 publishProgress(i); //模拟耗时操作 sleep(500); } return i; } //执行在主线程里 @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); log("onProgressUpdate: " + values[0]); } //异步操作执行完成后调用该方法 @Override protected void onPostExecute(Integer integer) { super.onPostExecute(integer); log("onPostExecute: " + integer); } }.execute(13); } private void sleep(long time) { try { Thread.sleep(time); } catch (Exception e) { e.printStackTrace(); } } private void log(String msg) { Log.i(TAG, msg + " > " + Thread.currentThread()); }
执行结果如下
04-14 13:02:10.250 I: onPreExecute: > Thread[main,5,main]04-14 13:02:10.251 I: doInBackground: init > 13 > Thread[AsyncTask #1,5,main]04-14 13:02:10.255 I: doInBackground: 4 > Thread[AsyncTask #1,5,main]04-14 13:02:10.264 I: onProgressUpdate: 4 > Thread[main,5,main]04-14 13:02:10.757 I: doInBackground: 3 > Thread[AsyncTask #1,5,main]04-14 13:02:10.758 I: onProgressUpdate: 3 > Thread[main,5,main]04-14 13:02:11.259 I: doInBackground: 2 > Thread[AsyncTask #1,5,main]04-14 13:02:11.260 I: onProgressUpdate: 2 > Thread[main,5,main]04-14 13:02:11.761 I: doInBackground: 1 > Thread[AsyncTask #1,5,main]04-14 13:02:11.762 I: onProgressUpdate: 1 > Thread[main,5,main]04-14 13:02:12.263 I: doInBackground: 0 > Thread[AsyncTask #1,5,main]04-14 13:02:12.264 I: onProgressUpdate: 0 > Thread[main,5,main]04-14 13:02:12.765 I: onPostExecute: -1 > Thread[main,5,main]
接下来就去挖坟,看看这是一个怎样的流程,首先从AsyncTask的入口execute着手
@MainThread public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
在execute里面调用了executeOnExecutor()函数,不过多了一个参数sDefaultExecutor,先看看这个参数是个什么鬼
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
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接口的类,知道他是一个类就可以了.再回过来继续扒坟,看看executeOnExecutor()又做了什么
@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; }
这里面先判断了一下当前的状态,怪不得这个异步任务只能执行一次execute(),原来在这块根据状态抛出了异常.判断状态之后调用了onPreExecute(),这是AsyncTask回调的第一个函数,注意这个 @MainThread 注解的意思是这个函数必须在主线程中执行.回调onPreExecute()之后又调用了exec.execute(mFuture),看看mFuture是啥,
mFuture = new FutureTask<Result>(mWorker)
public class FutureTask<V> implements RunnableFuture<V>
public interface RunnableFuture<V> extends Runnable, Future<V>看到这里可以了解到mFuture是实现了Runnable接口的类的实例。根据我对AsyncTask的了解这个exec.execute(mFuture)的操作会跟doInBackground()这个回调扯上匪夷所思的关系.凡是要讲究证据,再继续往下找线索.这个exec就是上面找的sDefaultExecutor,不在重复粘贴代码了,可以去上面看,看看他的execute()方法都干了啥,让在里面又调用了mTasks.offer(),mTasks是ArrayDeque类型,这句是把任务推进队列。接下来就调用了 scheduleNext();
protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } }
这个函数是把队列中的第一个任务放进线程池,这样一来在条件允许的情况下会执行该任务,也就是会在新的线程里回调mFuture的的run方法。下面研究一下FutureTask类
public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; // ensure visibility of callable }根据上面可以知道mFuture实例中的callable变量是mWorker实例,再看看他的run函数,
public void run() { if (state != NEW || !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread())) return; try { Callable<V> c = callable; if (c != null && state == NEW) { V result; boolean ran; try { result = c.call(); ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } if (ran) set(result); } } finally { // runner must be non-null until state is settled to // prevent concurrent calls to run() runner = null; // state must be re-read after nulling runner to prevent // leaked interrupts int s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); } }
在这里调用的mWorker的call()函数,在回到AsyncTask类看看mWorker是什么样子的。
mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Result result = null; try { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked result = doInBackground(mParams); Binder.flushPendingCommands(); } catch (Throwable tr) { mCancelled.set(true); throw tr; } finally { postResult(result); } return result; } };
原来在这里调用了doInBackground(),因为他是由mFuture所在线程调用的,也就是线程池里的线程,并非在主线程上运行,所以这里不能出现直接更新UI的操作。在最后还调用了 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; }他向一个handler发送了一条MESSAGE_POST_RESULT类别的消息,这个handler在哪呢
private static Handler getHandler() { synchronized (AsyncTask.class) { if (sHandler == null) { sHandler = new InternalHandler(); } return sHandler; } }
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; } } }
原来他是AsyncTask里的handler,他接收到MESSAGE_POST_RESULT消息的时会调用finish()函数
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
在finish()里调用了 onPostExecute(result);因为是AsyncTask的handler调用的finish()函数,因此该函数是运行在AsyncTask所在的线程里的,也就是主线程。至此AsyncTask的三个函数
都已经出现了,还差一个protected void onProgressUpdate(Integer... values),这个函数通常是为了更新进度条的,与他有直接关系的就是publishProgress(Progress... values)protected void onPreExecute()
protected Integer doInBackground(Integer... integers)
protected void onPostExecute(Integer integer)
@WorkerThread protected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); } }这个函数向handler发送了一条MESSAGE_POST_PROGRESS类别的消息,handler接收到该类别消息后会调用onProgressUpdate,这样就会更新进度条了,到这里onProgressUpdate()也出现了,扒坟结束。
阅读全文
0 0
- 从应用角度看Android源码
- 从应用角度看Android源码
- 从应用角度看Android源码
- 从应用角度看Android源码
- 从应用角度看Android源码
- 【Android】从源码角度看Handler机制
- 从源码角度看Handler原理
- 从源码角度看Activity知识点(一)
- 从源码角度看Activity知识点(二)
- 从JDK源码角度看Boolean
- 从JDK源码角度看Object
- 从JDK源码角度看Byte
- 从JDK源码角度看Short
- 从JDK源码角度看Integer
- 从JDK源码角度看Long
- 从JDK源码角度看Long
- 从JDK源码角度看Float
- 从JDK源码角度看Float
- C#解析JSON字符串总结
- 动态加载so库
- IntelliJ IDEA 常用快捷键
- 常用的正则
- Tortoise SVN更新脚本
- 从应用角度看Android源码
- document.querySelector() document.querySelectAll()
- 自定义解析器【一】
- Redis资料汇总
- Ceph RBD编程接口Librbd(C++) -- 映像创建与数据读写
- Java随机数
- 17/7/31学习笔记04
- Android提示错误“R cannot be resolved…”
- MySQL 索引