通常情况下使用Handler发送消息并且处理消息。
一:此时mHandler属于UI主线程。
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//其他代码
}
}
二:此时mHandler属于子线程(工作者线程)
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();
}
}
new Handler()的时候做了如下工作: public Handler() {
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 = null ;
}
至此:Looper = Thread + Handler
||
||
||
这种情况下,如果没有绑定对应的Looper对象,在此刷新Ui会抛出异常;
Can't create handler inside thread that has not called Looper.prepare()
为什么需要调用 Looper.prepare();Looper.loop();这两个方法:
先看看Looper类有些什么
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();//保存Looper变量,保证多个looper拷贝
final MessageQueue mQueue;//消息队列
final Thread mThread;//当前线程
当调用prepare()方法时做了些什么?
public static void prepare() {
if (sThreadLocal .get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}//检查该线程Looper实例变量是否为空,保证一个线程只有一个looper实例变量。
sThreadLocal.set(new Looper());//这样sThreadLocal 就保存了当前线程的looper对象实例。
}
||
||
||
private Looper () {
mQueue = new MessageQueue();//一个Looper操作的消息队列
mRun = true ;
mThread = Thread.currentThread();//绑定到当前线程
}
||
||
||
public static void loop() {
Looper me = myLooper();//获取与当前线程绑定的looper实例,
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
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 ();
//进入死循环,不断的循环消息队列,取出消息处理消息
while (true ) {
Message msg = queue.next(); // 取出消息
if (msg != null) {
//msg.target 其实是一个Handler ,作用看后面
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
long wallStart = 0;
long threadStart = 0;
// 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 );
wallStart = SystemClock.currentTimeMicro();
threadStart = SystemClock.currentThreadTimeMicro();
}________打印日志
msg.target.dispatchMessage(msg);//将消息处理转到msg.target 而看Message源码Handler target;
if (logging != null) {
long wallTime = SystemClock.currentTimeMicro() - wallStart;
long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;
logging.println( "<<<<< Finished to " + msg.target + " " + msg.callback);
if (logging instanceof Profiler) {
((Profiler) logging).profile(msg, wallStart, wallTime,
threadStart, threadTime);
}
}
// 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.recycle();//
}
}
}
||
||
||
先看看Messenger有些什么?
/*package*/ Bundle data;
/*package*/ Handler target;
/*package*/ Runnable callback;//用于回调,
public void dispatchMessage(Message msg) {
//先判断msg.callback是否为空或者不为空的情况?
//问题1:而msg.callback是个线程,什么时候被初始化?
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback .handleMessage(msg)) {
return;
}
}
handleMessage(msg);//这里可以看出,最终消息发出后该消息会由Handler的handleMessage(msg);处理。
}
}
解答: //问题1:而msg.callback是个线程,什么时候被初始化?
private final void handleCallback(Message message) {
message.callback.run();//直接执行到传进来的线程的run方法中去了,即又回调回去了。
}
Handler还有这样一中用法(即延迟处理消息):
new Handler().postDelayed( new Runnable() {
@Override
public void run() {
//操作代码
}
}, 300);
------------>看postDelayed 方法:
public final boolean postDelayed (Runnable r, long delayMillis)
{
//传进来的线程被放进了getPostMessage(r)方法
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
------------>getPostMessage(r)方法
private final Message getPostMessage(Runnable r) {
Message m = Message. obtain();
m.callback = r;//callback即被初始化了。则该消息的callback不为空
return m;
}
一路跟踪postDelayed的具体代码,最后到了sendMessageAtTime这个方法中来了。
上面一点说明了:handleCallback(msg);与 handleMessage(msg);的区别
||
||
||
因此先看看sendMessageAtTime 这个方法:
public boolean sendMessageAtTime (Message msg, long uptimeMillis)
{
boolean sent = false;
MessageQueue queue = mQueue;//问题1:这个是那里来的?也就是说这个是不是就是该线程绑定的looper的那个消息队列?
if (queue != null) {
msg.target = this;//问题2:当前Handler即为处理消息的目标handler
sent = queue.enqueueMessage(msg, uptimeMillis);//处理消息
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue" );
Log. w("Looper", e.getMessage(), e);
}
return sent;
}
||
||
||
处理消息放进来,拿出去的操作
final boolean enqueueMessage(Message msg, long when) {
---------------开始-------------------------------------
异常情况:消息正在使用;目标为空主线程不允许;
if (msg.isInUse()) {
throw new AndroidRuntimeException(msg
+ " This message is already in use." );
}
//mQuitAllowed消息队列 是否允许结束标志位
他的使用在这里: public static void prepareMainLooper() {
prepare();
setMainLooper(myLooper ());
myLooper().mQueue.mQuitAllowed = false;
}而prepareMainLooper是在ActivityThread的时候调用,即初始化主线程的时候。说明他是与主线程挂钩的。
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 ;
}
重点方法:enqueueMessage()+next()
||
||
||
从Handler的源码看,Handler的所有发送消息方法中,不管以何种方式发送最后都会转到sendMessageAtTime这个
方法中。
另外:刷新UI的另外几种方式:
runOnUiThread( new Runnable() {
public void run() {
//代码
}
});
|
|
|
public final void runOnUiThread(Runnable action) {
//判断是否是主线程,如果是则直接到这个线程的run方法中
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
|
|
|
public final boolean post (Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
后面的和上面一样了。最后还是回归到了r的run方法中
btn1.post(new Runnable () {
@Override
public void run() {
// TODO Auto-generated method stub
}
});
Android消息处理机制
最新推荐文章于 2020-04-10 10:48:51 发布