千家信息网

Handler相关面试题有哪些

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,本篇内容主要讲解"Handler相关面试题有哪些",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"Handler相关面试题有哪些"吧!1.获取Message实
千家信息网最后更新 2026年11月01日Handler相关面试题有哪些

本篇内容主要讲解"Handler相关面试题有哪些",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"Handler相关面试题有哪些"吧!

1.获取Message实例的方式有哪些?哪一种更好?

获取Message实例的方法主要有两种,一种是直接创建,Message msg = new Message。另一种是通过Message.obtain()或者Handler.obtatinMessage()来得到一个Message对象。更推荐使用后一种方式,这种方式得到的对象是从对象回收池中得到,复用已经处理完的Message对象,而不是重新生成一个新对象。Message.obtain()和Handler.obtatinMessage()最终都是调用了Message类的obtain()方法,查看方法内容,就知道是从对象回收池里得到Message。

  public static Message obtain() {          synchronized (sPoolSync) {              if (sPool != null) {                  Message m = sPool;                  sPool = m.next;                  m.next = null;                  m.flags = 0; // clear in-use flag                  sPoolSize--;                  return m;              }          }          return new Message();    }

2.当Activity有多个Handler的时候,Message消息是否会混乱?怎么样区分当前消息由哪个Handler处理?

不会混乱,哪个Handler发送的消息,到时候也是这个handler处理。在发送消息的时候,会绑定target,这个target就是Handler本身,当需要handler调用dispatchMessage(msg)处理消息的时候,这个Handler就是发送消息时绑定的handler。
无论用哪一种方法发送消息,最终都会调用enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)来发送消息

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

这里的this,就是当前的handler。在来看需要Handler处理消息的时候,取的是哪一个handler,下面贴出主要源码。

 public static void loop() {  ......        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         ......            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));            }            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;            final long dispatchEnd;            try {                msg.target.dispatchMessage(msg);                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;            } finally {                if (traceTag != 0) {                    Trace.traceEnd(traceTag);                }            }           ......            msg.recycleUnchecked();        }    }

这是循环消息时的部分代码,处理消息代码是msg.target.dispatchMessage(msg);,这里的target就是当时发送消息的handler。

3.在子线程发送消息,却能够在主线程接收消息,主线程和子线程是怎么样切换的?

子线程用handler发送消息,发送的消息被送到与主线程相关联的MessageQueue,也是主线程相关联的Looper在循环消息,handler所关联的是主线程的Looper和MessageQueue,所以最后消息的处理逻辑也是在主线程。只有发送消息是在子线程,其它都是在主线程,Handler与哪个线程的Looper相关联,消息处理逻辑就在与之相关的线程中执行,相应的消息的走向也就在相关联的MessageQueue中。所以子线程切换到主线程是很自然的过程,并没有想象中的复杂。

4.能不能在子线程中创建Handler?

可以,但是在创建前先调用prepare()方法创建Looper。Handler创建的时候,会去检查是否有创建Looper,如果没有创建就会抛出异常。相关源码如下:

 public Handler(Callback callback, boolean async) {     ......        mLooper = Looper.myLooper();        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread " + Thread.currentThread()                        + " that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;        mCallback = callback;        mAsynchronous = async;    }

所以我们在子线程需要先调用prepare()方法创建Looper。这里还多提一点,在主线程创建就不需要自己创建Looper,因为在ActivityTread类里面,已经为我们创建好了,相关源码如下:

 public static void main(String[] args) {     ......        Looper.prepareMainLooper();// 为主线程创建looper        // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.        // It will be in the format "seq=114"        long startSeq = 0;        if (args != null) {            for (int i = args.length - 1; i >= 0; --i) {                if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {                    startSeq = Long.parseLong(                            args[i].substring(PROC_START_SEQ_IDENT.length()));                }            }        }        ActivityThread thread = new ActivityThread();        thread.attach(false, startSeq);        if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();        }        if (false) {            Looper.myLooper().setMessageLogging(new                    LogPrinter(Log.DEBUG, "ActivityThread"));        }        // End of event ActivityThreadMain.        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);        Looper.loop();        throw new RuntimeException("Main thread loop unexpectedly exited");    }

Looper.prepareMainLooper();这句代码就是为主线程创建Looper。 所以在主线程中直接创建一个Handler,就直接可以循环消息,因为安卓的主线程已经为我们准备好了Looper。

5.一个线程可以有几个Handler?几个Looper?

一个线程可以有多个Handler,但是只有一个Looper。创建Handler之前,需要创建Looper,否则会报错。源码里面已经做了说明。

 public Handler(Callback callback, boolean async) {   ......        mLooper = Looper.myLooper();        if (mLooper == null) {//判断Looper是否被创建            throw new RuntimeException(                "Can't create handler inside thread " + Thread.currentThread()                        + " that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;        mCallback = callback;        mAsynchronous = async;    }

在来看Looper的创建,是在prepare()方法里。

  // sThreadLocal.get() will return null unless you've called prepare().  static final ThreadLocal sThreadLocal = new ThreadLocal();  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是否存在,存在就会抛出Only one Looper may be created per thread异常,这是在告诉我们一个线程只能有一个Looper。而TreadLocal的作用就是线程间隔离,确保一个线程对应一个Looper。还可以看看Looperg构造方法的源码

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

MessageQueue的创始化是在Looper的构造方法里。不管一个线程有多少个Handler,相关联的都是同一个Looper和MessageQueue。

关于Handler,可以问的问题有很多,以上只是抽出一些我认为比较重要的问题。在寻找答案以后,我将Handler机制的整个过程在脑海中过了一遍,并且画了个草图。

Handler机制中重要类的相互关联图

Handler机制原理涉及几个重要的类:Handler、Message、MessageQueue、Looper。
就用子线程向主线程发送消息来说明整个过程。
首先在主线程创建一个Handler,在Handler类里面会创建Looper以及MessageQueue的对象,并且在Handler构造方法里面赋值

 final Looper mLooper; final MessageQueue mQueue; public Handler(Callback callback, boolean async) { ......        mLooper = Looper.myLooper();        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread " + Thread.currentThread()                        + " that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;        mCallback = callback;        mAsynchronous = async;    }

mLooper = Looper.myLooper();得到的Looper是主线程的Looper
mQueue = mLooper.mQueue;得到的MessageQueue就是在Looper构造方法里面创建的MessageQueue。
创建好了Handler实例,我们就会在子线程调用handler.sendMessage(msg);发送消息,将message放到MessageQueue里面。在enqueueMessage()里面就给每个message设置target,这个target就是当前的handler。

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

再然后调用Looper.loop();(在ActivityThread的main()里面已经帮我们写好)开始循环消息,拿到消息以后就会用handler取出消息进行处理,重点代码是msg.target.dispatchMessage(msg);,这里的handler就和一开始我们为message设置的Handler对应。

  /**       * 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);          }      }

最后我们在Handler的handleMessage(msg)里面去处理我们的消息。
这就是子线程给主线程发送消息的整个过程,源码很多,我只是截取了部分重点。这里多提一点就是线程处理消息。 在线程中处理消息需要做三件事情

1. 先创建一个Looper (Looper.prepare()) 2. 再创建Handler,默认是和当前线程的Looper关联起来 3. 循环消息(Looper.loop())

这三个步骤的顺序不能调换。因为主线程已经帮我们创建了Looper,所以我们不需要写,如果是在子线程创建Looper就需要了。

Handler机制的理解要靠自己去琢磨,不断的看源码,去理解,理清它们之间的互相调用。只有比较深入的理解了Handler,才能在面试中回答面试官的问题,靠死记硬背是不可取的。

到此,相信大家对"Handler相关面试题有哪些"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

线程 消息 方法 处理 就是 是在 关联 对象 源码 时候 循环 代码 机制 过程 重要 内容 只有 实例 方式 问题 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网高科技 河南云网互联网络科技有限公司 国智互联网科技 科技制造互联网公司 深圳天众互联网科技公司 齐家互联网科技有限公司 互联网科技类展会 华脉科技工业互联网产品 中国的互联网科技企业的崛起 福州新华互联网科技学校 知乎 昭通云南众福互联网科技有限公司 新兴科技互联网创新大赛颁奖典礼 速维有品互联网信息科技(苏州)有限公司 国大互联网教育科技有限公司薪资 众安科技工业互联网合作 江苏互联网智能科技产品出厂价 互联网科技博主张洲 保山浩联互联网科技有限公司 六子台科技互联网展会 武汉亿视互联网科技有限公司 深圳九邦互联网科技有限公司 喔噻互联网科技 互联网科技股票 互联网科技媒体 亿策互联网科技 天津摩尔互联网科技 山东吉时兔互联网科技有限公司 汉立互联网科技有限公司联系电话 河南住房之家互联网科技 恒生互联网科技业指数调整周期
0