Handler消息通信机制的使用及源码解析,Looper的工

一、Handle原理图

图片 1handle流程图.png

经过地点绘制的流程图,大家实际能够知道handle精晓起来不是很难。上边具体讲授一下应用流程

如何利用Handler,为啥要动用Handler,几时利用Handler?

二、Handler、Message、MessageQueue、Looper方法及品质

  1. Handler.java:(3个属性,10个方法)3个属性:
final MessageQueue mQueue;封装好的消息被handler发送出去,其实就是将消息放到消息队列中去final Looper mLooper;每一个handler都有一个looper为其不断接收消息队列中的消息,并返回给handler。final Callback mCallback; 被handler接收到的消息要通过Callback接口中的handleMessage()方法来进行处理。

10个方法:

public boolean handleMessage(Message msg); Callback接口中的handleMessage()方法,用来处理返回给handler的消息的。public final Message obtainMessage(); 获取Message对象,其本质还是调用Message类的obtain()方法来获取消息对象。public final boolean sendMessage(Message msg) 发送消息public final boolean sendEmptyMessage 发送只有what属性的消息,就是发送空白消息public final boolean post(Runnable r) 发送消息public final boolean postAtTime(Runnable r, long uptimeMillis) 定时发送消息public final boolean postDelayed(Runnable r, long delayMillis) 延迟发送消息public void dispatchMessage(Message msg) 分发消息,当Looper循环接收消息队列中的消息时,就在不断调用handler的分发消息方法,从而触发Callback接口中的消息处理方法handleMessage()来对消息进行处理。public final boolean sendMessageDelayed(Message msg, long delayMillis) sendMessage()就是在调用延时发送消息的方法。public boolean sendMessageAtTime(Message msg, long uptimeMillis) 延时发送消息的方法就是在调用定时发送消息的方法。private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) 将消息压入消息队列中
  1. MessageQueue.JAVA:
final boolean enqueueMessage(Message msg, long when) handler发送的消息正是通过该方法被加进了消息队列中。因为消息队列中有消息,从而触发了Looper通过loop()方法循环接收所有的消息。final Message next();
  1. Looper.JAVA:(1个属性,5个方法)3个属性
 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); 正是由于该线程本地变量,保证了一个线程中只能保存一个Looper对象,也就是说一个Thread中只能有一个Looper对象。

5个方法:

public static void prepare() 每个handler所在的线程都必须有一个Looper提前准备好。public static void prepareMainLooper() 主线程中的的Looper已经被自动准备好。而该方法不需要手工调用。public static Looper getMainLooper() 获取主线程中的Looper对象public static void loop() Looper的作用就是循环接收消息队列中的消息。该方法中执行了一个无限循环。public static Looper myLooper() 该方法的作用是从线程本地变量中获取到当前线程的Looper对象。
  1. Message.java:(10个属性,7个方法)10个属性:
public int what; 该属性一般用来标识消息执行的状态。public int arg1; 用来存放整型数据的属性。public int arg2; 用来存放整型数据的属性。public Object obj; 用来存放复杂消息数据的属性。Bundle data; 用来存放复杂消息数据的属性。Handler target; 标识该消息要被发送给哪个Handler对象。Message sPool; 消息池中的每个消息对象。int sPoolSize; 记录消息池中剩余消息的数量。int MAX_POOL_SIZE=50; 消息池中最大消息数量。Messenger replyTo; 定义消息的信使对象,将来可以用于跨APP的消息传递。

7个方法:

public static Message obtain() 从消息池中获取消息对象。public void recycle() 往消息池中归还消息对象。public void setTarget(Handler target) 给消息设置接收该消息的目标handler对象。public Handler getTarget() 获取消息的接收handler对象。public void sendToTarget() 将消息发送到目标handler对象。其本质是调用handler对象的sendMessage()方法来发送当前消息对象。public void setData(Bundle data) 将Bundle对象设置到message对象中Bundle属性中。public Bundle getData() 从消息对象中获取Bundle属性的数据。

在Android中系统明显主线程(UI线程)不可能围堵超过5s,不然会出现"Application Not Responding"。约等于说,你无法在主线程中展开耗费时间操作(互联网供给,数据库操作等),只好在子线程中开展。举例通过互连网供给从服务端重返的数量须要更新UI,那时候就用到了Handler(因为handler可开展线程间的简报)。

消息传递机制中各艺术之间的实施顺序

图片 2音讯传递顺序.png

Handler有四大意素:

Handler、Mesage、Message Queue、Looper

Handler
概念:Handler是Message的第一管理者
作用:
1.担负将Message增添到音信队列中
2.甩卖Looper分派过来的Message

Mesage
概念:Handler接收和处理的新闻对象,能够知道为包装了几许数据的对象
选取:后台线程管理完数据后要求更新UI,可发送一条包含更新音信的Message给UI线程(或有handler的线程)

Message Queue
概念:消息队列
功用:用来贮存在通过Handler发送的音讯,依据先进先出的顺序排列

Looper
概念:循环器,不断的收取MessageQueue中的新闻并传递给Handler
效用:循环抽出MessageQueue的Message,将抽出的Message交付给相应的Handler

注意:各类线程只好具有三个Looper,但八个Looper能够和三个线程的Handler绑定,也正是说两个线程可未来三个Looper所持有的MessageQueue中发送音讯,那给大家提供了线程之间通讯的可能。

地点这么些定义片段摘自互联网

ps:我们在类型中会使用到大气的handler,那时候要是退出Activity的时候肯定要记得销毁handler,并清空新闻和CallBack,

handler.removeCallbacksAndMessages(null);

下面这是官方的解释:意思是说如果参数为null的话,会将所有的Callbacks和Messages全部清除掉。
这样就可以在activity推出的时候调用,有效避免内存泄漏。

Added in API level 1 Remove any pending posts of callbacks and sent 
messages whose obj is token. If token is null, all callbacks and 
messages will be removed.

结语

对此handler其实未有豪门想象的那么难,在常常的干活中,我们使用的时候相当多,日常采纳就能够有不等同的敞亮。最终,接待大家点赞和提问哦!

接下去从源码扒一下Handler的流程:

1.在主线程恐怕贰个子线程中开创Handler对象;
创建Handler的时候它有7个构造方法:

/*
     * Set this flag to true to detect anonymous, local or member classes
     * that extend this Handler class and that are not static. These kind
     * of classes can potentially create leaks.
     */
    private static final boolean FIND_POTENTIAL_LEAKS = false;
    private static final String TAG = "Handler";

    /**
     * Default constructor associates this handler with the {@link Looper} for the
     * current thread.
     *
     * If this thread does not have a looper, this handler won't be able to receive messages
     * so an exception is thrown.
     */
    public Handler() {
        this(null, false);
    }

    /**
     * Constructor associates this handler with the {@link Looper} for the
     * current thread and takes a callback interface in which you can handle
     * messages.
     *
     * If this thread does not have a looper, this handler won't be able to receive messages
     * so an exception is thrown.
     *
     * @param callback The callback interface in which to handle messages, or null.
     */
    public Handler(Callback callback) {
        this(callback, false);
    }

    /**
     * Use the provided {@link Looper} instead of the default one.
     *
     * @param looper The looper, must not be null.
     */
    public Handler(Looper looper) {
        this(looper, null, false);
    }

    /**
     * Use the provided {@link Looper} instead of the default one and take a callback
     * interface in which to handle messages.
     *
     * @param looper The looper, must not be null.
     * @param callback The callback interface in which to handle messages, or null.
     */
    public Handler(Looper looper, Callback callback) {
        this(looper, callback, false);
    }

    /**
     * Use the {@link Looper} for the current thread
     * and set whether the handler should be asynchronous.
     *
     * Handlers are synchronous by default unless this constructor is used to make
     * one that is strictly asynchronous.
     *
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with respect to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
     *
     * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
     *
     * @hide
     */
    public Handler(boolean async) {
        this(null, async);
    }

    /**
     * Use the {@link Looper} for the current thread with the specified callback interface
     * and set whether the handler should be asynchronous.
     *
     * Handlers are synchronous by default unless this constructor is used to make
     * one that is strictly asynchronous.
     *
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with respect to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
     *
     * @param callback The callback interface in which to handle messages, or null.
     * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
     *
     * @hide
     */
    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();  // 得到当前线程的Looper对象,或通过Loop.getMainLooper()获得当前进程的主线程的Looper对象
        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;
    }

    /**
     * Use the provided {@link Looper} instead of the default one and take a callback
     * interface in which to handle messages.  Also set whether the handler
     * should be asynchronous.
     *
     * Handlers are synchronous by default unless this constructor is used to make
     * one that is strictly asynchronous.
     *
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with respect to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
     *
     * @param looper The looper, must not be null.
     * @param callback The callback interface in which to handle messages, or null.
     * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
     *
     * @hide
     */
    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

上边刚开端就告诉大家成立Handler如若不是静态的,会产生内存泄漏的;大家逐条看一下那多少个构造方法。

1.只要空参,不点名Looper对象,那么些Handler会绑定到开创这一个线程的线程上,新闻管理回调也就在在创立线程中实施

PS:主线程中的Loop是在UI线程入口创制的,activity在UI线程中,可是activity而不是UI线程的输入,UI线程入口ActivityThread中,代码如下:

 public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");

        // 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();  // 创建Looper并ThreadLocal.set(looper);绑定

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();   // 创建Handler
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();     // Looper遍历消息队列

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

看源码传送门:https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/java/android/app/ActivityThread.java#L2130

2.多了个CallBack回调接口,那实际上是用来堵住管理音信的。请看上边包车型客车代码:

private static Handler handler =  new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        Toast.makeText(getApplicationContext(),"第一滴血",Toast.LENGTH_SHORT).show();
        return false;
    }
}){
    @Override
    public void handleMessage(Message msg) {
        Toast.makeText(getApplicationContext(),"敢死队",Toast.LENGTH_SHORT).show();
    }
};

ps:在第5行作者return true,结果吐司只显示“第一滴血”。
当return false时,结果吐司先出示“第一滴血”,紧接着展现“敢死队”;那样大家就能够见道,Callback其实是用来阻止管理音信的。

3.运用传进去的looper,通过点名Looper对象进而绑定相应线程,即给Handler钦点Looper对象也便是绑定到了Looper对象所在的线程中。Handler的新闻处理回调会在Looper对象所在线程中试行。

4.同一时候钦命Looper和落实拦阻新闻的回调。

5.暗许景况下都是联合的,调用那么些格局能够安装“是还是不是异步”

6和7和地点是同一的,就多了叁个论断是不是异步的进口。

2.Looper对象的创造和实例化;

/** 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 void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        /**一个线程只能持有一个Looper实例,sThreadLocal保存线程持有的looper对象*/
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        /**sThreadLocal是一个ThreadLocal变量,用于在一个线程中存储变量,这里Looper变量就存放在ThreadLocal里*/
        sThreadLocal.set(new Looper(quitAllowed));
    }

上边我们看看Looper的构造方法:

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed); // 创建Looper时,会自动创建一个与之匹配的MessageQueue
        mThread = Thread.currentThread(); // Looper对应的当前线程
    }

收获当前线程中的looper;

/**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

获取当前线程中Looper所持有的MessageQueue:

/**
     * Return the {@link MessageQueue} object associated with the current
     * thread.  This must be called from a thread running a Looper, or a
     * NullPointerException will be thrown.
     */
    public static @NonNull MessageQueue myQueue() {
        return myLooper().mQueue;
    }

再来看看looper是怎么从MessageQueue 收取音讯,转到达handler的:

/**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
        //myLooper()方法是返回sThreadLocal存储的Looper实例
        final Looper me = myLooper();
        //me==null就会抛出异常,说明looper对象没有被创建,
        //也就是说loop方法必须在prepare方法之后运行,消息循环必须要先在线程中创建Looper实例
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }

        //获取Looper实例中的消息队列mQueue,一个Looper持有一个MessageQueue
        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 (;;) {
            //next()方法用于取出消息队列中的消息,如果取出的消息为空,则线程阻塞,消息队列是一个链表结构
            Message msg = queue.next(); // might block
            //没有message即返回
            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.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            try {
                //把消息派发给msg的target属性,然后用dispatchMessage方法去处理
                msg.target.dispatchMessage(msg);
            } 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);
            }
            //将处理完的Message对象回收,以备下次obtain重复使用。
            msg.recycleUnchecked();
        }
    }

ps:能够看看Looper的效用是:
1.实例化Looper对象自己(prepare()方法),成立与之对应的MessageQueue(looper()构造方法)
2.loop()方法不断从MessageQueue中取新闻,派发给Handler,然后调用相应Handler的dispatchMessage()方法进行新闻管理。

3.在handle中绑定Looper并从MessageQueue中得到信息;
在handle在那之中的二个构造函数中张开获取looper的:

  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());
            }
        }

        //Looper.myLooper()获得了当前线程保存的Looper实例
        mLooper = Looper.myLooper();

        //如果没有looper实例就会抛出异常,这说明一个没有创建looper的线程中是无法创建一个Handler对象的;
        //子线程中创建一个Handler时需要创建Looper,且开启循环才能使用这个Handler
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }

        //获取looper实例的MessageQueue,保证handler实例与looper实例的MessageQueue关联
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

Handler把消息传递到新闻队列中:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        //handler发出的消息最终会保存到消息队列中
        return queue.enqueueMessage(msg, uptimeMillis);
    }

在主线程中Handler是如何创建Looper的;

public static void main(String[] args) {
        ...
        //  通过prepareMainLooper方法为主线程创建一个looper
        Looper.prepareMainLooper();
        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        ...
        // 开启消息循环
        Looper.loop();
        ...
    }

    /**
     * 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()方法用于创建一个looper对象
        //主线程的消息循环是不允许退出的
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

如此那般就总结完毕了线程间的通讯。

案例:

import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

/**
 * 进入今天的话题,弄清楚handler的来龙去脉
 */
public class MainActivity extends AppCompatActivity {
    private static final String TAG  = MainActivity.class.getSimpleName();

    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Log.e(TAG,msg.obj.toString());
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        oneMethod();
    }

    private void oneMethod() {
        new Thread(){
            @Override
            public void run() {
                super.run();
//                Message msg = new Message();
//                Message msg = Message.obtain();//  这里我们的Message 已经不是 自己创建的了,而是从MessagePool 拿的,省去了创建对象申请内存的开销
                Message msg = handler.obtainMessage(); // 这里我们的Message 已经不是 自己创建的了,而是从MessagePool 拿的,省去了创建对象申请内存的开销
                // 所以开发中我们一般建议使用第二种或者第三种方式创建handler,性能好一点
                msg.obj = "111";
                handler.sendMessage(msg);
            }
        }.start();
    }


}

打字与印刷结果:

图片 3

Paste_Image.png

还应该有一种选择what的:

import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import com.fly.customview.customclock.invoke.HandlerTag;

/**
 * 进入今天的课题,弄清楚handler的来龙去脉
 */
public class MainActivity extends AppCompatActivity {
    private static final String TAG  = MainActivity.class.getSimpleName();

    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case HandlerTag.ONE:
                    Log.e(TAG,msg.obj.toString() + "********ONE*******");
                    break;
                case HandlerTag.TWO:
                    Log.e(TAG,msg.obj.toString() + "********TWO*******");
                    break;
                case HandlerTag.THREE:
                    Log.e(TAG,msg.obj.toString() + "********THREE*******");
                    break;
                case HandlerTag.FOUR:
                    Log.e(TAG,msg.obj.toString() + "********FOUR*******");
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        twoMethod();
    }

    private void twoMethod() {
        new Thread(){
            @Override
            public void run() {
                super.run();
                Message msg = handler.obtainMessage(); // 这里我们的Message 已经不是 自己创建的了,而是从MessagePool 拿的,省去了创建对象申请内存的开销
                msg.obj = "第一滴血";
                msg.what = HandlerTag.ONE;
                handler.sendMessage(msg);
            }
        }.start();
    }

}

/**
 * author:fly
 * date:2017.3.14
 * des: Handler的what的标记,因为接口的属性默认是public static final 常量,且必须赋初值
 * modify:
 *
 */
public interface HandlerTag {
    int ONE = 1;
    int TWO = 2;
    int THREE = 3;
    int FOUR = 4;
}

打字与印刷结果:

图片 4

Paste_Image.png

Handler中有三种获得Message的法子,如下:

//方法1  
 Message msg = new Message();  
 msg.what = 1;  
 msg.arg1 = 2;  
 msg.arg2 = 3;  
 msg.obj = "demo";  
 mHandler.sendMessage(msg);  
 //方法2  
 Message msg2 = mHandler.obtainMessage();  
 //obtainMessage();  
 //obtainMessage(what);  
 //obtainMessage(int what,Object obj);   
 //obtainMessage(int what,int arg1,int arg2);  
 //obtainMessage(int what,int arg1,int arg2,Object obj );  
 msg2.what = 1;  
 msg2.arg1 = 2;  
 msg2.arg2 = 3;  
 msg2.obj = "demo";  
 msg2.sendToTarget();  
 //方法3  
 Message msg3 = Message.obtain();  
 msg3.sendToTarget();  

骨子里选用中,经常使用第三种方法照旧第二种办法(其实是同等的,handler.obtainMessage最后也是调用了Message的obtain方法)。

  在Message的官方文档中,有这样一句话:

 While the constructor of Message is public, the best way to get one of these is to call Message.obtain() or one of the Handler.obtainMessage() 

 methods, which will pull them from a pool of recycled objects.

意思是说,虽然Message的构造方法是公共的(可以通过New操作创建一个Message对象),但获取实例最好的方式还是Message.obtain()或者 Handler.obtainMessage() ,这两种方法提供的对象是消息池中那些已经创建但不再使用的对象。节约了内存资源。

总结:
那基本是二个好像生产者花费者的模子,轻巧说假若在主线程的MessageQueue未有音信时,就能够阻塞在loop的queue.next()方法里,这时候主线程会释放CPU财富步向休眠状态,直到有下个音讯进来时候就能够唤起主线程,在2.2 版本从前,那套机制是用大家熟习的线程的wait和notify 来促成的,之后的版本涉及到Linux pipe/epoll机制,通过往pipe管道写端写入数据来唤醒主线程职业。原理类似于I/O,读写是杜绝的,不占用CPU财富。
招待阅读。

本文由365bet体育在线官网发布于网络编程,转载请注明出处:Handler消息通信机制的使用及源码解析,Looper的工

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。