欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android 消息机制问题总结

程序员文章站 2024-03-06 20:46:02
android的消息机制几乎是面试必问的话题,当然也并不是因为面试,而去学习,更重要的是它在android的开发中是必不可少的,占着举足轻重的地位,所以弄懂它是很有必要的。...

android的消息机制几乎是面试必问的话题,当然也并不是因为面试,而去学习,更重要的是它在android的开发中是必不可少的,占着举足轻重的地位,所以弄懂它是很有必要的。下面就来说说最基本的东西。

looper

作用:

关联起thread

循环取出消息

1、looper是否可以直接实例化?

looper构造方法是私有的,其中做了两件事

创建一个messagequeue

得到与之对应的thread

private looper(boolean quitallowed) {
  mqueue = new messagequeue(quitallowed);
  mthread = thread.currentthread();
}

2、一个线程能对应多个lopper?

不能,一个线程对应一个looper对象,通过threadlocal保证一个线程只有一个looper与之对应,如果多次调用looper.prepare();则会抛出运行时异常。

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));
}

3、looper是无限循环,会阻塞吗?

是,当开启一个loop后是一个死循环,从messagequeue中取出消息,处理消息,但是也有可能退出,在没有消息后退出循环。

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);
  }

4、可以再次调用looper.preparemainlooper吗?

不可以,looper.preparemainlooper最终也是调用prepare(),同2.

public static void preparemainlooper() {
  prepare(false); // 创建一个looper
  synchronized (looper.class) {
    if (smainlooper != null) {
      throw new illegalstateexception("the main looper has already been   prepared.");
    }
    smainlooper = mylooper();
  }
}

5、mainlooper什么时候创建的?

mainlooper是启动activity创建activitythread(并不是一个thread)时候创建,所以不能多次创建。

public static void main(string[] args) {
 // 略
  process.setargv0("<pre-initialized>");
 looper.preparemainlooper();
 // 略
 activitythread thread = new activitythread();
 thread.attach(false);
 // 略
 if (smainthreadhandler == null) {
  smainthreadhandler = thread.gethandler();
 }

 // 略
 looper.loop();
 throw new runtimeexception("main thread loop unexpectedly exited");
 }
}

handler

作用:

发送消息到messagequeue

处理消息

1、handler如何与looper、messagequeue关联起来?

我们知道一个looper对应一个thread,一个looper包含一个messagequeue。当我们创建handler时就会从当前线程中取出与之对应的looper,让后在从looper中取出messagequeue。

// 1、自动获取
public handler(callback callback, boolean async) {
 // 略
  mlooper = looper.mylooper(); // 取出当前线程中的looper
  if (mlooper == null) {
    throw new runtimeexception(
      "can't create handler inside thread that has not called    looper.prepare()");
  }
  mqueue = mlooper.mqueue; // 取出messagequeue
  mcallback = callback;
  masynchronous = async;
}
// 2、传递一个looper进来
public handler(looper looper, callback callback, boolean async) {
    mlooper = looper;
    mqueue = looper.mqueue;
    mcallback = callback;
    masynchronous = async;
  }

message

单项链表结构。

作用:

数据的载体

1、消息如何复用的?

从全局消息池(链表结构)中

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();
}

2、message为什么能传递?

android中想要传递对象要么实现serializable要么parcelable,在这里是实现了parcelable接口。

public final class message implements parcelable {
  // 略
}

3、如何与handler关联?

我们知道在消息传机制中handler充当着“快递员”的角色,那么他又是如何与“货物”--message发生关系呢?实际上message有一个成员变量target他的类型正是handler,

/*package*/ runnable callback;

public int arg1; 

public int arg2;

public object obj;

/*package*/ handler target; // 关键点

当我们通过handler去send一个message时候最终都会为target赋值为this,即当前的handler。

private boolean enqueuemessage(messagequeue queue, message msg, long uptimemillis) {
  msg.target = this; // 赋值语句
  if (masynchronous) {
    msg.setasynchronous(true);
  }
  return queue.enqueuemessage(msg, uptimemillis);
}

另为如果是通过message.obtain(),获取的复用message也会为其赋值。

多说一句,handler.obtainmessage()调用的就是message.obtain()。

public final message obtainmessage(){
  return message.obtain(this);
}

总结:

通过一系列的包涵关系,最终looper、handler、message、messagequeue即发生关联,从而形成一个闭合,开启消息循环。

Android 消息机制问题总结

困惑

最近一直在看这方面的知识,但是能力有限,还是有不少困惑,如果有错误,或你理解下面的问题请联系我,愿与君交流学习,谢谢

1、message中的spool,哪里初始化的?为什么message.obtain()中不会抛异常?

2、activitythread并不是线程,为什么可以创建一个looper,main thread什么时候创建?

3、为什么序列化了的对象就可以传递?与binder有关?

4、messagequeue对应的是nativemessagequeue,具体实现需要学习?

5、loop.loop(),会退出吗?退出时机是什么?如果会退出,那么主线程同样会退出吗?

以上就是对android 消息机制的资料整理,后续继续补充相关资料,谢谢大家对本站的支持