Android 根据源码详细讲解Handler

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


 * 
 * <p>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)入队在一个不同的线程上执行的动作。
 
 
 * 
 * <p>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 <em>post</em> versions allow you to enqueue Runnable objects to be called by the message queue when they are received; 
 * the <em>sendMessage</em> 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方法所处理
 
 
 * 
 * <p>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,您可以当消息队列准备就绪时,允许处理该项。或者在它被处理之前或者在绝对时间之前指定一个延迟。
 * 后两者允许您实现超时、记号、和其他基于时间的行为。
 * 
 * <p>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 <em>post</em> or <em>sendMessage</em> 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 flag
			sPoolSize--;
			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}.
 *
 * <p>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.next
			prev.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 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 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 libcore
	EventLogger.setReporter(new EventLoggingReporter());

	AndroidKeyStoreProvider.install();

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

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

	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。



扫码关注,共同进步

















猜你喜欢

转载自blog.csdn.net/Aminy123/article/details/80967789