【移動應(yīng)用開發(fā)技術(shù)】android中怎么實現(xiàn)異步消息機制_第1頁
【移動應(yīng)用開發(fā)技術(shù)】android中怎么實現(xiàn)異步消息機制_第2頁
【移動應(yīng)用開發(fā)技術(shù)】android中怎么實現(xiàn)異步消息機制_第3頁
【移動應(yīng)用開發(fā)技術(shù)】android中怎么實現(xiàn)異步消息機制_第4頁
【移動應(yīng)用開發(fā)技術(shù)】android中怎么實現(xiàn)異步消息機制_第5頁
已閱讀5頁,還剩5頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論