首先我们来看看Handler更新UI线程一般使用
首先要进行Handler 申明,复写handleMessage方法( 放在主线程中)
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO 接收消息并且去更新UI线程上的控件内容
if (msg.what == UPDATE) {
// 更新界面上的textview
tv.setText(String.valueOf(msg.obj));
}
super.handleMessage(msg);
}
};
子线程发送Message给ui线程表示自己任务已经执行完成,主线程可以做相应的操作了。
new Thread() {
@Override
public void run() {
// TODO 子线程中通过handler发送消息给handler接收,由handler去更新TextView的值
try {
//do something
Message msg = new Message();
msg.what = UPDATE;
msg.obj = "更新后的值" ;
handler.sendMessage(msg);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
我们通过画图来了大体解一下handler的消息机制
先看左侧我们通过handler来发消息,这个实在子线程中的。handler可以创建多个,假设我们创建两个handler为handler1和handler2.每个handler都可以向消息队列发消息。handler1发送消息后到消息队列,假设消息为msg1.handler2也会发送消息排在消息队列的msg。但是消息队列是唯一的,消息队列会按照时间排序。消息队列依次从消息队列取消息。之后通过轮询器来取出消息,轮询器实在主线程中的。每个消息通过target属性来找到自己的消息。然后再调用handleMessage()方法中处理结果。
下面我们通过四个类来将handler消息机制弄清楚。Message,MesageQueue,Handler,Looper。
Message
1, new Message()
2, Message.obtain();
3, handler.obtainMessage();
MesageQueue
存放Message的容器,单链表
默认:msg的when都是0 后加的放到最前面
如果when不等于0 按when的值大小进入排序:when的值小的在队列的前面
Handler
消息处理类
handleMessage(Message msg)方法,覆盖此方法,做ui的处理
Looper
轮询器 : 轮询取消息,linux底层管道通讯
Message类
**//代表message值是什么**
public int what;
public int arg1;
public int arg2;
**//如果信息较多用Obj来作为信息的载体。**
public Object obj;
public Messenger replyTo;
**// /*package*/为私有的访问权限并不对外提供。**
/*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;
/*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
/*package*/ int flags;
**//发消息的时间,默认情况下是0。写1000即为等待1000毫秒中再发**
/*package*/ long when;
/*package*/ Bundle data;
**//target也就是用来区分message的**
/*package*/ Handler target;
**//一个回调接口**
/*package*/ Runnable callback;
**//next其实就是一个单链表**
/*package*/ Message next;
我们来看一下Message.obtain();中代码
//为了满足语法来new Object();
private static final Object sPoolSync = new Object();
private static Message sPool;
public static Message obtain() {
synchronized (sPoolSync) {
//sPool是一个消息池,上面定义了,也就还是一个消息。
if (sPool != null) {
//从消息池中取消息。
Message m = sPool;
//然后再指向下一个。
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
//如果消息池中没有消息也就是直接创建了一个新的消息。
return new Message();
}
我们再来看一下clearForRecycle()这个方法。
//这个方法将所有的属性进行了清零。
void clearForRecycle() {
flags = 0;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
when = 0;
target = null;
callback = null;
data = null;
}
这也就是我们在如下代码中常犯的错误的解释:
//将target=null。msg.what也就不知道到底是哪个target了。发消息也就会报错了。
Message msg = Message.obtain();
msg.what = 1;
msg.what = 2;
为什么会调用clearForRecycle()这个方法呢?我们看一下下面的方法。也就是在recycle()这个方法中调用了clearForRecycle()方法。
public void recycle() {
clearForRecycle();
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
//将静态变量sPool赋值给了next
next = sPool;
//这个又指向了sPool
sPool = this;
sPoolSize++;
}
}
}
通过上面的方法中的两句、
//将静态变量sPool赋值给了next
next = sPool;
//这个又指向了sPool
sPool = this;
并且结合obtain()中的
sPool = m.next;
m.next = null;
我们就可以将两个消息重用为一个消息了。综上 Message类中的方法都跟这个Obtain()方法一样。将消息重用。
ActivityThread执行main();
//1,
Looper.prepareMainLooper();
// 2,
public static final void prepareMainLooper() {
//3
prepare();
setMainLooper(myLooper());
if (Process.supportsProcesses()) {
myLooper().mQueue.mQuitAllowed = false;
}
}
// 4
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//5,,调用的时候Looper.myLooper()-->
sThreadLocal.set(new Looper());
}
// 6,在handler的默认构造函数中去调用取值
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
Handler()的构造函数
public Handler() {
//轮询器的初始化,主线程
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
// 从轮询器中获取消息队列
mQueue = mLooper.mQueue;
//回调初始化为null
mCallback = null;
}
通过上面我们需要看两个代码
1, Looper.myLooper();
public static final Looper myLooper() {
//从sThreadLocal取值 ,赋值看 上面##### ActivityThread执行main()
//ThreadLocal 线程变量。开启多个线程的时候,为每个线程设置一个值。当前线程再去取值的时候,他会取出自己线程的值。而不会取到别的线程设置的值。
return (Looper)sThreadLocal.get();
}
2, mQueue = mLooper.mQueue;//获取轮询器中的消息队列
Handler发送Message
1,handler.sendMessage(msg);//发送消息
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
2,sendMessageDelayed(msg, 0);
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
3,sendMessageAtTime()
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
boolean sent = false;
//获取消息队列,mQueue的赋值请看Handler的默认构造函数
MessageQueue queue = mQueue;
if (queue != null) {
//把自己的handler和Message绑定,this就是Handler
msg.target = this;
//把msg放到消息队列并且完成排序(按时间和顺序)
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
4,sent = queue.enqueueMessage(msg, uptimeMillis);
消息队列里enqueueMessage方法,
1,放消息
2,排序(按消息的时间排序,如果时间一样,后加的在前面
final boolean enqueueMessage(Message msg, long when) {
if (msg.when != 0) {
throw new AndroidRuntimeException(msg
+ " This message is already in use.");
}
if (msg.target == null && !mQuitAllowed) {
throw new RuntimeException("Main thread not allowed to quit");
}
final boolean needWake;
synchronized (this) {
if (mQuiting) {
RuntimeException e = new RuntimeException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
return false;
} else if (msg.target == null) {
mQuiting = true;
}
msg.when = when;
//Log.d("MessageQueue", "Enqueing: " + msg);
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked; // new head, might need to wake up
} else {
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
needWake = false; // still waiting on head, no need to wake up
}
}
if (needWake) {
nativeWake(mPtr);
}
return true;
}
Looper取消息
在应用程序启动之前
ActivityThread的main已经执行好,并且开始等待接收消息
调用 Looper.loop();//轮询取消息
1,Looper的loop方法
while (true) {
//消息队列
Message msg = queue.next(); // might block
//if (!me.mRun) {
// break;
//}
if (msg != null) {
//找不到对应的handler
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
//处理消息
msg.target.dispatchMessage(msg);
if (me.mLogging!= null) me.mLogging.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("Looper", "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);
}
//4,
msg.recycle();
}
}
}
2, msg.target.dispatchMessage(msg);
调用Handler的dispatchMessage分发消息
public void dispatchMessage(Message msg) {
if (msg.callback != null) {// runOnUiThread
//2.5
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//3handleMessage
handleMessage(msg);
}
}
2.5 handleCallback(msg); 用户调用了runOnUiThread方法调用
a,
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
b,
mHandler.post(action);
public final boolean post(Runnable r)
{
c,
return sendMessageDelayed(getPostMessage(r), 0);
}
d,
private final Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
e,
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
//把handler发出去 msg.callback= Runnable
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//////////上面abcde是通过runOnUiThread方法发送消息的逻辑
取消息
handleCallback(msg);
private final void handleCallback(Message message) {
message.callback.run();//runOnUiThread里写的功能,在主线程运行
}
3, 在主线程中调用Handler的handleMessage(msg)用户覆盖的方法处理消息
处理ui相关的操作
4, msg.recycle();
msg的回收
public void recycle() {
synchronized (mPoolSync) {
if (mPoolSize < MAX_POOL_SIZE) {
clearForRecycle();
next = mPool;
mPool = this;
}
}
}