1.消息隊列(Handler, MessageQueue,Message,Looper)
1.1Handler的作用:
(1)android中最常見的,刷新ui,這裏基本就是在主線程創建handler (2)不用刷新ui,僅僅是傳遞處理消息,包括線程間傳遞消息和線程內部傳遞消息,這裏基本就是在子線程創建handler。如下:
new Thread(new Runnable() {
@Override public void run() {
Looper.prepare();
handler2 = new Handler(){
@Override public void handleMessage(Message msg) {
if (msg.arg1==1) {
Toast.makeText(MainActivity.this,"hanlder2",Toast.LENGTH_SHORT).show();
}
System.out.println("handler2========="+Thread.currentThread().getName());
super.handleMessage(msg);
}
};
Message message = handler2.obtainMessage();
message.arg1 = 1;
handler2.sendMessage(message);
Looper.loop();
}
}
).start();
1.2Looper.perpare()分析
在子線程中創handler必須調用先調用Looper.perpare(),再創建handler最後調用Looper.loop()。深入到源碼就可以看見prepare方法中其實就是在子線程中創建了一個Looper放到threadlocal中,這裏也間接說明了一個線程最多隻能創建一個looper對象,一個handler也有且只有一個looper和它相對應的。
public static void prepare() {
prepare(true);
}
private static void prepare(Boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
2 Handler消息處理機制的工作流程:
handler把消息Messagr發送到消息隊列MessageQueue裏,然後Looper通過死循環不斷的從消息隊列中獲取到Message,由於Message的target是handler,於是就轉到handleMessage方法中去處理。從源碼角度來分析這個過程:
2.1從activity啓動入口ActivityThread.Main()開始分析
main方法中會調用Looper.prepareMainLooper方法來創建Looper對象,Looper的構造函數中又會創建MessageQueue對象。
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
prepareMainLooper()源碼如下,在prepare中可以看見是創建了Looper對象。
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
private static void prepare(Boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
來看Looper的構造方法,裏面創建了消息隊列MesageQueue對象。
private Looper(Boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
2.2Mesage消息的發送過程。
public final Boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final Boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public Boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private Boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
可以看到sendMessage最後是走到queue.enqueueMessage(msg, uptimeMillis)方法到消息隊列排隊,queue就是looper的構造函數中創建的messagequeue,上面的message的target其實就是handler,到此handler就把mesage發送到messagequeue了。
2.3消息在消息隊列中的排隊過程
msg.markInUse();
msg.when = when;
Message p = mMessages;
Boolean needWake;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p;
prev.next = msg;
}
從上面可以看到mesagequeue內部其實就是個單鏈表,用mMessage表示當前待處理的消息。(1)應用首次調用sendMessage時,當前待處理的消息爲null,則p爲空,則會執行;(2)當前傳入msg的when小於當前待處理msg的when,及當前傳入的消息要先於當前待處理mMessages得到處理,所以傳入的msg賦值爲mMessages,而下一個待處理消息才爲原先的待處理消息。(3)當消息的時間(when)比當前待處理的消息的時間(when)大,這個時候就會移動鏈表,根據時間先後,插入到合適的位置
2.4Looper.loop()從消息隊列中取消息並處理的過程
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next();
msg.target.dispatchMessage(msg);
}
}
可以很清楚的看到最後是走到了handleMessage方法的。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
2.5其他子線程更新ui的方法底層實現,其實都是調用Handler.senMessage實現的
- (1).Handler的post()方法
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
- (2)View的post()方法
public Boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
ViewRootImpl.getRunQueue().post(action);
return true;
}
}
- (3)Activity的runOnUiThread()方法
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
3.Activity一些比較難的知識點
3.1setResult和finish的順序關係
Activity-A中用startActivityForResult()方法啓動了Activity-B,並且在B中通過setResult()方法給A返回值,這個過程的生命週期執行過程爲:
B---onBackPressed
B---finish
B---onPause
A---onActivityResult
A---onRestart
A---onStart
A---onResume
B---onStop
B---onDestroy
3.2onSaveInstanceState()和onRestoreInstanceState()
正常情況下是不會觸發這兩個方法,當activity被系統破壞例如屏幕旋轉時會觸發。onSaveInstanceState(),系統在用戶離開Activity時調用它保存數據到bundle對象,然後,如果系統在被銷燬之後必須重新創建Activity實例,它會將相同的Bundle對象傳遞給您的Activity的onRestoreInstanceState()方法以及您的onCreate() 方法。
static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
...
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// 保存用戶自定義的狀態
savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
// 調用父類交給系統處理,這樣系統能保存視圖層次結構狀態
super.onSaveInstanceState(savedInstanceState);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // 記得總是調用父類
// 檢查是否正在重新創建一個以前銷燬的實例
if (savedInstanceState != null) {
// 從已保存狀態恢復成員的值
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
} else {
// 可能初始化一個新實例的默認值的成員
}
...
}
public void onRestoreInstanceState(Bundle savedInstanceState) {
// 總是調用超類,以便它可以恢復視圖層次超級
super.onRestoreInstanceState(savedInstanceState);
// 從已保存的實例中恢復狀態成員
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
m
3.3onNewIntent()和onConfigurationChanged()
onConfigurationChanged:當系統的配置信息發生改變時,系統會調用此方法。注意,只有在配置文件AndroidManifest中處理了configChanges屬性對應的設備配置,該方法纔會被調用。如果發生設備配置與在配置文件中設置的不一致,則Activity會被銷燬並使用新的配置重建。
橫豎屏幕切換的配置:android:configChanges="orientation|screenSize"
onNewIntent的觸發時機:第一種情況:activity launchMode爲singleTask或者singleInstance的時候,activity第二次被啓動的時候會調用onNewIntent。第二種情況:activity launchMode爲singleTop singleTask singleInstance的時候,也就是棧頂複用acitivity再次被啓動時會調用。其實說白了就是在棧中只有一個activity實例的情況下,再次進入activity會執行onNewIntent方法。