在Android中,常用的主线程同步方式有以下几种:
这几种方式其原理都是一样的,都是基于Handler。
runOnUiThread是Activity中的一个final方法,不可以被重写,接受一个Runnable对象,其内部实现首先是判断当前线程是不是UI线程,如果是UI线程则直接调用Runnable的run()方法,如果不是,则通过Handler将Runnablepost到主线程,此Handler为主线程的Handler。
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
这里的mUiThread在Activity的attach()方法中得到初始化。
final void attach(...) {
...
mUiThread = Thread.currentThread();
...
}
这里的mUiThread 为什么会是主线程呢?
我们知道,当Zygote孵化出一个进程之后,便会执行ActivityThread中的main()方法,main()方法中初始化了mainLooper,随后new了一个ActivityThread对象,初始化了一个名为mH的Handler,然后进行Looper.loop()操作。
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
...
Looper.loop();
}
在mH中是这样实现的,然后调用handleLaunchActivity,最后执行Activity的attach方法,便初始化了mUiThread。
class H extends Handler {
...
public void handleMessage(Message msg) {
....
case LAUNCH_ACTIVITY:
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
break;
....
}
}
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
...
Activity a = performLaunchActivity(r, customIntent);
...
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
...
}
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
getRunQueue().post(action);
return true;
}
public boolean postDelayed(Runnable action, long delayMillis) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.postDelayed(action, delayMillis);
}
getRunQueue().postDelayed(action, delayMillis);
return true;
}
两个方法都会先判断attachInfo是否为空,如果不为空则执行Handler.post(),那么attachInfo的赋值情况如何呢?
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
mAttachInfo = info;
}
void dispatchDetachedFromWindow() {
mAttachInfo = null;
}
dispatchAttachedToWindow和dispatchDetachedFromWindow何时被调用这里不做展开,当attachInfo为空时,也就是执行了dispatchDetachedFromWindow之后,post的Runnable便会被加入到mRunQueue中,这里可以暂且将其理解为一个Runnable数组,当下次调用dispatchAttachedToWindow后,便会从mRunQueue中拿出Runnable依次执行handler.postDelayed。
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
...
if (mRunQueue != null) {
mRunQueue.executeActions(info.mHandler);
mRunQueue = null;
}
...
}
public void executeActions(Handler handler) {
synchronized (this) {
final HandlerAction[] actions = mActions;
for (int i = 0, count = mCount; i < count; i++) {
final HandlerAction handlerAction = actions[i];
handler.postDelayed(handlerAction.action, handlerAction.delay);
}
mActions = null;
mCount = 0;
}
}
在AsyncTask中有一个名为mHandler的Handler,可以通过getHandler拿到,通常我们使用AsyncTask都是调用AsyncTask的无参构造方法,而无参构造方法会初始化主线程的Handler。在AsyncTask中,onPreExecute、onCancelled、onPostExecute、onProgressUpdate都会在主线程被调用,除onPreExecute是在一开始就被调用外,其余方法皆是通过Handler让其在主线程执行。
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult
mHandler就是AsyncTask内部的InternalHandler
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@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;
}
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
protected void onProgressUpdate(Progress... values) {
}