转载请注明出处:http://blog.csdn.net/mr_liabill/article/details/48373779 来自《LiaBin的博客》
Handler
Handler使用子线程looper
public class MyThread extends Thread {
private Handler handler;
@Override
public void run() {
super.run();
//此时当前线程跟looper绑定,如果没调用这个方法,那么
//handler = new Handler();就会抛出Can't create handler inside thread that has not called Looper.prepare()异常
Looper.prepare();//此时生成的loop对象可以通过Looper.myLooper()获取。实际调用sThreadLocal.set(new Looper(quitAllowed));
//Handler无参数的构造函数内部调用了mLooper= Looper.myLooper();
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
Log.d("LiaBin", "MyThread handleMessage");
}
};
//handler = new Handler(Looper.myLooper());//等价于上面的语法,都是获取当前线程的looper
Looper.loop();//开启循环取消息
}
//提供一个退出方法,否则Loop方法在无限循环,MyThread终止不了
public void quit() {
if (Looper.myLooper() != null) {
Looper.myLooper().quit();
}
}
public Handler getHandler() {
return handler;
}
}
如果此时main线程想给这个线程发消息
MyThread myThread = new MyThread();
myThread.start();
//发送消息到myThread线程对应的looper队列中
myThread.getHandler().sendEmptyMessage(0);
此时注意:myThread线程一直在run,除非调用quit方法
另一方面:
handler = new Handler(Looper.getMainLooper());//获取main线程的looper
handler.sendEmptyMessage(0);//消息被发送到main线程中,然后处理
Handler使用main线程looper
public class TestActivity extends AppCompatActivity {
private Handler handler= new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
handler.sendEmptyMessage(0);
new TestThread(handler).start();
}
}
public class TestThread extends Thread {
private Handler handler;
public TestThread(Handler handler) {
this.handler = handler;
}
@Override
public void run() {
super.run();
//dosomething...
handler.sendEmptyMessage(0);
}
}
此时实际上handler是在main线程中创建,默认使用的是main线程的looper,所以消息在main线程中处理
activity是运行在main线程中的,启动任何一个activity,首先都会调用ActivityThread的main方法,可以看到调用了prepareMainLooper为mian线程创建了looper,之后Looper.loop()。
public static void main(String[] args) {
..............
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");
}
}
post方法
public void onClick(View v){
new Thread(new Runnable(){
public void run(){
final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");
handler.post(new Runnable(){
public void run(){
mImageView.setImageBitmap(bitmap);
}
});
}
}).start();}
handler的post方法接受一个runnable参数,但是不是runnable实际上是运行handler对应的线程中的,而不是子线程,注意区分Thread和Runnable的区别
总结
1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。
2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。
3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。
4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。
5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;//mQueue跟上面的looper一一对应
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);//把这个msg放到looper对应的消息队列中了
}
Looper
几个静态方法
Looper.perpare() Thread中调用,那么就为当前线程绑定了looper,如果在activity,service等中调用,那么就是为main线程绑定looper,此时这样调用是多余了,因为在main线程中早已经执行了prepareMainLooper方法
Looper.myLooper() Thread中调用,那么获取的就是当前线程perpare创建的looper,如果是在activity,service等中调用,那么其实是等效于getMainLooper的,因为返回的都是main线程的looper
Looper.prepareMainLooper() 赋值main线程的looper,sMainLooper = myLooper();如果在子线程中就不要调用这个方法了,而是调用perpare方法
Looper.getMainLooper() 获取main线程的looper,如果需要在子线程中发送消息到main线程,如果不想把handler参数传进来,那么可以使用Handler hander=new Handler(Looper.getMainLooper())
quit/quitSafely looper的消息队列不再接收消息,所以此时再用handler发消息是接收不到的
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
public static
@Nullable
Looper myLooper() {
return sThreadLocal.get();
}
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;
for (; ; ) { //不间断的取消息
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
msg.target.dispatchMessage(msg);
...........
}
}
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
activity,sercice等默认都是运行在main线程中的
public final class ActivityThread {
......
public static final void main(String[] args) {
......
Looper.prepareMainLooper();
......
ActivityThread thread = new ActivityThread();
thread.attach(false);
......
Looper.loop();
......
thread.detach();
......
}
}
所以如果以下代码
public class TestActivity extends AppCompatActivity {
private Handler handler= new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
}
}
此时handler发送的消息是在main线程中处理的,handler没有参数的构造函数默认调用如下方法
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();
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;
}
mLooper = Looper.myLooper();//获取当前线程的looper,因为当前线程是main线程,所以handler发送的消息是在main线程中处理的
注意区分,handler在activity,service中创建还是在Thread内部创建的区别
MessageQueue
面试有提到MessageQueue的原理,当即就说,不就是一个简单的队列呗,先进先出,那这个message什么时候进什么时候出队列,比如以下两行伪代码
sendMessageDelayed(msg1,5000);
sendMessage(msg2);
此时msg1和msg2谁先进消息队列,这个时候我就犯难了,直觉告诉我,应该是msg2先进队列,因为最后肯定是msg2先被处理的,先进先出嘛。。
面试官再问真是这样么,如果我此时再sendMessageDelayed(msg3,2000);那么msg3在队列的什么位置,msg1,msg3怎么先后处理,然后就GG了
Handler.MessageQueue源码分析
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
不管是sendMessage,post还是sendMessageDelayed,postDelayed最后都进入sendMessageAtTime方法,
SystemClock.uptimeMillis() + delayMillis
这段代码是关键,把系统当前时间+delay的时间作为参数传递下去
继续往下分析,调用了queue.enqueueMessage
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
进入MessageQueue类,注意when参数,就是上面的SystemClock.uptimeMillis() + delayMillis
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;
}
这下终于豁然开朗了
Message p = mMessages; //mMessages应该就是队列的头节点了
如果刚进来消息的when比头结点的when还小,那么把这个message当作头节点,否则,则在队列中根据when来判断插入合适的位置。并不是按照进来一个消息就放在队列尾这种方式
如此一来,就能解决上面的疑惑了,
sendMessageDelayed(msg1,5000);
sendMessage(msg2);sendMessageDelayed(msg3,2000);
还是按照send的先后顺序进队列,msg1,msg2,msg3,但是队列中的位置却是
尾 msg1 msg3 msg2 头
所以最后handlemessage的先后顺序是msg2 msg3 msg1
我们都知道Loop.loop()不断的通过messagequeue.next()从消息队列中取消息。在来看看messagequeue的next方法,下面抽取关键代码段
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
final long now = SystemClock.uptimeMillis();表示的是当前时间
如果队列头结点的when比now当前时间还大,说明还没到delay的时间,return null,否则才处理这个message
总结
最后总结一下:
1. MessageQueue 通过链表方式实现
2. message插入到队列的哪个位置,是通过时间点来判断,SystemClock.uptimeMillis() + delayMillis(当前时间+delay时间),这个时间点越大越在队列的后部,越晚handler
3. 严格来说MessageQueue先进先出并不准确,因为并不是简单的插入到队列尾