消息隊列和Activity的難點

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方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章