当前位置: 首页 > news >正文

android 线程消息深入

    在网上有许多资料对这三者关系的分析,但都比较笼统不够细致入微.

以下是自己深入源码分析其结果.

Handler 源码:

public class Handler {

    private static final boolean FIND_POTENTIAL_LEAKS = false;

    private static final String TAG = "Handler";

 

    public interface Callback {

        public boolean handleMessage(Message msg);

    }

    final MessageQueue mQueue;

    final Looper mLooper;

    final Callback mCallback;

    IMessenger mMessenger;

    /**

     * Subclasses must implement this to receive messages.

     */

    public void handleMessage(Message msg) {

    }

    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;

    }

 

    /**

     * Handle system messages here.

     */

    public void dispatchMessage(Message msg) {

        if (msg.callback != null) {

            handleCallback(msg);

        } else {

            if (mCallback != null) {

                if (mCallback.handleMessage(msg)) {

                    return;

                }

            }

            handleMessage(msg);

        }

    }

    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;

}

public boolean sendMessageAtTime(Message msg, long uptimeMillis)

    {

        boolean sent = false;

        MessageQueue queue = mQueue;

        if (queue != null) {

            msg.target = this;

            sent = queue.enqueueMessage(msg, uptimeMillis);

        }

        else {

            RuntimeException e = new RuntimeException(

                this + " sendMessageAtTime() called with no mQueue");

            Log.w("Looper", e.getMessage(), e);

        }

        return sent;

    }

 

从源码分析可以看出:

handler在无参数的构造方法中调用Looper.myLooper()方法,里面就是从当前线程里面获取一个Looper对象,如果没有则创建.这样对Looper就进行初始化,初始化Looper的同时一并初始化MessageQueue,并且从中得到looper的MessageQueue .可以看出Handler就是Looper和MessageQueue的管理者和调度者.

其中最重要的是:sendMessageAtTime(Message msg, long uptimeMillis)这个方法,当你往Handler中发送Message消息的时候,从代码看出他自己并不去处理Message ,而是交给了MessageQueue.由以下从这段代码来处理:

queue.enqueueMessage(msg, uptimeMillis), 其具体实现要看下面的对

MessageQueue的分析

 

 

Looper结构关联的内容:

Looper 源码:

public class Looper {

    private static final boolean DEBUG = false;

    private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;

 

    // sThreadLocal.get() will return null unless you've called prepare().

    private static final ThreadLocal sThreadLocal = new ThreadLocal();

 

    final MessageQueue mQueue;

    volatile boolean mRun;

    Thread mThread;

    private Printer mLogging = null;

    private static Looper mMainLooper = null;

   

    public static final void prepare() {

        if (sThreadLocal.get() != null) {

            throw new RuntimeException("Only one Looper may be created per thread");

        }

        sThreadLocal.set(new Looper());

}

public static final void loop() {

        Looper me = myLooper();

        MessageQueue queue = me.mQueue;

        while (true) {

            Message msg = queue.next(); // might block

            if (msg != null) {

                if (msg.target == null) {

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

                msg.recycle();

            }

        }

    }

从源码可以看出Looper 封装的信息:

 

Looper实质上是对当前线程, ThreadLocal,MessageQueue的封装,也就是负责在多线程之间传递消息的一个循环器.

 

当你往Handler中添加消息的时候则,里面这个方法: public static final void loop()死循环的方法就会被系统调用,之后的功能代码是:

msg.target.dispatchMessage(msg),则从MessageQueue中得到一个

Message(msg),之后调用Handler的dispatchMessage(msg),这个方法内部实际调用的就是 Handler.handleMessage(msg)方法,这个就是我们在

activity要重写的方法,所以我们就能够得到其他子线程传递的Message了.

 

Message的源码分析:

public final class Message implements Parcelable {

    public int what;

    public int arg1;

    public int arg2;

    public Object obj;

    public Messenger replyTo;

    long when;

    Bundle data;

    Handler target;    

    Runnable callback;

    Message next;

    private static Object mPoolSync = new Object();

    private static Message mPool;

    private static int mPoolSize = 0;

    private static final int MAX_POOL_SIZE = 10;

   

When: 向Handler发送Message生成的时间

Data: 在Bundler 对象上绑定要线程中传递的数据

Next: 当前Message 对一下个Message 的引用

Handler: 处理当前Message 的Handler对象.

mPool: 通过字面理解可能叫他Message池,但是通过分析应该叫有下一个Message引用的Message链更加适合.

其中Message.obtain(),通过源码分析就是获取断掉Message链关系的第一个Message.

MessageQueue

 

public class MessageQueue {

    Message mMessages;

    private final ArrayList mIdleHandlers = new ArrayList();

    private boolean mQuiting = false;

    boolean mQuitAllowed = true;

   

    public static interface IdleHandler {

        boolean queueIdle();

}

 

public final void addIdleHandler(IdleHandler handler) {

     if (handler == null) {

         throw new NullPointerException("Can't add a null IdleHandler");

     }

        synchronized (this) {

            mIdleHandlers.add(handler);

        }

}

 

final boolean enqueueMessage(Message msg, long when) {

        if (msg.when != 0) {

            throw new AndroidRuntimeException(msg

                    + " This message is already in use.");

        }

        if (msg.target == null && !mQuitAllowed) {

            throw new RuntimeException("Main thread not allowed to quit");

        }

        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;

                this.notify();

            } else {

                Message prev = null;

                while (p != null && p.when <= when) {

                    prev = p;

                    p = p.next;

                }

                msg.next = prev.next;

                prev.next = msg;

                this.notify();

            }

        }

        return true;

    }

mMessages: 为当前序列的第一个Message, 通过源码分析 MessageQueue并不是对许多Message 之间的关系维护,这样也许可以省去很多事把,而Message 之间的关系

则统统丢给了Message自己去维护,这个可以从对Message源码分析可以理解.

 

mIdleHandler: 保存的是一系列的handler的集合.

 

其中final boolean enqueueMessage(Message msg, long when),

这个方法就是上面提到Handler 处理消息时调用到的方法,对她理解了就显

的很重要了,功能代码如下:

msg.when = when;

Message p = mMessages;

if (p == null || when == 0 || when < p.when) {

       msg.next = p;

       mMessages = msg;

       this.notify();

} else {

      Message prev = null;

      while (p != null && p.when <= when) {

               prev = p;

               p = p.next;

           }

       msg.next = prev.next;

       prev.next = msg;

       this.notify();

}

 

当向MessageQueue中添加消息的时候,判断当前的Message(mMessage)是否为空,

如果为空或者when=0或者when<p.when: 则把要添加的Message(msg)赋给当

前的Message(mMessage),并且将msg.next属性设为空,

如果不为空: 则循环把当前的Message(mMessage)的下一个Message(next)进行遍历,用prev记住当前的message,直到找到prev的下一个Message为空的时候就退出循环,最后将msg接到prev的屁股后面,

即这段代码: prev.next = msg;

转载于:https://www.cnblogs.com/622698abc/archive/2012/10/25/2739995.html

相关文章:

  • ios动态库和静态库
  • Chrome开发——第一个博客链接插件
  • RabbitMQ消息队列(九):Publisher的消息确认机制
  • 减治算法求n个数中的最小数的位置
  • spark2.1.0 自定义AccumulatorV2累加少值(线程不安全)?
  • heartbeat+ldirectord实现web与dns的高可用性
  • __new__ 是什么鬼
  • C#面向对象20 序列化和反序列化
  • SecureCRT 只用 RZ 命令上传大文件失败
  • Ubuntu 10.04下安装libgtk2.0-dev
  • MySQL多实例介绍及配置
  • Java类与对象初始化的过程(一道经典的面试题)
  • EF架构~性能高效的批量操作(Insert篇)
  • user-agent 验证移动端请求
  • python用zipfile模块打包文件或是目录、解压zip文件实例
  • IE9 : DOM Exception: INVALID_CHARACTER_ERR (5)
  • 【159天】尚学堂高琪Java300集视频精华笔记(128)
  • 【划重点】MySQL技术内幕:InnoDB存储引擎
  • create-react-app做的留言板
  • Docker 笔记(2):Dockerfile
  • exports和module.exports
  • express + mock 让前后台并行开发
  • oldjun 检测网站的经验
  • SegmentFault 技术周刊 Vol.27 - Git 学习宝典:程序员走江湖必备
  • unity如何实现一个固定宽度的orthagraphic相机
  • 笨办法学C 练习34:动态数组
  • 测试开发系类之接口自动化测试
  • 大数据与云计算学习:数据分析(二)
  • 今年的LC3大会没了?
  • 前言-如何学习区块链
  • 时间复杂度与空间复杂度分析
  • 优化 Vue 项目编译文件大小
  • 在GitHub多个账号上使用不同的SSH的配置方法
  • 怎么将电脑中的声音录制成WAV格式
  • Semaphore
  • ​DB-Engines 12月数据库排名: PostgreSQL有望获得「2020年度数据库」荣誉?
  • # 数论-逆元
  • #LLM入门|Prompt#1.7_文本拓展_Expanding
  • #Z0458. 树的中心2
  • #预处理和函数的对比以及条件编译
  • (done) ROC曲线 和 AUC值 分别是什么?
  • (iPhone/iPad开发)在UIWebView中自定义菜单栏
  • (独孤九剑)--文件系统
  • (力扣题库)跳跃游戏II(c++)
  • (三)docker:Dockerfile构建容器运行jar包
  • (转)如何上传第三方jar包至Maven私服让maven项目可以使用第三方jar包
  • (转贴)用VML开发工作流设计器 UCML.NET工作流管理系统
  • .NET 4.0中的泛型协变和反变
  • .NET Framework 3.5中序列化成JSON数据及JSON数据的反序列化,以及jQuery的调用JSON
  • .Net接口调试与案例
  • @31省区市高考时间表来了,祝考试成功
  • @cacheable 是否缓存成功_让我们来学习学习SpringCache分布式缓存,为什么用?
  • @ConfigurationProperties注解对数据的自动封装
  • [ vulhub漏洞复现篇 ] Apache APISIX 默认密钥漏洞 CVE-2020-13945
  • [8-27]正则表达式、扩展表达式以及相关实战