博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
android的handler、looper、Message之间的关系
阅读量:2072 次
发布时间:2019-04-29

本文共 4671 字,大约阅读时间需要 15 分钟。

handler:绑定到一个线程上,一个线程可以有多个handler

looper:线程跟looper是一一对应的,所以looper不能被调用两次否则会抛出异常

messge:handler利用message来携带消息

messagQueue:用来状态message,一个looper对应一个消息队列

如何来判断一个消息队列对应一个handler呢,在sendmessage中获取到一个消息队列的持有者looper

looper的两个方法:prepare()和loop()

1.

复制代码

public static final void prepare() {        if (sThreadLocal.get() != null) {            throw new RuntimeException("Only one Looper may be created per thread");        }        sThreadLocal.set(new Looper(true));}

复制代码

给当前线程一个设定一个looper实例

2.

private Looper(boolean quitAllowed) {        mQueue = new MessageQueue(quitAllowed);        mRun = true;        mThread = Thread.currentThread();}

给这个looper创建一个消息队列(在构造函数中),并返回当前的线程

3.

复制代码

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;        // 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();        for (;;) {            Message msg = queue.next(); // might block            if (msg == null) {                // No message indicates that the message queue is quitting.                return;            }            // 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);            }            msg.target.dispatchMessage(msg);            if (logging != null) {                logging.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(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();        }}

复制代码

public static Looper myLooper() {        return sThreadLocal.get();    }

直接拿到该looper实例中的消息队列,然后循环每一个message(进入了无限循环),遍历消息之后会通过这个message的handler进行分发。

msg.target.dispatchMessage(msg); 中的target是handler

总结looper的主要作用

1) 与当前线程绑定,保证一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue。

2) loop()方法,不断从MessageQueue中去取消息,交给消息的target属性的dispatchMessage去处理。

handler

复制代码

public Handler() {        this(null, false);}public Handler(Callback callback, boolean async) {        if (FIND_POTENTIAL_LEAKS) {            final Class
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 = callback; mAsynchronous = async; }

复制代码

handler绑定到looper上,由于一个looper对一个一个消息队列,这样这个handler就绑定到这个looper上了,也同时绑定到了这个线程上。

handler.sendMessgae()是用来讲Message添加进消息队列的。。dispatchmessage才是用于分发的(如上looper介绍)

复制代码

public void dispatchMessage(Message msg) {        if (msg.callback != null) {            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);        }    }

复制代码

public void handleMessage(Message msg) {    }

handleMessage此时是空的函数,需要我们之后的复写

步骤:

复制代码

1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。6、handler也可以进行存在于子线程中,为什么我们一般见到的都在主线程中呢?因为一般是针对UI空间更新的操作是不安全的所以handler放在主线程中,如果不存在这样的业务,当然可以用handler

转载地址:http://btvmf.baihongyu.com/

你可能感兴趣的文章
Hadoop HDFS文件操作的Java代码
查看>>
Hadoop学习笔记—3.Hadoop RPC机制的使用
查看>>
Hadoop学习笔记—22.Hadoop2.x环境搭建与配置
查看>>
JTS Geometry关系判断和分析
查看>>
GIS基本概念
查看>>
Java文件操作①——XML文件的读取
查看>>
java学习总结之文件操作--ByteArrayOutputStream的用法
查看>>
Java生成和操作Excel文件
查看>>
Java的三种代理模式
查看>>
java静态代理与动态代理简单分析
查看>>
JTS Geometry关系判断和分析
查看>>
阿里巴巴十年Java架构师分享,会了这个知识点的人都去BAT了
查看>>
Intellij IDEA 使用技巧一
查看>>
idea如何显示git远程与本地的更改对比?
查看>>
Git 分支 - 分支的新建与合并
查看>>
git创建与合并分支
查看>>
23种设计模式介绍以及在Java中的实现
查看>>
如何把本地项目上传到Github
查看>>
Git的使用--如何将本地项目上传到Github
查看>>
zookeeper客户端命令行查看dubbo服务的生产者和消费者
查看>>