0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

详解Android Handler机制和原理

Android编程精选 来源:Android编程精选 作者:Android编程精选 2023-03-26 14:32 次阅读

Handler的使用

Android开发中,Handler机制是一个很重要的知识点,主要用于消息通信

Handler使用的三大步骤:

1、Loop.prepare()。

2、new一个Handler对象,并重写handleMessage方法。

3、Loop.loop()。

先运行实例代码观察现象,再深入分析内部原理。

publicclassLooperThreadextendsThread{
privatestaticfinalString TAG = LooperThread.class.getSimpleName();
privateHandler handler;

@Override
publicvoidrun(){
Looper.prepare();
handler = newHandler(Looper.myLooper(), newHandler.Callback() {
@Override
publicbooleanhandleMessage(@NonNull Message msg){
Log.d(TAG, "what: "+ msg.what + ", msg: "+ msg.obj.toString());
returntrue;
}
});
Looper.loop();
}

publicvoidsendMessage(intwhat, Object obj){
Message msg = handler.obtainMessage(what, obj);
handler.sendMessage(msg);
}
}

publicclassFirstActivityextendsAppCompatActivity{
privatestaticfinalString TAG = FirstActivity.class.getSimpleName();

privateLooperThread looperThread;

@Override
protectedvoidonCreate(Bundle savedInstanceState){

looperThread = newLooperThread();
looperThread.start();
try{
Thread.sleep(1000);
} catch(InterruptedException e) {
e.printStackTrace();
}
looperThread.sendMessage(1, "Hello android!");
}

编译运行程序,输出如下:

2021-10-0623:15:24.32320107-20107/com.example.activitytest D/FirstActivity: Task id is73
2021-10-0623:15:25.32820107-20124/com.example.activitytest D/LooperThread: what:1, msg:Hello android!
2021-10-0623:15:25.39420107-20132/com.example.activitytest I/OpenGLRenderer: Initialized EGL, version1.4
2021-10-0623:15:25.39420107-20132/com.example.activitytest D/OpenGLRenderer: Swap behavior 1

Loop.prepare方法内部实现原理

了解某个方法具体做了什么,最好的方法就是追踪下去看源码。我们跟随IDE一步一步查看Loop.prepare到底做了什么。

/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
publicstaticvoidprepare() {
prepare(true);
}

privatestaticvoidprepare(boolean quitAllowed) {
if(sThreadLocal.get() != null) {
thrownewRuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(newLooper(quitAllowed));
}

sThreadLocal是一个ThreadLocal类型变量,且ThreadLocal是一个模板类。Loop.prepare最终创建一个新的Looper对象,且对象实例被变量sThreadLocal引用。继续追踪下去,查看Looper构造方法做了什么操作。

privateLooper(booleanquitAllowed){
mQueue = newMessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
......
MessageQueue(booleanquitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
到这里我们已经很清楚,Looper构造方法主要是创建一个MessageQueue,且MessageQueue构造方法调用native方法获取底层queue的指针,mQuitAllowed值为true表示允许退出loop,false表示无法退出loop。结合前面Looper.prepare方法内部代码,表示我们创建的Looper允许退出loop。 new一个Handler对象实例,到底做了什么?
/**
* Use the provided {@linkLooper} instead of the default one and take a callback
* interface in which to handle messages.
*
* @paramlooper The looper, must not be null.
* @paramcallback The callback interface in which to handle messages, or null.
*/
publicHandler(@NonNull Looper looper, @Nullable Callback callback){
this(looper, callback, false);
}
......
/**
* Use the provided {@linkLooper} instead of the default one and take a callback
* interface in which to handle messages. Also set whether the handler
* should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by conditions such as display vsync.
*
* @paramlooper The looper, must not be null.
* @paramcallback The callback interface in which to handle messages, or null.
* @paramasync If true, the handler calls {@linkMessage#setAsynchronous(boolean)} for
* each {@linkMessage} that is sent to it or {@linkRunnable} that is posted to it.
*
* @hide
*/
@UnsupportedAppUsage
publicHandler(@NonNull Looper looper, @Nullable Callback callback, booleanasync){
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}

Handler还有其他构造方法,这里我们调用其中一种构造方法创建一个Handler对象实例。该构造方法要求传入一个Looper对象实例和CallBack对象实例。回顾一下最开始的例子代码,我们传入的形参,一个是由Looper.myLooper方法获取的Looper对象实例,另外一个则是Callback匿名类。我们先看看Looper.myLooper到底获取到了什么。

/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
publicstatic@Nullable Looper myLooper() {
returnsThreadLocal.get();
}
这里获取到的就是前面Looper.prepare方法新创建的Looper对象实例,所以Looper.prepare方法必须在创建Handler对象实例之前调用。再回到Handler构造方法里,有几个地方很关键: 1、Handler内部保存了Looper对象引用。 2、Handler内部保存了Looper内部的MessageQueue对象引用。 3、Handler内部保存了Callback对象引用。 4、mAsyncchronous值为true表示handleMessage方法异步执行,false表示同步执行。

Looper.loop方法内部实现原理

/**
* Run the message queue in this thread. Be sure to call
* {@link#quit()} to end the loop.
*/
publicstaticvoidloop(){
finalLooper me = myLooper();
if(me == null) {
thrownewRuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
if(me.mInLoop) {
Slog.w(TAG, "Loop again would have the queued messages be executed"
+ " before this one completed.");
}

me.mInLoop = true;
finalMessageQueue 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();
finallongident = Binder.clearCallingIdentity();

// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
finalintthresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);

booleanslowDeliveryDetected = false;

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
finalPrinter logging = me.mLogging;
if(logging != null) {
logging.println(">>>>> Dispatching to "+ msg.target + " "+
msg.callback + ": "+ msg.what);
}
// Make sure the observer won't change while processing a transaction.
finalObserver observer = sObserver;

finallongtraceTag = me.mTraceTag;
longslowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
longslowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if(thresholdOverride > 0) {
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
finalbooleanlogSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
finalbooleanlogSlowDispatch = (slowDispatchThresholdMs > 0);

finalbooleanneedStartTime = logSlowDelivery || logSlowDispatch;
finalbooleanneedEndTime = logSlowDispatch;

if(traceTag != 0&& Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}

finallongdispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
finallongdispatchEnd;
Object token = null;
if(observer != null) {
token = observer.messageDispatchStarting();
}
longorigWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
try{
msg.target.dispatchMessage(msg);
if(observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch(Exception exception) {
if(observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throwexception;
} finally{
ThreadLocalWorkSource.restore(origWorkSource);
if(traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if(logSlowDelivery) {
if(slowDeliveryDetected) {
if((dispatchStart - msg.when) <= 10) {
                        Slog.w(TAG, "Drained");
                        slowDeliveryDetected = false;
                    }
                } else {
                    if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                            msg)) {
                        // Once we write a slow delivery log, suppress until the queue drains.
                        slowDeliveryDetected = true;
                    }
                }
            }
            if (logSlowDispatch) {
                showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", 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.recycleUnchecked();
        }
    }

代码较长,我们只取关键代码阅读。通过myLooper获取新创建的Looper对象实例,进而获取Looper内部的MessageQueue对象实例。然后进入死循环中不断调用MessageQueue类的next方法获取MessageQueue里的message,然后调用dispatchMessage进行消息分发,最后由handleMessage进行消息处理。到这里Looper、MessageQueue和Handler之间的关系就建立起来了。介于篇幅,发送消息和消息处理原理,下篇文章详细分析。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Android
    +关注

    关注

    12

    文章

    3947

    浏览量

    128420
  • 通信
    +关注

    关注

    18

    文章

    6111

    浏览量

    136753
  • 代码
    +关注

    关注

    30

    文章

    4857

    浏览量

    69498
  • handler
    +关注

    关注

    0

    文章

    7

    浏览量

    3090

原文标题:详解Android Handler机制和原理(一)

文章出处:【微信号:AndroidPush,微信公众号:Android编程精选】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    相关推荐

    Trigger Handler

    handler
    橙群微电子
    发布于 :2023年02月23日 09:04:12

    高保真胆机制详解

    http://115.com/file/be3wripk#高保真胆机制详解.rar
    发表于 02-14 09:54

    Android系统原理与开发要点详解_培训课件

    Android系统原理与开发要点详解_培训课件
    发表于 08-20 13:01

    android 通信机制 socket

    socket 作为一种通信机制,可以实现单机或者跨网络之间的通信,要有明确的server端和client端。android里面最简单的socket 通信的demo://1. IP 地址
    发表于 01-09 22:36

    Android系统下Java编程详解,Android学习者必备

    Android系统下Java编程详解,从各方面对Android系统的学习做出详解,这些都是在华清远见学习的一手资料,可以下载学习哦,我学过了,还是不错的
    发表于 05-30 13:21

    详解Linux内核抢占实现机制

    本文详解了Linux内核抢占实现机制。首先介绍了内核抢占和用户抢占的概念和区别,接着分析了不可抢占内核的特点及实时系统中实现内核抢占的必要性。然后分析了禁止内核抢占的情况和内核抢占的时机,最后介绍了实现抢占内核所做的改动以及何时需要重新调度。
    发表于 08-06 06:16

    AndroidHandler

    在了解 Handler 前,首先需要知道 Android 中,当程序启动时,Android 系统会启动一条线程,该线程也被称作 UI 线程,主要用于进行界面 UI 的操作。而又因为其不是线程安全
    发表于 09-23 09:05

    深入剖析Android消息机制

    深入剖析Android消息机制
    发表于 01-22 21:11 11次下载

    Android开发手册—API函数详解

    Android开发手册—API函数详解
    发表于 10-17 09:01 13次下载
    <b class='flag-5'>Android</b>开发手册—API函数<b class='flag-5'>详解</b>

    基于Android开发手册—API函数详解

    基于Android开发手册—API函数详解
    发表于 10-24 09:06 18次下载
    基于<b class='flag-5'>Android</b>开发手册—API函数<b class='flag-5'>详解</b>

    Android 异步通信原理机制-- handler

    .handler的作用:完成Android中的线程通信(数据的异步加载显示,在子线程中完成耗时操作,在子线程中加载之后通知UI线程显示数据)
    发表于 06-13 01:10 2055次阅读

    家用风力发电机制作过程详解

    家用风力发电机制作过程详解
    的头像 发表于 08-21 16:11 3.6w次阅读

    详细解答Android消息机制

    Android程序运行中,线程之间或者线程内部进行信息交互时经常会使用到消息,如果我们熟悉这些基础的东西及其内部的原理,将会使我们的Android开发变的容易、可以更好地架构系统。在学习Android消息
    发表于 04-24 15:30 521次阅读
    详细解答<b class='flag-5'>Android</b>消息<b class='flag-5'>机制</b>

    Android开发手册API函数详解资料免费下载

    本文档的主要内容详细介绍的是Android开发手册API函数详解资料免费下载。
    发表于 02-22 08:00 0次下载

    矿石收音机制详解

    矿石收音机制详解
    发表于 12-27 17:52 83次下载