Moosphan / Android-Daily-Interview

:pushpin:每工作日更新一道 Android 面试题,小聚成河,大聚成江,共勉之~
5.47k stars 776 forks source link

2020-03-04:试从源码角度分析Handler的post和sendMessage方法的区别和应用场景? #239

Open Moosphan opened 4 years ago

SanYueSI commented 4 years ago

最简单的区别就是post 是无参回调直接new Runnable就可以实现 sendMessage有参数 post一般用于单个场景 比如单一的倒计时弹框功能 sendMessage的回调需要去实现handleMessage Message则做为参数 用于多判断条件的场景 比如3个按钮 实现不同的效果

luotuoxiangzi02 commented 4 years ago

handler.post和handler.sendMessage方法最后都会调用sendMessageAtTime方法进行消息的发送,但是在post方法中message是通过getPostMessage(Runnable r)这个方法获取的message,在这个方法中有这样一句代码m.callback = r ,给message的callback赋值为runnable对象,而在dispatchMessage这个方法中对消息进行分发的时候,先进行了msg.callback != null的判断,如果不为null,消息是通过handleCallback(msg);这个方法处理的,在这个方法中message.callback.run();调用的是post方法传递过来的runnable内的run方法处理消息,如果为空,再进行handler内部的callback判断mCallback != null,如果handler内的callback不为空,执行mCallback.handleMessage(msg)这个处理消息并判断返回是否为true,如果返回true,消息处理结束,如果返回false,消息交给handler的handleMessage(msg)处理。 所以区别就是调用post方法的消息是在post传递的Runnable对象的run方法中处理,而调用sendMessage方法需要重写handleMessage方法或者给handler设置callback,在callback的handleMessage中处理并返回true。(文字表达能力有限,抱歉)

LvKang-insist commented 4 years ago

post 使用的是 Runable,而 sendMessage 需要重新方法,或者设置 Callback

//应用场景:感觉那个使用符合逻辑,并且方便就用那个了

lov3blacksilk commented 4 years ago

post是将一个Runnbale封装成Message, 并赋值给callback参数,从这个过程之后就和sendMessge没有任何区别,会接着执行sendMessageDelayed->sendMessageAtTime,然后进入消息队列等待执行,到达Message执行时间时调用Handler的dispatchMessage方法, 其中有逻辑判断: 如果Message的callback不为空,就会执行callback的run方法,如果Message的callback为null,就会判断Handler的callback是否为空,不为空的话会执行Handler的callback的handleMessage方法,如果Handler的callback为空,则会执行Handler的handleMessage方法。 所以:

  1. post是属于sendMessage的一种赋值callback的特例
  2. post和sendMessage本质上没有区别,两种都会涉及到内存泄露的问题
  3. post方式配合lambda表达式写法更精简

话外:

  1. 现在都是使用rxjava或者其他构建好的线程切换逻辑,以前有一段时间我是手写handle的主线程和子线程切换,如果遇到这种经常需要切换线程的逻辑时,我觉得可能sendMessage方式更合适一些,举个栗子: post方式: Thread1.post(() -> (Thread2.post(() -> Thread1.post(.......);,这种写法嵌套好像有点儿多,但是线程切换清晰一点儿 sendMessage写法你懂得我就不写了,只要构建好两个Handler, 代码更简洁一点儿 这两种哪个比较好还是看个人习惯吧。
  2. 涉及到内存泄露问题时没法直接使用lambda表达式,如果有多个不同的Message需要处理的话我觉得多数场景下sendMessage更好一点儿,毕竟写一个弱引用就行了

总的来说应用场景没啥区别...

LillteZheng commented 4 years ago

其实没多大区别,post 只是把runnable 给 msg.callback ,而sendMessage 只是用数据给 msg,最后都是传递这个 Message。 从源码也知道,在 dispatchMessage 中,如下:

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

如果 callback 不为空,则执行 handleCallback(msg); 方法,就是用ActivityThread去执行这个runnable,如果未null,就执行我们熟悉的 handleMessage(msg)

mlinqirong commented 2 years ago

handle的post和sendMessage方法的区别在于post是发送无参和执行自己实现的runnable 而sendMessage发送是带有message并执行handleMessage post的场景是一些单于不需要标记参数和what sendMessage的场景是需要传递message标记参数是what