handler的dispatchMessage方法是如何被调用的? 探索 m.target是如何被附加上handler的

首先来点基础描述:
主线程的handler的looper,也就是Loop.getMainLooper()返回的loop,默认在ActivityThread类的main方法初始化了 ,在main方法里面调用了Loop.perpareMainLoper();初始化了一个loop,所以一般主线程的looper实际上就是那里初始化的looper具体ActivityThread类的main```代码如下:


    public static void main(String[] args) {
        CloseGuard.setEnabled(false);
        Environment.initForCurrentUser();
        Process.setArgV0("<pre-initialized>");
        Looper.prepareMainLooper();
        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.

        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
}

创建了一个默认的loop又维护了一个messageQuare主线程的looper轮训方法loop()是早早就被调用了的,

  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;
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
          
                return;
            }


      
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

 
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
          
            }

            msg.recycleUnchecked();
        }
    }

那么handler类里面的dispatchMessage触发是因为添加到消息队列中的消息Message类的``target被设置了handler,然后在Looper类的loop方法里面处理这个消息的时候触发,也就是下面的这句代码 msg.target.dispatchMessage(msg);```

         try {
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }

msg.target.的成员变量为handler,也就是代码是从这里调用的。

Looper相关方法
构建loop静态对象 保证一个线程只有一个

public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }


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

至于Looper.loop()方法上面已经贴过了,也就是开启轮训,当没有的时候cpu进入等待。这个和某个酷Q机器人易语言源码当中的消息处理惊人的相似。他那个差不多就是消息队列的死循环,没有的时候就进行睡眠,然后有消息的时候线程唤醒。
里面用到了ThreadLocal通过线程名作为键,保证了一个线程只有一个ThreadLocal一个Looper

    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

ThreadLocal的关键方法

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

源码太深,这里只讲如何被设置上去的,
根据handler的源码分析,post postDelay实际上都最终调用了sendMessageAtTime然后调用了
return enqueueMessage(queue, msg, uptimeMillis);

那么继续,先看看handler的一些方法,

    public final Message obtainMessage()
    {
        return Message.obtain(this);
    }

    public final Message obtainMessage(int what)
    {
        return Message.obtain(this, what);
    }
    

    public final Message obtainMessage(int what, Object obj)
    {
        return Message.obtain(this, what, obj);
    }

这里都把handler传递进去了
Message的obtain方法设置了 m.target

  public static Message obtain(Handler h, int what, Object obj) {
        Message m = obtain();
        m.target = h;
        m.what = what;
        m.obj = obj;

        return m;
    }

既然是这样的,那么自己创建一个纯message类会触发吗?

 Message message=new Message();
                message.what=1;
                message.obj="测试纯message";
                handler.sendMessage(message);

结果令人震惊,还是触发了,这message.taget他是如何被设置的呢?

然后又看了看,原来那报错的红色代码没有被我注意到,也就是说追踪走的sendMessageAtTime方法走的enqueueMessage方法中强制给message的targer设置了handler为自己。

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

这句话明显的写这句话msg.target = this; 所以 明白为什么可以回调了,ok讲解完毕,知其然也知其所以然了。

其它相关

1、handler类的queue成员变量是从Looper中获取到的,handler发消息实际上是拿到Looper里面的静态消息队列字段
mLooper.mQueue

2、而mQueue = new MessageQueue(quitAllowed);也就是消息队列对象的初始化是通过prepare的调用导致sThreadLocal.set(new Looper(quitAllowed));这句代码被执行,然后导致Looper构造方法执行,然后触发这个队列的初始化。···mQueue = new MessageQueue(quitAllowed);···

sThreadLocal也就是ThreadLocal默认在成员变量就初始化了sThreadLocal而且是静态的 这个字段也是放到Looper类里面存起来的
3、真正负责处理消息的是在looper()开启一个死循环for,不断的0调用MessageQueuenext() 知道返回null才终止,,在这个方法几乎是没法出来了,永远卡在这个方法,除非满足特定条件,`比如messagequarequit方法被调用。
4、looperlooper死死循环外,消息队列MessageQueue next也嵌套了一个死循环,所以即使消息没有也不会进行立马返回,而是等待,只有当有消息的时候才返回给looper()处理这里面主要做一些时间的处理,比如那些延时时间发送的。

有些东西还是没法理解,深度对我来说还是遥不可及

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容