澳门新莆京手机网站-新蒲京娱乐场 > 书籍 > 澳门新莆京手机网站Android Handler Looper Message 详细解析

澳门新莆京手机网站Android Handler Looper Message 详细解析

Handler

public Handler(Looper looper, Callback callback, boolean async) {
       mLooper = looper;
       mQueue = looper.mQueue;
       mCallback = callback;  //handleMessage的借口
       mAsynchronous = async;
   }

上边是 Handler 布局器,由此可见,它具有 looper 对象,以致 looper 的 message queue 。

要经过 Handler 来处总管件,能够重写 handleMessage(Message msgState of Qatar,也足以一向通过 post(Runnable r卡塔尔来管理。那七个主意都会在looper循环中被调用。

还记得刚在loop循环中管理音讯的 msg.target.dispatchMessage(msg卡塔尔方法。今后大家来看下那几个艺术的源码。

public void dispatchMessage(Message msg) {
    //注意!这里先判断message的callback是否为空,否则就直接处理message的回调函数
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            //正是在这调用我们平常重写handleMessage
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

科学,正是在此个点子中调用了 handleMessage(Message msg卡塔尔(قطر‎。值得注意的是,再调用 handleMessage(Message msg卡塔尔此前,还肯定了message的callback是不是为空。那是怎么?

相当轻松,那就是 post(Runnable r卡塔尔国方法也能用来处管事人件的来由。直接看它的源码。我就不赘述了。相信已经很清晰了。

public final boolean post(Runnable r)
{
    //获取消息并发送给消息队列
    return  sendMessageDelayed(getPostMessage(r), 0);
}

private static Message getPostMessage(Runnable r) {
    //创建消息,且直接设置callback
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

msg.recycle();

publicclass LooperThread extends Thread { 
@Override 
publicvoid run() { 
// 将眼前线程最早化为Looper线程 
Looper.prepare(); 

Message

Message 便是部分须要管理的风浪,比如访谈互联网、下载图片、更新ui分界面什么的。 Message 具有多少个比较关键的质量。

  • public int what 标记符,用来甄别 message
  • public int arg1,arg2 能够用来传递一些轻量型数据如int之类的
  • public Object obj Message 自带的Object类字段,用来传递对象
  • Handler target 指代此 message 对象对应的 Handler

如果指引比价复杂性的多少,提出用 Bundle 封装,具体方法这里不讲了。

值得注意之处是,即便 Message 的布局方法是公有的,不过不建议选用。最棒的格局是行使 Message.obtain(卡塔尔(قطر‎或许 Handler.obtainMessage(卡塔尔能越来越好的使用循环池中的对象。日常不要手动设置 target ,调用 Handler.obtainMessage(State of Qatar 方法会自动的装置 Message 的 target 为当前的 Handler 。

得到 Message 之后能够调用 sendToTarget(卡塔尔 ,发送新闻给 Handler , Handler 再把音讯放到 message queue 的尾巴

+Long.toHexString(ident)+"to 0x"

复制代码代码如下:

Looper

大约, Looper 就是八个关押 message queue 的类。大家直接来看下源码好了。

public class Looper {
    ......

    private static final ThreadLocal sThreadLocal = new ThreadLocal();

    final MessageQueue mQueue;//拥有的消息队列

    ......

    /** Initialize the current thread as a looper.
 * This gives you a chance to create handlers that then reference
 * this looper, before actually starting the loop. Be sure to call
 * {@link #loop()} after calling this method, and end it by calling
 * {@link #quit()}.
 */
    //创建新的looper对象,并设置到当前线程中
    public static final void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }
    ·····
    /**
 * Return the Looper object associated with the current thread. Returns
 * null if the calling thread is not associated with a Looper.
 */
    //获取当前线程的looper对象
    public static final Looper myLooper() {
        return (Looper)sThreadLocal.get();
    }

    private Looper() {
        mQueue = new MessageQueue();
        mRun = true;
        mThread = Thread.currentThread();
    }

    ......
}

由源码可以看到, looper 具有 MessageQueue 的引用,並且须求调用 Looper.prepare(卡塔尔 方法来为当下线程创立 looper 对象。Android注释很详细的表达了那些措施。

This gives you a chance to create handlers that then reference

this looper, before actually starting the loop. Be sure to call

loop() after calling this method, and end it by calling

quit()

也正是说只用在调用完 Looper.prepare(卡塔尔国 之后,在当前的线程创制的 Handler 才干用有日前线程的 looper 。然后调用 loop(卡塔尔国 来打开循环,管理 message .来回顾看一下 loop(卡塔尔(قطر‎ 的源码

public static void loop() {
        final Looper me = myLooper();//获取looper对象
        if (me == null) {
            //若为空则说明当前线程不是LooperThread,抛出异常
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue; 获取消息队列
        .....
        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
            //打印log,说明开始处理message。msg.target就是Handler对象
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            //重点!!!开始处理message,msg.target就是Handler对象
            msg.target.dispatchMessage(msg);

            //打印log,处理message结束
            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }
            .....
        }
    }

很显著,正是三个大的大循环,不断从音讯队列出抽出音讯。然后调用一个很着重的主意 msg.target.dispatchMessage(msg卡塔尔 开首次拍卖卖音讯。 msg.target 便是 message 对应的 handler .其实笔者直接在重新小说到初的定义。 looper 对象管理MessageQueue ,从当中收取 message 分配给相应的 handler 来拍卖。

在分析 msg.target.dispatchMessage(msgState of Qatar 方法从前,先让我们精通下 message 和 handler

综上说述通过handler发出的message犹如下特点:

 

总结

昨日整整都弄精晓了。先调用 Looper.prepare(卡塔尔 使当前线程成为 LooperThread , Looper.loop(卡塔尔 开启循环之后,然后成立 message ,再由 Handler 发送给音讯队列,最终再交由 Handler 管理。上面是合法给出的LooperThread最标准的用法。

class LooperThread extends Thread {
    public Handler mHandler;

    public void run() {
        Looper.prepare();

        mHandler = new Handler() {
            public void handleMessage(Message msg) {
                // process incoming messages here
            }
        };

        Looper.loop();
    }

末段的末段,再提一下,常常在说的主线程也等于UIThread,也是一个LooperThread。那也是干吗我们能在子线程中发送消息,然后在主线程中更新ui。因为 Handler 是在主线程成立的,所以 Handler 关联的是主线程的 looper ,最终给三个更新ui的实例。

 private static Handler handler=new Handler();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.message_activity);  
    new Thread(new Runnable() {                    
        @Override
        public void run() {
            // tvTest.setText("hello word");
            // 以上操作会报错,无法再子线程中访问UI组件,UI组件的属性必须在UI线程中访问
            // 使用post方式设置message的回调
            handler.post(new Runnable() {                    
                @Override
                public void run() {
                    tvTest.setText("hello world");                        
                }
            });                                
        }
    }).start();
}

上边给出sample代码,仅供参照他事他说加以考查:

 

Android异步消息机制结构

Android异步消息管理构造,其实没那么复杂。轻松的话正是 looper 对象拥有message queue ,况兼担任从 message queue 中抽取音信给 handler 来管理。同不正常候 handler 又承受发送 message 给 looper ,由 looper 把 message 增多到 message queue 尾巴部分。就四个圈儿。下边给出图解,应该轻松吧?

新蒲京娱乐场 1

由此很明朗 handler 和 looper 是来维系在协同的。要求证实的是,三个message 能够针对同一个 handler ,多少个 handler 也得以本着同多个 looper 。

再有一点很关键,普通的线程是不曾 looper 的,假诺须求 looper 对象,那么必须要先调用 Looper.prepare(State of Qatar 方法,何况一个线程只好有二个looper 。调用完之后,此线程就形成了所谓的 LooperThread ,若在时下 LooperThread 中开创 Handler 对象,那么此 Handler 会自动关联到当下线程的 looper 对象,也等于兼具 looper 的引用。

classMyHandlerextendsHandler {

调用loop方法后,Looper线程就起来真的行事了,它不断从友好的MQ中抽取队头的音信(也叫任务卡塔尔(قطر‎执行。其源码深入分析如下:

3.Looper使四个线程变成Looper线程。

作为二个大三的预备程序猿,小编读书android的一大乐趣是可以透过源码学习google大牌们的兼顾观念。android源码中蕴藏了大量的设 计方式,除此以外,android sdk还细心为大家规划了各个helper类,对于和本身同样渴望水平获得进级的人的话,都太值得少年老成读了。那不,明天为了通晓android的音讯处理机 制,笔者看了Looper,Handler,Message那多少个类的源码,结果又叁回被googler的规划震憾了,特与大家狼吞虎咽。

returnresult;

复制代码代码如下:

Handler handler;

自家在小标题中校handler描述为“异步管理大师”,这归功于Handler具有上面多个关键的特色:

super.handleMessage(msg);

publicclass LooperThread extends Thread { 
private Handler handler1; 
private Handler handler2; 

2.post发出的message,其callback为Runnable对象

publicclass SampleTask implements Runnable { 
privatestaticfinal String TAG = SampleTask.class.getSimpleName(); 
Handler handler; 

@Override

quit(State of Qatar方法截止looper循环:

}

public Handler() { 
// 没看懂,直接略过,,, 
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()); 


// 默许将关系当前线程的looper 
mLooper = Looper.myLooper(); 
// looper不可能为空,即该私下认可的布局方法只能在looper线程中接收 
if (mLooper ==null) { 
thrownew RuntimeException( 
"Can't create handler inside thread that has not called Looper.prepare()"); 

// 首要!!!间接把事关looper的MQ作为自身的MQ,由此它的音信将发送到关联looper的MQ上 
mQueue = mLooper.mQueue; 
mCallback =null; 

finalCallback mCallback;

 

//还是日志。。。

privatefinal Message getPostMessage(Runnable r) { 
Message m = Message.obtain(卡塔尔(قطر‎; //取得空的message 
m.callback = r; //将runnable设为message的callback, 
return m; 

Looper.myLooper(卡塔尔国获得当前线程looper对象:

// 此措施用于向关系的MQ上发送Runnable对象,它的run方法就要handler关联的looper线程中施行 
publicfinalboolean post(Runnable r) 

// 注意getPostMessage(r)将runnable封装成message 
return sendMessageDelayed(getPostMessage(r), 0); 

}

什么样是handler?handler扮演了往MQ上增添音信和拍卖消息的剧中人物(只管理由自个儿产生的新闻),即照会MQ它要施行三个职责(sendMessage卡塔尔国,并在loop到和睦的时候试行该任务(handleMessage卡塔尔(قطر‎,整个经过是异步的。handler创设时会关联一个looper,暗中认可的布局方法将关联当前线程的looper,但是那也是能够set的。暗许的结构方法:

publicvoiddispatchMessage(Message msg) {

复制代码代码如下:

if(mCallback!=null) {

到此结束,你应有对Looper有了大旨的问询,计算几点:

风流罗曼蒂克、线程的法力师 Looper

除此而外prepare(State of Qatar和loop(卡塔尔国方法,Looper类还提供了生机勃勃部分实惠的主意,比方

通过地点两行为主代码,普通线程就进级为Looper线程了!!!看看这两行代码各自做了什么。

复制代码代码如下:

@Override

2)Looper.loop()

returnsent;

复制代码代码如下:

Thread.sleep(5000);

publicvoid appendText(String msg) { 
textview.setText(textview.getText() +"n"+ msg); 

sThreadLocal.set(newLooper());

复制代码代码如下:

//将眼下线程开首化为Looper线程

// 处理runnable消息 
privatefinalvoid handleCallback(Message message) { 
message.callback.run(卡塔尔; //直接调用run方法! 

// 由子类完结的钩方法 
publicvoid handleMessage(Message msg) { 

}

// 种种Looper对象中有它的音讯队列,和它所属的线程 
private Looper() { 
mQueue =new MessageQueue(); 
mRun =true; 
mThread = Thread.currentThread(); 

mRun=true;

复制代码代码如下:

mQueue=newMessageQueue();

新蒲京娱乐场 2              

}

 

Looper的字面意思是“循环者”,它被设计用来使一个日常线程形成Looper线程。所谓Looper线程正是循环专门的工作的线程。在前后相继开拓中(尤其是GUI开垦中),常常会须要二个线程不断循环,生机勃勃旦有新职分则施行,试行完继续伺机下贰个职分,那正是Looper线程。使用Looper类成立Looper线程非常粗略,代码如下:

class MyHandler extends Handler { 
@Override 
publicvoid handleMessage(Message msg) { 
String result = msg.getData().getString("message"); 
// 更新UI 
appendText(result); 


privateLooper() {

2.例如你的message只需求指引简易的int消息,请优先选用Message.arg1和Message.arg2来传递音信,那比用Bundle更外省部存款和储蓄器

新蒲京娱乐场,}

能够看出,叁个线程能够有几个Handler,可是只可以有一个Looper!

publicclassSampleTaskimplementsRunnable {

// 实例化多少个handler 
handler1 =new Handler(); 
handler2 =new Handler(); 

//各类Looper对象中有它的新闻队列,和它所属的线程

那就消除了android最精髓的不可能在此外非主线程中更新UI的主题素材。android的主线程也是二个looper线程(looper 在android中运用很广卡塔尔(قطر‎,我们在其间创制的handler暗许将涉嫌主线程MQ。由此,利用handler的一个solution就是在 activity中开创handler并将其引述传递给worker thread,worker thread施行完义务后使用handler发送音信布告activity更新UI。(进度如图State of Qatar

}

 

}

异步管理大师 Handler

else{

因此地方两行为主代码,你的线程就进级为Looper线程了!!!是否超美妙?让我们放缓镜头,看看这两行代码各自做了怎么。

Thread mThread;

1.即便Message有public的暗中同意布局方法,不过你应有经过Message.obtain(卡塔尔国来从音讯池中得到空音信对象,以节省财富。

finallongident=Binder.clearCallingIdentity();

新蒲京娱乐场 3

+msg.callback);

public SampleTask(Handler handler) { 
super(); 
this.handler = handler; 

returnmThread;

线程的法力师 Looper

}

public Thread getThread() { return mThread; }

finalLooper mLooper;//关联的looper

上边给出sample代码,仅供参谋

if(me.mLogging!=null) me.mLogging.println(

publicfinalbooleanpost(Runnable r)

 

}

2.Looper内部有一个消息队列,loop(卡塔尔方法调用后线程初叶不住从队列中收取音讯实行

publicSampleTask(Handler handler) {

新蒲京娱乐场 4

thrownewRuntimeException("Only one Looper may be created per thread");

publicclass Looper { 
// 每种线程中的Looper对象实际是几个ThreadLocal,即线程本地存款和储蓄(TLS卡塔尔国对象 
privatestaticfinal ThreadLocal sThreadLocal =new ThreadLocal(); 
// Looper内的消息队列 
final MessageQueue mQueue; 
// 当前线程 
Thread mThread; 
// 。。。别的属性 

privateHandler handler2;

 

Handler管理音信

// ...其他管理,如实例化handler 

//要是message未有callback,则调用handler的钩子方法handleMessage

复制代码代码如下:

appendText(result);

}

上面我们就能够为事情发生前的LooperThread类参与Handler:

finalMessageQueue mQueue;

 

{

装进任务 Message

//回收message资源

 

publicvoidrun() {

3.Looper使八个线程产生Looper线程。

message.callback.run(卡塔尔(قطر‎;//直接调用run方法!

Handler管理音讯

1.各样线程有且最三只可以有叁个Looper对象,它是三个ThreadLocal

@Override 
publicvoid run() { 
// 将日前线程初始化为Looper线程 
Looper.prepare(); 

try{//模拟施行某项职务,下载等

其他措施就不列项支出了,简单来讲通过handler发出的message好似下特点:

(klass.getModifiers()&Modifier.STATIC)==0) {

新蒲京娱乐场 5

+msg.callback+":"+msg.what

@Override 
protectedvoid onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.main); 
澳门新莆京手机网站,textview = (TextView) findViewById(R.id.textview); 
// 创设并运营职业线程 
Thread workerThread =new Thread(new SampleTask(new MyHandler())); 
workerThread.start(); 

看源码。

msg.target.dispatchMessage(msg);

}

因此源码,prepare(卡塔尔背后的职业方法一望而知,其主导正是将looper对象定义为ThreadLocal。要是你还不清楚怎么着是ThreadLocal,请参谋《通晓ThreadLocal》。

}catch(InterruptedException e) {

有了handler之后,大家就能够利用 post(Runnable)postAtTime(Runnable, long)postDelayed(Runnable, long)sendEmptyMessage(int)sendMessage(Message)sendMessageAtTime(Message, long)和 sendMessageDelayed(Message, long)这一个方法向MQ上发送新闻了。光看这个API你大概会以为handler能发二种音讯,生龙活虎种是Runnable对象,风流倜傥种是message对象,那是直观的了然,但实在post发出的Runnable对象最终都被封装成message对象了,见源码:

2.Looper内部有多少个新闻队列,loop(卡塔尔(قطر‎方法调用后线程最早再三从队列中收取消息试行

新蒲京娱乐场 6

handleMessage(msg);

// 开端循环管理音讯队列 
Looper.loop(); 

if(FIND_POTENTIAL_LEAKS) {

Handler发送信息

/*这种艺术允许让activity等来落到实处Handler.Callback接口,制止了合力攻敌编排handler重写handleMessage方法。*/

 

  • Long.toHexString(ident) +" to 0x" 
  • Long.toHexString(newIdent) +" while dispatching to " 
  • msg.target.getClass().getName() +"" 
  • msg.callback +" what="+ msg.what); 

    // 回收message资源 
    msg.recycle(); 


}

// 管理音讯,该办法由looper调用 
publicvoid dispatchMessage(Message msg) { 
if (msg.callback !=null) { 
// 如果message设置了callback,即runnable消息,处理callback! 
handleCallback(msg); 
} else { 
// 假使handler本人设置了callback,则举行callback 
if (mCallback !=null) { 
/* 这种格局允许让activity等来促成Handler.Callback接口,幸免了协和编写handler重写handleMessage方法。见 */ 
if (mCallback.handleMessage(msg)) { 
return; 


// 假若message未有callback,则调用handler的钩方法handleMessage 
handleMessage(msg); 

}

Looper的字面意思是“循环者”,它被规划用来使一个习以为常线程形成Looper线程。所谓Looper线程就是循环职业的线程。在程序支付中(特别是GUI开拓中),大家平常会须求叁个线程不断循环,少年老成旦有新职务则进行,实行完继续守候下三个职务,那正是Looper线程。使用Looper类成立Looper线程很简短:

}

publicvoid quit() { 
// 创立一个空的message,它的target为NULL,表示结束循环音信 
Message msg = Message.obtain(); 
// 发出音讯 
mQueue.enqueueMessage(msg, 0); 

finalClassklass=getClass();

final MessageQueue mQueue; // 关联的MQ 
final Looper mLooper; // 关联的looper 
final Callback mCallback; 
// 其余质量 

handler2=newHandler();

1)Looper.prepare()

publicThread getThread() {

 

//处理runnable消息

3.擅用message.what来标记音讯,以便用区别方法管理message。

}

publicclass TestDriverActivity extends Activity { 
private TextView textview; 

到此截至,你应当对Looper有了基本的摸底,总括几点:

2.handler是在它波及的looper线程中管理消息的。

}

复制代码代码如下:

msg.target=this;//message的target必需设为该handler!

复制代码代码如下:

//试图在有Looper的线程中另行创设Looper将抛出极度

1.handler可以在任性线程发送新闻,那一个信息会被增添到关联的MQ上。

publicclassLooper {

2.post发出的message,其callback为Runnable对象

result.setData(data);

from:

"<<<<< Finished to"+msg.target+""

  • msg.callback +": "+ msg.what 
    ); 
    // 相当的重大!将真正的拍卖专门的学业交给message的target,即后边要讲的handler 
    msg.target.dispatchMessage(msg); 
    // 依旧日志。。。 
    if (me.mLogging!=null) me.mLogging.println( 
    "<<<<< Finished to "+ msg.target +"" 
  • msg.callback); 

setContentView(R.layout.main);

Handler的用处

Looper.loop();

publicstaticfinalvoid loop() { 
Looper me = myLooper(卡塔尔(قطر‎; //获得当前线程Looper 
MessageQueue queue = me.mQueue; //获得当前looper的MQ 

handler被描述为“异步管理大师”,那归功于Handler具有上边多少个主要的特色:

这正是说,我们怎么往MQ上增加新闻吧?上面有请Handler!(掌声~~~)

switch (msg.what) {

android的音讯管理有多个大旨类:Looper,Handler和Message。其实还会有二个Message Queue(音讯队列),但是MQ棉被服装进到Looper里面了,大家不会从来与MQ打交道,因而我没将其当作着力类。下目生机勃勃一介绍:

}

// 别的情势 

mLooper=Looper.myLooper();

// 下边没看懂,同样不影响明白 
finallong newIdent = Binder.clearCallingIdentity(); 
if (ident != newIdent) { 
Log.wtf("Looper", "Thread identity changed from 0x" 

+msg.target.getClass().getName()+""

// 大家调用该方法会在调用线程的TLS中创建Looper对象 
publicstaticfinalvoid prepare() { 
if (sThreadLocal.get() !=null) { 
// 试图在有Looper的线程中重复创制Looper将抛出拾分 
thrownew RuntimeException("Only one Looper may be created per thread"); 

sThreadLocal.set(new Looper()); 

// 其他办法 

Log.w(TAG,"The following Handler class should be static or leaks might occur:"+

在全体消息管理体制中,message又叫task,封装了义务指点的消息和管理该职责的handler。message的用法比较轻便,这里不做总括了。然则有与上述同类几点必要在意(待补充):

上一篇:没有了 下一篇:没有了

Copyright © 2015-2019 http://www.carrefourstation.com. 澳门新莆京手机网站-新蒲京娱乐场有限公司 版权所有