首先我从ui线程的调用过程中开始分析。
(1) 在ui线程中系统会初始化一个looper对象,源码中在activityThread中的main方法中调用了Looper.prepareMainLooper()方法对looper进行初始化,并且调用loop方法开始执行无限循环的中messagequeue中获取msg并利用handler发送(这个源码下面会说)。
public static void main(String[] args) {
SamplingProfilerIntegration.start();
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
EventLogger.setReporter(new EventLoggingReporter());
Security.addProvider(new AndroidKeyStoreProvider());
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper(); //这也是为什么ui线程中不需要执行prepare及loop方法的理由了
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
(2)在调用prepareMainLooper的时候会调用prepare方法:
sMainLooper的声明为private static Looper sMainLooper; 即当前线程的looper对象,从static 和下面贴出的looper的私有构造函数可以知道looper是单例的。
sThreadLocal声明为static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();可以理解为用来保存looper的对象。
mylooper()是调用的sThreadLocal.get(),来获取保存的looper对象
public static void prepareMainLooper() {
prepare(false); //创建looper对象及MessageQueue
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper(); //获取looper对象
}
}
prepare方法中进行了对looper的判断,如果当looper存在的时候继续调用prepare方法时就会抛出Only one Looper may be created per thread的运行异常,这就是为什么一个线程只能拥有一个looper的原因了。
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) { //使其保证一个线程只拥有一个looper
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
而在looper的构造函数之中,我们会创建一个MessageQueue对象,因为上面的代码保证了sThreadLocal即looper的唯一性,所以MessageQueue也是唯一的。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread(); //保存当前线程,在使用时可以用来获取或者判断是否为当前本地线程
}
那么我们现在得到了用来管理message的messagequeue,和用来取出message的looper对象。
(3)调用loop方法,利用死循环来不断获取messagequeue中的message
public static void loop() {
final Looper me = myLooper(); //获取当前线程的looper对象
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue; //获取当前线程的消息队列
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // 获取消息队列的下一个消息,如果没有消息,将会阻塞
if (msg == null) {
//如果消息为null,直接退出循环,表示消息队列正在退出。
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg); //点过去就知道了msg.target为handler对象,下面会讲此方法。
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
//保证在分发消息的过程中线程标识符不会被修改
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.recycle(); //释放资源
}
}
(4)上面的可以简单的理解为,ui线程会自己调用looper.prepare方法来初始化looper及messagequeue,然后调用loop方法,通过无限循环来利用looper对象取出保存在messagequeue中的message对象,然后利用handler处理消息。
那么现在看下msg.target.dispatchMessage(msg);是怎么运行的,首先知道msg.target即为一个handler对象,dispatchMessage方法点进去之后会调用handleMessage
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
handleMessage在源码中就是个空方法,每次我们新建handler对象的时候都会重写此方法,进行操作。这就是完整的消息机制。
而在handler.sendMessage方法中会执行一步一步的执行到enqueueMessage方法,在这个方法中会间msg.target赋值为handler,之后将其中的message保存到messagequeue之中。然后通过loop的无限循环可以使其执行dispatchMessage方法,取出队列中的对象,进行处理。
那么在不是ui线程中想要利用handler消息机制的话,那么就必须自己调用prepare和loop方法了,如下:
public void looper()
{
new Thread()
{
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
//非主线程中默认没有创建looper对象
//Toast.makeText(mContext, "不可以打toast", 0).show();
Looper.prepare();
Toast.makeText(mContext, "可以打toast", 0).show();
Looper.loop();
}
}.start();
}
总结下: 1.调用prepare()方法创建looper对象及其对应的messagequeue
2.创建handler对象来通过其sendMessage方法发送message到messagequeue中。
3.通过loop方法中的无限循环以先进先出的原则来通过handler对象的handleMessage方法来处理消息