摘要:關(guān)于中的消息機(jī)制就進(jìn)行到這里,下一篇將講講中的內(nèi)存泄漏問(wèn)題以及處理方法。
這幾天對(duì)handler有一些研究,寫出來(lái)供大家看看。 一、消息機(jī)制詳解 Android程序中,主要是通過(guò)消息機(jī)制來(lái)推動(dòng)整個(gè)程序運(yùn)作的。而消息機(jī)制中,完成主要功能的主要有以下幾個(gè)類: 1、Looper 2、Message、MessageQueue 3、handler 這是最基礎(chǔ)的幾個(gè)消息機(jī)制類,下面探究一下這幾個(gè)類如何完成Android消息機(jī)制的運(yùn)行。 首先看Message和MessageQueue。Message顧名思義,是消息機(jī)制中消息的載體,繼承Parcelable序列化接口,可以在進(jìn)程和組件之間作為消息的載體傳播消息。而MessageQueue就是承載message的隊(duì)列。關(guān)于Message,主要有以下幾點(diǎn)總結(jié): 1、Message中是持有Handler對(duì)象,作為Message的target的。這也很好理解,為了發(fā)送消息給handler嘛~這里要注意的一點(diǎn)是,Message中持有handler,而handler一般是持有Context的,所以這里是有可能引發(fā)內(nèi)存泄漏的,后面會(huì)對(duì)這點(diǎn)進(jìn)行進(jìn)一步講解。
有了target之后,message就可以調(diào)用:
還有
public void sendToTarget() {
target.sendMessage(this);
} //發(fā)送消息到target handler
2、Message中有四個(gè)參數(shù):
public int what
public int arg1
public int arg2
public Object obj
what參數(shù)是消息的識(shí)別碼,用于給handler判斷不同的Message,采取不同的處理方法,這個(gè)不用多說(shuō)了。
arg1和arg2都是一些攜帶在message中的int消息,相比setData(bundle)更加輕量級(jí)。
obj是message中可以承載的對(duì)象,注意要實(shí)現(xiàn)Parcelable接口。
3、Message中的recyle方法是用于當(dāng)message被消費(fèi)后,對(duì)message進(jìn)行回收的。這個(gè)方法也蠻重要的,正是因?yàn)閙essage會(huì)自己回收自己,才避免了很多內(nèi)存泄漏的問(wèn)題。
4、接下來(lái)看看MessageQuene。MessageQueue是承載Message的隊(duì)列,其中最重要的方法是next方法,這個(gè)方法的作用是返回隊(duì)列中下一個(gè)message。
接下來(lái)看看Looper。Looper我覺(jué)得是消息機(jī)制中最核心的類,起到了推動(dòng)整個(gè)消息機(jī)制運(yùn)行的作用。 looper中的主要有以下四個(gè)方法: public static prepare(); public static myLooper(); public static loop(); public void quit(); prepare方法代碼如下:
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));
}
這個(gè)方法可以理解為為本現(xiàn)場(chǎng)初始化隊(duì)列消息,每個(gè)線程要使用looper進(jìn)行消息循環(huán)時(shí),都要先調(diào)用perpare方法。 myLooper方法用于返回當(dāng)前消息隊(duì)列的線程。注意,一個(gè)消息隊(duì)列只能有一個(gè)線程。 Looper中最重要的是loop方法,調(diào)用這個(gè)方法,整個(gè)隊(duì)列遍開始循環(huán)。下面看看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;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn"t corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
可以看到,loop方法中不斷地從消息隊(duì)列mQueue中去獲取下一個(gè)要處理的消息msg,如果消息的target成員變量為null,就表示要退出消息循環(huán)了 否則的話就要調(diào)用這個(gè)target對(duì)象的dispatchMessage成員函數(shù)來(lái)處理這個(gè)消息,這個(gè)target對(duì)象的類型為Handler 在上面的代碼中,msg調(diào)用了它的target的dispatchMessage方法,實(shí)際上就是將msg丟給handler去處理了(實(shí)際上handler也沒(méi)有處理,是提供接口給實(shí)現(xiàn)了handleMessage的具體事務(wù)類去處理)。 接下來(lái)看看Handler。Handler主要分為SendMessage和HandleMessage兩個(gè)方法,分別是發(fā)送msg和處理msg。 SendMessage方法代碼如下:
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);
}
重點(diǎn)在最后一行加粗的代碼,就是把msg裝進(jìn)msgqueue隊(duì)列中(message肯定是持有messageQueue對(duì)象的廢話)。其實(shí)發(fā)送消息實(shí)際上,也就是把消息裝進(jìn)消息隊(duì)列中而已,因?yàn)榍懊娴膌oop方法已經(jīng)在不斷的循環(huán)的讀取msgqueue中的消息,只要把消息加進(jìn)messagequeue中,就可以是消息得到處理。 再來(lái)看看消息是怎樣被處理的:
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
這里可以看到,實(shí)際上handler是沒(méi)有處理msg的,而是給繼承了handler的具體類,實(shí)現(xiàn)handlermessage,并對(duì)消息做出相應(yīng)的處理。 我們可以看出,handler實(shí)際上并沒(méi)有做什么事情,只是提供回調(diào)接口,給具體的類去實(shí)現(xiàn)。在使用handler的時(shí)候,可以讓具體處理msg的類繼承handler.Callback接口,實(shí)現(xiàn)handleMessage方法去處理消息。 關(guān)于Android中的消息機(jī)制就進(jìn)行到這里,下一篇將講講handler中的內(nèi)存泄漏問(wèn)題以及處理方法。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/64413.html
今年3月,Google 破天荒提前半年發(fā)布了 Android N 開發(fā)者預(yù)覽版。當(dāng)然,作為一個(gè)不合格的谷粉并沒(méi)有第一時(shí)間體驗(yàn)安裝,因?yàn)橹两袢匀荒軌蚧貞浧饋?lái)去年今日此門中(霧)興沖沖刷了 Android M Preview 的時(shí)候發(fā)現(xiàn)各種 Crash 就連微信也(不出所料得)中招時(shí)自己一臉懵逼的心情。當(dāng)然,為自己的機(jī)智而慶幸并沒(méi)有過(guò)多久,很快就有微信好友(當(dāng)然也是純純的谷粉)反饋微信又雙叒叕在 An...
摘要:如何挑選合適的導(dǎo)航結(jié)構(gòu)導(dǎo)航設(shè)計(jì)是應(yīng)用設(shè)計(jì)的關(guān)鍵,設(shè)計(jì)規(guī)范以下簡(jiǎn)稱規(guī)范中將導(dǎo)航元素分為對(duì)等層次和歷史導(dǎo)航等幾類,例如表和透視表導(dǎo)航窗格是對(duì)等導(dǎo)航元素,中心大綱細(xì)節(jié)屬于分層導(dǎo)航元素,返回則屬于歷史導(dǎo)航元素。 此文已由作者楊凱明授權(quán)網(wǎng)易云社區(qū)發(fā)布。 歡迎訪問(wèn)網(wǎng)易云社區(qū),了解更多網(wǎng)易技術(shù)產(chǎn)品運(yùn)營(yíng)經(jīng)驗(yàn)。 繼Windows 10系統(tǒng)發(fā)布之后,很多Windows用戶更新了系統(tǒng)。win10系統(tǒng)的發(fā)布,...
閱讀 3769·2021-09-02 09:53
閱讀 2749·2021-07-30 14:57
閱讀 3492·2019-08-30 13:09
閱讀 1179·2019-08-29 13:25
閱讀 810·2019-08-29 12:28
閱讀 1453·2019-08-29 12:26
閱讀 1129·2019-08-28 17:58
閱讀 3305·2019-08-26 13:28