什么是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。



扫码关注,共同进步

Android 根据源码详细讲解Handler_第1张图片
















更多相关文章

  1. Android的消息通知--Notification
  2. android 主线程与分线程 做同步
  3. mono android 非UI线程操作UI线程
  4. 【Android】监听自定义通知栏消息事件
  5. 使用Android消息机制实现点击开始计数和暂停计数
  6. android 监听 USB 拔插广播消息
  7. android 获取联系人和短消息信息
  8. android多线程进度条

随机推荐

  1. 关于android 布局中诡异的AttributeSet
  2. android ksoap用法
  3. Android(安卓)java.lang.NoSuchMethodErr
  4. Android调用百度地图API实现――实时定位
  5. android 群发短信
  6. Unable to start activity ComponentInfo
  7. android,总结,判断应用程序是否切换到后
  8. Monkey测试结果解析(二)
  9. How to set up a link betwteen a real A
  10. Android(安卓)之 setContentView 源码阅