每个Android编程开发者必须知道的消息机制问题总结
安安 2017-09-20 来源 :网络 阅读 1057 评论 0

摘要: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编程开发者必须知道的消息机制问题总结 

困惑

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

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

2、ActivityThread并不是线程,为什么可以创建一个Looper,Main Thread什么时候创建?

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

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

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

 

以上,关于Android编程的全部内容讲解完毕啦,欢迎大家继续关注!更多关于Android编程的干货请关注职坐标Android编程频道!

本文由 @安安 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程