什么是Handler

我们来看一下Handler源码中是怎么说的

/** * A Handler allows you to send and process {@link Message} and Runnable * objects associated with a thread's {@link MessageQueue}.  Each Handler * instance is associated with a single thread and that thread's message * queue.  When you create a new Handler, it is bound to the thread / * message queue of the thread that is creating it -- from that point on, * it will deliver messages and runnables to that message queue and execute * them as they come out of the message queue.  * Handler 允许您发送和处理{@链接消息}和与一个线程的{@ Link MessageQueue}}相关联的Runnable对象。每个Handler * 实例与单个线程和该线程的消息队列关联。当创建新的 Handler 时,它将绑定到线程和该线程正在创建线程的消息队列。 * 从那时起,当它们从消息队列中出来时,Handler将向该消息队列(message queue)传递messages and runnables并执行。 *  * 

There are two main uses for a Handler: (1) to schedule messages and * runnables to be executed as some point in the future; and (2) to enqueue * an action to be performed on a different thread than your own. * 处理程序有两个主要用途: * (1)调度消息和将来执行某个点的runnables; * (2)入队在一个不同的线程上执行的动作。 * *

Scheduling messages is accomplished with the * {@link #post}, {@link #postAtTime(Runnable, long)}, * {@link #postDelayed}, {@link #sendEmptyMessage}, * {@link #sendMessage}, {@link #sendMessageAtTime}, and * {@link #sendMessageDelayed} methods. * The post versions allow you to enqueue Runnable objects to be called by the message queue when they are received; * the sendMessage versions allow you to enqueue a {@link Message} object containing a bundle of data that will be * processed by the Handler's {@link #handleMessage} method (requiring that * you implement a subclass of Handler). * 消息调度是通过#post#postDelayed#sendMessage#sendMessageDelayed这4个方法完成的。 * post版本的方法允许你接收消息队列时调用的可运行对象的队列; * sendMessage版本的方法允许你调用一个包含bundle数据队列,这个bundler数据最终会被Handler子类的handleMessage方法所处理 * *

When posting or sending to a Handler, you can either * allow the item to be processed as soon as the message queue is ready * to do so, or specify a delay before it gets processed or absolute time for * it to be processed. The latter two allow you to implement timeouts, * ticks, and other timing-based behavior. * 当发送到Handler,您可以当消息队列准备就绪时,允许处理该项。或者在它被处理之前或者在绝对时间之前指定一个延迟。 * 后两者允许您实现超时、记号、和其他基于时间的行为。 * *

When a * process is created for your application, its main thread is dedicated to * running a message queue that takes care of managing the top-level * application objects (activities, broadcast receivers, etc) and any windows * they create. You can create your own threads, and communicate back with * the main application thread through a Handler. This is done by calling * the same post or sendMessage methods as before, but from * your new thread. The given Runnable or Message will then be scheduled * in the Handler's message queue and processed when appropriate. * 当为应用程序创建进程时,其主线程专用于运行管理顶级队列的消息队列应用对象(活动、广播接收器等)和他们创造的任何窗口。 * 您可以创建自己的线程,并通过Handler与主线程与之通信。这是在你新的线程里面通过调用相同的POST或sendMessage方法来完成的。 * 然后,给定的可运行或消息将被安排在处理程序的消息队列中,并在适当的时候进行处理。 */

先看一个Handler的应用例子,在一个服务中,发送消息给activity

handler在activity中定义

public class MainActivity extends AppCompatActivity {    private static DemoHandler handler;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);if (handler == null) {            handler = new DemoHandler();        }    }    public class DemoHandler extends Handler {        @Override        public void handleMessage(Message msg) {            switch (msg.what) {                case 0:                    //透传    startActivity(new Intent(MainActivity.this, ScannerActivity.class));                    break;                case 1:                    //推送                    startActivity(new Intent(MainActivity.this, ScannerActivity.class));                    break;            }        }    }    public static void sendMessage(Message msg) {        handler.sendMessage(msg);    }}

service发送消息:

 public class GeTuiIntentService extends GTIntentService {    @Override    public void onReceiveMessageData(Context context, GTTransmitMessage gtTransmitMessage) {        //收到透传消息        String data = new String(gtTransmitMessage.getPayload());        sendMessage(data,0);    }    private void sendMessage(String data, int what) {        Message msg = Message.obtain();        msg.what = what;        msg.obj = data;        MainActivity.sendMessage(msg);    }}

这是我们常见的一种Handler使用方式,sendMessage(msg);

这样我们就简单实现了service和activity之间的通信。

那具体Handler是怎么工作的呢?我们先看一下在执行 new Handler()的时候,查看Handler类,都做了那些工作:

public Handler() {        this(null, false);}
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对象mLooper = Looper.myLooper();if (mLooper == null) {throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");}        //获取Looper中的消息队列        mQueue = mLooper.mQueue;mCallback = callback;mAsynchronous = async;}

由上可以看出,在我们初始化Handler的时候,做了两步工作,获取Looper和MessageQueue两个对象。

那我们在发送消息的时候,又做了哪些工作呢?

Message msg = Message.obtain();msg.what = what;msg.obj = data;MainActivity.sendMessage(msg);
查看Message类:
private static final Object sPoolSync = new Object();private static Message sPool;private static int sPoolSize = 0;private static final int MAX_POOL_SIZE = 50;private static boolean gCheckRecycle = true;/** * Return a new Message instance from the global pool. Allows us to * avoid allocating new objects in many cases. */public static Message obtain() {synchronized (sPoolSync) {if (sPool != null) {Message m = sPool;sPool = m.next;m.next = null;m.flags = 0; // clear in-use flagsPoolSize--;return m;}}return new Message();}
创建一个message对象,如果sPool!=null时,返回已有message对象。返回对象之后,给message的what和obj参数赋值。

这两个参数啥意思啊?请看源码解释:

 /** * User-defined message code so that the recipient can identify * what this message is about. Each {@link Handler} has its own name-space * for message codes, so you do not need to worry about yours conflicting * with other handlers. *///用户自己定义的消息码,以便接收方可以识别该消息是关于什么的。每一个Handler都有它自己消息码的名称空间,因此你不必担心与其他Handler发生冲突。 public int what;/** * An arbitrary object to send to the recipient.  When using * {@link Messenger} to send the message across processes this can only * be non-null if it contains a Parcelable of a framework class (not one * implemented by the application).   For other data transfer use * {@link #setData}. * * 

Note that Parcelable objects here are not supported prior to * the {@link android.os.Build.VERSION_CODES#FROYO} release. *///要发送给接收者的任意对象。当使用Messenger跨进程发送消息时,如果它包含一个序列化的framework class,这个对象不能为空 public Object obj;

说白了,一个是消息码,一个是消息,消息码来标记消息是干嘛用的。

继续看 handler.sendMessage(msg);方法,大概意思是把一个消息推到消息队列的尾部,这个消息会在连接到这个Handler的线程中的handleMessage方法中接收到。

/** * Pushes a message onto the end of the message queue after all pending messages * before the current time. It will be received in {@link #handleMessage}, * in the thread attached to this handler. *   * @return Returns true if the message was successfully placed in to the  *         message queue.  Returns false on failure, usually because the *         looper processing the message queue is exiting. */public final boolean sendMessage(Message msg){return sendMessageDelayed(msg, 0);}public final boolean sendMessageDelayed(Message msg, long delayMillis){if (delayMillis < 0) {delayMillis = 0;}return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);}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);}

传入当前消息、消息所在消息队列、uptimeMillis,到enqueueMessage()

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {msg.target = this;if (mAsynchronous) {msg.setAsynchronous(true);}return queue.enqueueMessage(msg, uptimeMillis);}

msg.target = this; 目的是给msg绑定Handler

这时候,msg中已经赋值对象有:what(标记)、obj(数据)、target(Handler)

最后执行消息队列MessageQueue中的 enqueueMessage方法,传入msg。

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.nextprev.next = msg;}// We can assume mPtr != 0 because mQuitting is false.if (needWake) {nativeWake(mPtr);}}return true;}

通过上文分析,我们已经知道,Handler在创建的时候,初始化了一个Looper,那么Looper里面做了哪些工作呢?

/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the 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 (;;) {                //取走消息                Message msg = queue.next(); // might blockif (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 loggerfinal Printer logging = me.mLogging;if (logging != null) {logging.println(">>>>> Dispatching to " + msg.target + " " +msg.callback + ": " + msg.what);}final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;final long traceTag = me.mTraceTag;if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {Trace.traceBegin(traceTag, msg.target.getTraceName(msg));}final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();final long end;//发给目标处理try {msg.target.dispatchMessage(msg);end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();} finally {if (traceTag != 0) {Trace.traceEnd(traceTag);}}if (slowDispatchThresholdMs > 0) {final long time = end - start;if (time > slowDispatchThresholdMs) {Slog.w(TAG, "Dispatch took " + time + "ms on "+ Thread.currentThread().getName() + ", h=" +msg.target + " cb=" + msg.callback + " msg=" + msg.what);}}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()进入循环模式,知道msg==null,退出循环。注意中间的 msg.target.dispatchMessage(msg); 方法。调用的是Handler的dispatchMessage(msg);方法,传入消息。

/** * Subclasses must implement this to receive messages. */public void handleMessage(Message msg) {}/** * Handle system messages here. */public void dispatchMessage(Message msg) {if (msg.callback != null) {handleCallback(msg);} else {if (mCallback != null) {if (mCallback.handleMessage(msg)) {return;}}handleMessage(msg);}}

在handleMessage方法汇总处理消息!

至此,一个完整的消息处理流程已经梳理完毕。

总结一下:

一个完整的Handler消息处理一共涉及4个类:

Handler:消息辅助类,主要功能是向消息池发送消息事件(4种发送方式),和处理相应消息事件handleMessage。

Message:消息载体类,主要参数有消息码、消息内容、绑定Handler

MessageQueue:消息队列,主要向消息池投递消息(MessageQueue.enqueueMessage)和取走消息(MessageQueue.next)。

Looper:不断循环执行(Looper.loop),按分发机制将消息分发给目标处理者。



Handler通过sendMessage()发送Message到MessageQueue队列;

Looper通过loop(),不断提取出达到触发条件的Message,并将Message交给target来处理;

经过dispatchMessage()后,交回给Handler的handleMessage()来进行相应地处理。

将Message加入MessageQueue时,处往管道写入字符,可以会唤醒loop线程;如果MessageQueue中没有Message,并处于Idle状态,则会执行IdelHandler接口中的方法,往往用于做一些清理性地工作。




tip:为啥:主线程中创建Handler不需要调用Looper.prepare();和Looper.loop();方法;而在子线程中创建Handler需要调用这两个方法呢?

细心的你可能会发现,在Looper类的源码中,给我们提供了一个使用这两个方法创建Handler的例子:

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

而我们给出的在主线程中的例子没有这两个方法,也许我们可以去看一下主线程的源码来查一下其中的原因。找到ActivityThread.java源码:找到main函数:

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 libcoreEventLogger.setReporter(new EventLoggingReporter());AndroidKeyStoreProvider.install();// Make sure TrustedCertificateStore looks in the right place for CA certificatesfinal File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());TrustedCertificateStore.setDefaultUserDirectory(configDir);Process.setArgV0("");Looper.prepareMainLooper();ActivityThread thread = new ActivityThread();thread.attach(false);if (sMainThreadHandler == null) {sMainThreadHandler = thread.getHandler();}if (false) {Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));}// End of event ActivityThreadMain.Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");}
/** * 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();}}
这下明白了,主线程汇总已经调用了这两个方法!


Looper类用来为一个线程开启一个消息循环。    
默认情况下android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环。)   
Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue。



扫码关注,共同进步

















更多相关文章

  1. 【Android】Android(安卓)SurfaceFlinger之SurfaceFlinger启动过
  2. Android的消息通知--Notification
  3. Android(安卓)的ANR 问题解决
  4. mono android 非UI线程操作UI线程
  5. android:Handler MessageQueue Looper分析
  6. android 主线程与分线程 做同步
  7. android 通过handler实现异步处理
  8. android 监听 USB 拔插广播消息
  9. Softap热点原理分析

随机推荐

  1. [随时更新] Android小问题记录
  2. Android技术分享
  3. 【Android测试】Android抓包解析全过程
  4. Android(安卓)Protect-0.签名相关
  5. Android抓包工具使用与错误
  6. Android(安卓)7.1 bootchart触发后导致不
  7. Android(安卓)MVP 详解(下)
  8. Android,一个函数实现计步器(软计步,硬计
  9. WindowManger与window之基础篇
  10. Android仿饿了么搜索功能