Android基础_详解Handler消息机制

概念解释:
Message:消息;其中包含的是消息的ID,消息对象以及处理的数据,有MessageQueue统一列队,最终由handler处理.

Handler:处理者;负责的是message发送消息以及处理.Handler通过与Looper进行沟通

MessageQueue:消息队列;用来存放Handler发过来的消息,并且按照的是FIFO(先入先出的)规则执行,要注意的是存放的message并非实际意义的保存,而是将message以链表的形式串联起来,等待looper(轮询器)的抽取.

Looper:消息泵(也叫轮询器);不断地从 MessageQueue中抽取message执行.因此,一个线程中的 MessageQueue需要一个Looper进行管理.Looper是当前线程创建的时候产生的,new Handler之前必须要有looper对象,(主线程中是系统帮助创建的looper,看源码分析的话在ActivityThread中的main方法中就已经创建了looper,所以我们在主线程中直接new Handler不会报错的,子线程中new Handler会报错,要加上Looper.prepare()才行 )。
总的来说就是,当前的线程会绑定一个一个Looper对象,new Handler必须要有一个looper对象。

handler机制的处理:
首先:
    
    
//1. 主线程创建一个handler
Handler handler1 = new Handler();
//1.0 子线程也创建一个 看一看效果的
 
new Thread(new Runnable() {
@Override
public void run() {
Handler handler2 = new Handler();
}
}).start();
报错的:
    
    
FATAL EXCEPTION: Thread-129 Process: com.example.handlerdemo, PID: 1613
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
子线程中创建handler会导致崩溃的,提前调用 Looper.prepare() 就可以的;加上就可以的;


首先从Message开始说起:
1.创建Message的方式:
   
   
                /**
* 创建msg的三种方式
*/
Message msg = Message.obtain();
Message msg1 = handler.obtainMessage();
Message msg2 = new Message();

   
   
public final Message obtainMessage()
{
return Message.obtain(this);
}
最终还是调用的这边:
   
   
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();
}

创建的消息放到消息队列中:是怎么放呢?就是调用了 enqueueMessage ( queue , msg , uptimeMillis )
   
   
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);//this. enqueueMessage()说明是Handeler类中的方法
}

消息放进消息的队列的时候 是这样的: msg . target = this ;this就是Handler
也就是说你再发送消息的时候,哪一个handler发送哪一个就赋值给 msg . target ,当有多个handler发送消息的时候,怎么确定是哪个发的,就是通过 msg . target ;
   
   
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}

怎么进的队列? 
   
   
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;
}
 
//判断是否需要唤醒主线程处理消息
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}

//如果当前的消息需要马上处理,放到对头
//不需要马上处理的话 把消息队列按照时间进行排序
//判断是否需要唤醒主线程处理消息

消息队列中有一个唤醒机制:唤醒是因为阻塞:怎么说这个阻塞呢?我们接着看一下 ActivityThread main 方法中的Looper.loop方法
   
   
public static final void loop() {
Looper me = myLooper();
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(); // might block
//if (!me.mRun) {
// break;
//}
if (msg != null) {
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);
}
msg.recycle();
}
}
}
从第10行看,那是一个死循环,这个一个在主线程中的的死循环,难道你就不纳闷吗?这可是主线程,主线程中放一个死循环,不是会出现NOR吗?这边就是比较颠覆观念的Android代码执行,要有一个新的认识:所有的代码内部都是通过发消息去处理,发到主线程中,主线程通过Looper取到消息去处理,根据不同的消息调用不同方法.
仔细想一想就是为什么打开一个activity的时候,执行完之后为什么不自己关闭掉?这是因为还在执行的,就是出于死循环的状态,当你点击返回时候出发的是事件,实际上也是发送消息给主线程,主线程中的looper一直轮训消息,接受到消息后执行关闭.
也就是所有的代码都是执行在handler中的消息机制中的.

死循环等待的过程就是一个阻塞状态.  阻塞机制,采用的是Linux中的一种进程间通信方式,管道(Pipe),有一个特殊的文件,有两个描述符,一个读描述符,一个写描述符,一个进程拿写描述符写数据,另一个进程拿读描述符读数据,如果读不到数据就阻塞,写描述符只要写数据就可以唤醒读描述符。
这就是唤醒和阻塞机制.

Handler消息机制中,主线程拿读描述符读取消息,如果没有就阻塞,Handler在子线程发送消息,拿写描述符写数据,唤醒主线程,读到数据就处理。进行下一次轮询。

这边获取到消息的时候:是这样处理的: msg . target . dispatchMessage ( msg );
   
   
Message msg = queue.next(); // might block
    
    
msg.target.dispatchMessage(msg);
点进去一看:然后就到了我们常见的handleMessage方法.
   
   
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
// 如果Handler发送的是Message
handleMessage(msg);
}


创建Handeler:

创建handler的时候 ,在构造中是这样的必然要走,
   
   
public Handler(Callback callback, boolean async) {
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;
}

从当前线程中获取looper对象
   
   
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}

有获取必然有往里面放looper,为什么主线程中可以直接new Handler而不用prepare?主线程已经放过了。
   
   
ActivityThreadmain方法
 
public static final void main(String[] args) {
SamplingProfilerIntegration.start();
 
Process.setArgV0("<pre-initialized>");
// 准备Looper对象
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}
 
ActivityThread thread = new ActivityThread();
thread.attach(false);
 
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// 开始取消息
Looper.loop();
 
if (Process.supportsProcesses()) {
throw new RuntimeException("Main thread loop unexpectedly exited");
}
 
thread.detach();
String name = (thread.mInitialApplication != null)
? thread.mInitialApplication.getPackageName()
: "<unknown>";
Slog.i(TAG, "Main thread of " + name + " is now exiting");
}
准备Looper对象是这样的:Looper.prepareMainLooper();
   
   
public static final void prepareMainLooper() {
prepare();
setMainLooper(myLooper());
if (Process.supportsProcesses()) {
myLooper().mQueue.mQuitAllowed = false;
}
}
调用了这个方法prepare();
   
   
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 往当前线程中设置Looper对象
sThreadLocal.set(new Looper());
}
截止到这里 也就是发现系统一开始启动的时候主线程中已经放过一个looper对象了,也就解释了为什么主线程中直接new Handler不报错的原因

new Looper () 线程中设置looper对象,是怎么样的呢? 你在代码中new Looper的时候 会创建一个消息队列 说明一个looper对应一个消息队列
   
   
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}

这时候你在回去看Handler的构造就发现:Handler构造中也有一个队列,这个对列就是取Looper中的队列
  
  
ublic Handler(Callback callback, boolean async) {
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的对应关系?
多对一对一;
主线程可以new 多个Handler但是 只有一个Looper,Looper的构造中只走一个 MessageQueue;                                                                                                                 

这边有一个问题就是多对一,那么怎么区分是那个Handler发的消息呢?

就是处理消息的时候 根据msg.target  就是对应的Handler                       
   
   
msg.target.dispatchMessage(msg);

整体上就是这样的:



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值