【移動應(yīng)用開發(fā)技術(shù)】如何進(jìn)行Handler、Looper與MessageQueue源碼分析_第1頁
【移動應(yīng)用開發(fā)技術(shù)】如何進(jìn)行Handler、Looper與MessageQueue源碼分析_第2頁
【移動應(yīng)用開發(fā)技術(shù)】如何進(jìn)行Handler、Looper與MessageQueue源碼分析_第3頁
【移動應(yīng)用開發(fā)技術(shù)】如何進(jìn)行Handler、Looper與MessageQueue源碼分析_第4頁
【移動應(yīng)用開發(fā)技術(shù)】如何進(jìn)行Handler、Looper與MessageQueue源碼分析_第5頁
免費(fèi)預(yù)覽已結(jié)束,剩余2頁可下載查看

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

【移動應(yīng)用開發(fā)技術(shù)】如何進(jìn)行Handler、Looper與MessageQueue源碼分析

本篇文章為大家展示了如何進(jìn)行Handler、Looper與MessageQueue源碼分析,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。在Android中可以通過Handler來更新主線程中UI的變化,更新UI只能在主線程中進(jìn)行更新,而為了讓其他線程也能控制UI的變化,Android提供了一種機(jī)制Handler、Looper與MessageQueue一同協(xié)作來達(dá)到其他線程更新UI的目的。一般我們會在主線程中通過如下方法定義一個Handlerprivate

Handler

mHandler

=

new

Handler()

{

@Override

public

void

handleMessage(Message

msg)

{

tv.setText("mHandler

change

UI");

super.handleMessage(msg);

}

};一般都見不到Looper與MessageQueue的,那么它們都是在哪里調(diào)用與如何協(xié)作的呢?在主線程不會顯式的調(diào)用Looper而是會在ActivityThread.main方法中默認(rèn)調(diào)用。public

static

void

main(String[]

args)

{

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,

"ActivityThreadMain");

SamplingProfilerIntegration.start();

//

CloseGuard

defaults

to

true

and

can

be

quite

spammy.

We

//

disable

it

here,

but

selectively

enable

it

later

(via

//

StrictMode)

on

debug

builds,

but

using

DropBox,

not

logs.

CloseGuard.setEnabled(false);

Environment.initForCurrentUser();

//

Set

the

reporter

for

event

logging

in

libcore

EventLogger.setReporter(new

EventLoggingReporter());

//

Make

sure

TrustedCertificateStore

looks

in

the

right

place

for

CA

certificates

final

File

configDir

=

Environment.getUserConfigDirectory(UserHandle.myUserId());

TrustedCertificateStore.setDefaultUserDirectory(configDir);

Process.setArgV0("<pre-initialized>");

Looper.prepareMainLooper();//創(chuàng)建Looper

ActivityThread

thread

=

new

ActivityThread();

thread.attach(false);

if

(sMainThreadHandler

==

null)

{

sMainThreadHandler

=

thread.getHandler();

}

if

(false)

{

Looper.myLooper().setMessageLogging(new

LogPrinter(Log.DEBUG,

"ActivityThread"));

}

//

End

of

event

ActivityThreadMain.

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

Looper.loop();//開啟Looper循環(huán)

throw

new

RuntimeException("Main

thread

loop

unexpectedly

exited");

}如上代碼,調(diào)用了Looper.prepareMainLooper()方法,在主線程中創(chuàng)建了一個Looper,不信的話我們再查看該方法做了什么Looperpreparepublic

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));//創(chuàng)建Looper并賦給sThreadLocal

}

/**

*

Initialize

the

current

thread

as

a

looper,

marking

it

as

an

*

application's

main

looper.

The

main

looper

for

your

application

*

is

created

by

the

Android

environment,

so

you

should

never

need

*

to

call

this

function

yourself.

See

also:

{@link

#prepare()}

*/

public

static

void

prepareMainLooper()

{

prepare(false);

synchronized

(Looper.class)

{

if

(sMainLooper

!=

null)

{

throw

new

IllegalStateException("The

main

Looper

has

already

been

prepared.");

}

sMainLooper

=

myLooper();

}

}

public

static

@Nullable

Looper

myLooper()

{

return

sThreadLocal.get();

}在prepareMainLooper方法中調(diào)用了prepare而通過prepare會發(fā)現(xiàn)它其實(shí)就是創(chuàng)建了一個Looper,并把它賦給了sThreadLocal。同時可以通過myLooper方法獲取當(dāng)前線程中的Looper。再來看下new

Looper(quitAllowed)初始化了什么private

Looper(boolean

quitAllowed)

{

mQueue

=

new

MessageQueue(quitAllowed);

mThread

=

Thread.currentThread();

}在這里我們終于看到了MessageQueue了,它創(chuàng)建了一個MessageQueue。該消息隊列就是用來保存后續(xù)的Message。再回到ActivityThread.main方法中,發(fā)現(xiàn)它調(diào)用了Looper.loop()是用來開啟Looper循環(huán)的,監(jiān)聽消息隊列MessageQueue中的消息。loop我們來看下Looper.loop()的源碼:public

static

void

loop()

{

final

Looper

me

=

myLooper();//獲取Looper

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

final

Printer

logging

=

me.mLogging;

if

(logging

!=

null)

{

logging.println(">>>>>

Dispatching

to

"

+

msg.target

+

"

"

+

msg.callback

+

":

"

+

msg.what);

}

final

long

traceTag

=

me.mTraceTag;

if

(traceTag

!=

0)

{

Trace.traceBegin(traceTag,

msg.target.getTraceName(msg));

}

try

{

msg.target.dispatchMessage(msg);//通過Handler分發(fā)消息

}

finally

{

if

(traceTag

!=

0)

{

Trace.traceEnd(traceTag);

}

}

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中首先獲取了當(dāng)前所在線程的Looper,同時也獲取到了Looper中的MessageQueue,說明Looper已經(jīng)與當(dāng)前的線程進(jìn)行了綁定。在后面開啟了一個for的死循環(huán),發(fā)現(xiàn)它做的事件是不斷的從消息隊列中取出消息,***都交給msg.target調(diào)用它的dispatchMessage方法,那么target又是什么呢?我們進(jìn)入MessageMessage/*package*/

int

flags;

/*package*/

long

when;

/*package*/

Bundle

data;

/*package*/

Handler

target;

/*package*/

Runnable

callback;

//

sometimes

we

store

linked

lists

of

these

things

/*package*/

Message

next;發(fā)現(xiàn)它就是我們熟悉的Handler,說明***調(diào)用的就是Handler中的dispatchMessage方法,對消息的分發(fā)處理。這樣一來Handler就通過Looper聯(lián)系上了Looper所綁定的線程,即為主線程。Handlerpublic

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;

}通過Handler的初始化,它獲取了它所處線程的Looper,同時也獲取了Looper中的消息隊列。當(dāng)然如果所處線程的Looper為空的話就會拋出異常,這就解釋了為什么在非主線程中創(chuàng)建Handler要分別調(diào)用Looper.prepare與Looper.loop而主線程則不需要,因?yàn)樗J(rèn)已經(jīng)調(diào)用了。dispatchMessagepublic

void

dispatchMessage(Message

msg)

{

if

(msg.callback

!=

null)

{

handleCallback(msg);

}

else

{

if

(mCallback

!=

null)

{

if

(mCallback.handleMessage(msg))

{

return;

}

}

handleMessage(msg);

}

}

private

static

void

handleCallback(Message

message)

{

message.callback.run();

}回到前面,對于dispatchMessage的處理,首先判斷msg.callback是否為空,這里callback通過上面的Message應(yīng)該能知道他就是一個Runnable,如果不為空則直接調(diào)用Runnable的run方法。否則調(diào)用Handler的handleMessage方法.而這個方法相信大家已經(jīng)很熟悉了,對事件的處理都是在這個方法中執(zhí)行的。因?yàn)橥ㄟ^前面我們已經(jīng)知道了Handler已經(jīng)聯(lián)系上了主線程,所以handleMessage中的處理自然相對于在主線程中進(jìn)行,自然也能更新UI了。通過這里我們能把Looper比作是一個橋梁,來連接Looper所在的線程與Handler之間的通信,同時管理消息隊列MessageQueue中的消息。那么前面的Runnable又是如何不為空的呢?我們使用Handler有兩種方法,一種是直接創(chuàng)建一個Handler并且重寫它的handleMessage方法,而另一種可以通過Handler.post(Runnable)來使用,這樣事件的處理自然就在run方法中實(shí)現(xiàn)。上面介紹了Handler是如何聯(lián)系上了需要操作的線程與對消息是如何取出與處理的。下面來談?wù)勏⑹侨绾畏湃氲絃ooper中的MessageQueue中的。sendMessageAtTime通過Handler發(fā)送消息的方式很多,例如:sendMessage、sendEmptyMessage與sendMessageDelayed等,其實(shí)到***他們調(diào)用的都是sendMessageAtTime方法。所以還是來看下sendMessageAtTime方法中的實(shí)現(xiàn)。public

boolean

sendMessageAtTime(Message

msg,

long

uptimeMillis)

{

MessageQ

溫馨提示

  • 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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論