版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
【移動應(yīng)用開發(fā)技術(shù)】android中怎么實現(xiàn)異步消息機制
本篇文章給大家分享的是有關(guān)android中怎么實現(xiàn)異步消息機制,在下覺得挺實用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著在下一起來看看吧。Handler、Message、Loopler、MessageQueen首先看一下我們平常使用Handler的一個最常見用法。Handler
handler
=new
Handler(){
@Override
public
void
handleMessage(Message
msg)
{
super.handleMessage(msg);
//這里進行一些UI操作等處理
}
new
Thread(new
Runnable()
{
@Override
public
void
run()
{
Message
message
=
Message.obtain();
handler.sendMessage(message);
}
});
};看一下handler的構(gòu)造函數(shù)的源碼public
Handler()
{
this(null,
false);
}
//他會調(diào)用本類中的如下構(gòu)造函數(shù)
public
Handler(Callback
callback,
boolean
async)
{
if
(FIND_POTENTIAL_LEAKS)
{
final
Class<?
extends
Handler>
klass
=
getClass();
if
((klass.isAnonymousClass()
||
klass.isMemberClass()
||
klass.isLocalClass())
&&
(klass.getModifiers()
&
Modifier.STATIC)
==
0)
{
Log.w(TAG,
"The
following
Handler
class
should
be
static
or
leaks
might
occur:
"
+
klass.getCanonicalName());
}
}
mLooper
=
Looper.myLooper();
if
(mLooper
==
null)
{
throw
new
RuntimeException(
"Can't
create
handler
inside
thread
that
has
not
called
Looper.prepare()");
}
mQueue
=
mLooper.mQueue;
mCallback
=
callback;
mAsynchronous
=
async;
}看到當(dāng)mLooper==null時會拋一個“Can'tcreatehandlerinsidethreadthathasnotcalledLooper.prepare()”這個異常,所以我們在創(chuàng)建handler實例前首先需要調(diào)用Looper.prepare()public
static
void
prepare()
{
prepare(true);
}
//將looper保存到ThreadLocal中,這里可以把ThreadLocal理解為一個以當(dāng)前線程為鍵的Map,所以一個線程中只會有一個looper
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));
}
//我們看到在new
Looper(quitAllowed)中,創(chuàng)建了一個消息隊列MessageQueen
private
Looper(boolean
quitAllowed)
{
mQueue
=
new
MessageQueue(quitAllowed);
mThread
=
Thread.currentThread();
}接下來我們看handler.sendMessage(message)這個方法,從字面意思就是將信息發(fā)送出去。一般sendMessage累的方法最終都會調(diào)用sendMessageAtTime(Messagemsg,longuptimeMillis)這個方法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);
}我們看到最終會執(zhí)行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);
}最終又會調(diào)用MessageQueen中的queue.enqueueMessage(msg,uptimeMillis)這個方法,這里的queue就是looper構(gòu)造方法中創(chuàng)建的那個消息隊列//MessageQueen的enqueueMessage方法
boolean
enqueueMessage(Message
msg,
long
when)
{
if
(msg.target
==
null)
{
throw
new
IllegalArgumentException("Message
must
have
a
target.");
}
if
(msg.isInUse())
{
throw
new
IllegalStateException(msg
+
"
This
message
is
already
in
use.");
}
synchronized
(this)
{
if
(mQuitting)
{
IllegalStateException
e
=
new
IllegalStateException(
msg.target
+
"
sending
message
to
a
Handler
on
a
dead
thread");
Log.w(TAG,
e.getMessage(),
e);
msg.recycle();
return
false;
}
msg.markInUse();
msg.when
=
when;
Message
p
=
mMessages;
boolean
needWake;
if
(p
==
null
||
when
==
0
||
when
<
p.when)
{
//
New
head,
wake
up
the
event
queue
if
blocked.
msg.next
=
p;
mMessages
=
msg;
needWake
=
mBlocked;
}
else
{
//
Inserted
within
the
middle
of
the
queue.
Usually
we
don't
have
to
wake
//
up
the
event
queue
unless
there
is
a
barrier
at
the
head
of
the
queue
//
and
the
message
is
the
earliest
asynchronous
message
in
the
queue.
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;
//
invariant:
p
==
prev.next
prev.next
=
msg;
}
//
We
can
assume
mPtr
!=
0
because
mQuitting
is
false.
if
(needWake)
{
nativeWake(mPtr);
}
}
return
true;
}MessageQueen雖然名字是一個隊列,但實質(zhì)上他是一個單向鏈表,這個結(jié)構(gòu)能快速進行插入和刪除操作。從上面源碼可以看出來,主要是按照發(fā)送消息的時間順序?qū)sg插入到消息隊列中。接下來我們就需要從消息隊列中取出msg了。這時候就需要調(diào)用Looper.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
(;;)
{
//不斷從消息隊列中取出msg
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交由handler處理
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();
}
}可以看到Looper.loop()方法通過在一個死循環(huán)中調(diào)用Messagemsg=queue.next()將消息不斷的從消息隊列中取出來。queue.next()方法的作用就是從消息隊列中取msg,唯一跳出循環(huán)的方式是MessageQueen的next方法返回了null。現(xiàn)在msg已經(jīng)取出來,下一步就是怎樣將他傳遞給handler了對吧。所以在死循環(huán)中還有一個方法msg.target.dispatchMessage(msg),而msg.target就是handler,在上面handler的enqueueMessage()方法中傳入的msg.target=this,this就是handler本身,接下來就看看handler的dispatchMessage()方法public
void
dispatchMessage(Message
msg)
{
if
(msg.callback
!=
null)
{
handleCallback(msg);
}
else
{
if
(mCallback
!=
null)
{
if
(mCallback.handleMessage(msg))
{
return;
}
}
handleMessage(msg);
}
}如果我們采用無參的構(gòu)造函數(shù)創(chuàng)建handler,msg.callback與mCallback均為空,所以我們會調(diào)用handleMessage(msg),這樣文章開頭的那個實例整個流程就走完了,handleMessage(msg)會在handler實例所在的線程中執(zhí)行。//當(dāng)我們通過這種方式創(chuàng)建handler時,dispatchMessage中的mCallback就不為null
public
Handler(Callback
callback)
{
this(callback,
false);
}
//Callback是一個接口,里面正好也有我們需要的handleMessage(Message
msg),dispatchMessage中的
if
(mCallback
!=
null)
語句內(nèi)的內(nèi)容,就是我們需要重寫的handleMessage(Message
msg)方法
public
interface
Callback
{
public
boolean
handleMessage(Message
msg);
}//當(dāng)我們調(diào)用handler.post()方法執(zhí)行異步任務(wù)時
public
final
boolean
post(Runnable
r)
{
return
sendMessageDelayed(getPostMessage(r),
0);
}
//getPostMessage(r)這個方法中我們看到給m.callback賦值了,就是我們傳入的runnable接口
private
static
Message
getPostMessage(Runnable
r)
{
Message
m
=
Message.obtain();
m.callback
=
r;
return
m;
}
//最后在handleCallback方法中我們執(zhí)行了它的run方法,這也就解釋了為什么在子線程中可以用handler.post(Runnable
r)更新UI
private
static
void
handleCallback(Message
message)
{
message.callback.run();
}總結(jié)梳理整個執(zhí)行過程1.調(diào)用Looper.prepare()方
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 湛江幼兒師范??茖W(xué)?!稓v史教育創(chuàng)新》2023-2024學(xué)年第一學(xué)期期末試卷
- 二零二五年度知識產(chǎn)權(quán)授權(quán)使用合同樣本6篇
- 2025年教師團隊建設(shè)聘用合同及培訓(xùn)計劃3篇
- 云南外事外語職業(yè)學(xué)院《建筑安全技術(shù)及管理》2023-2024學(xué)年第一學(xué)期期末試卷
- 云南三鑫職業(yè)技術(shù)學(xué)院《傳統(tǒng)村落保護與更新設(shè)計》2023-2024學(xué)年第一學(xué)期期末試卷
- 2025年度個人住房貸款合同模板下載服務(wù)協(xié)議4篇
- 2025年度虛擬現(xiàn)實技術(shù)應(yīng)用于教育培訓(xùn)合同4篇
- 2025年度醫(yī)療設(shè)備質(zhì)押典當(dāng)融資服務(wù)合同4篇
- 2025年物業(yè)買賣合同社區(qū)可持續(xù)發(fā)展規(guī)劃3篇
- 云南民族大學(xué)《輔項理論與技術(shù)格斗類》2023-2024學(xué)年第一學(xué)期期末試卷
- PEP小學(xué)六年級英語上冊選詞填空專題訓(xùn)練
- 古建筑修繕項目施工規(guī)程(試行)
- GA 844-2018防砸透明材料
- 化學(xué)元素周期表記憶與讀音 元素周期表口訣順口溜
- 非人力資源經(jīng)理的人力資源管理培訓(xùn)(新版)課件
- MSDS物質(zhì)安全技術(shù)資料-201膠水
- 鉬氧化物還原過程中的物相轉(zhuǎn)變規(guī)律及其動力學(xué)機理研究
- (完整word)2019注冊消防工程師繼續(xù)教育三科試習(xí)題及答案
- 《調(diào)試件現(xiàn)場管理制度》
- 社區(qū)治理現(xiàn)代化課件
- 代持房屋協(xié)議書
評論
0/150
提交評論