Android:Handler相关面试题整理

39 篇文章 0 订阅
33 篇文章 1 订阅


前言

如果没有进行过Handler源码相关阅读和整理,强烈建议先看笔者的这篇博客
Handler消息机制整理
这篇记录Handler相关面试题的学习和整理

一、题目

1.Handler Looper MessageQueue之间的关系是什么

见这篇博客
Handler消息机制整理

2.为何可以在主线程中new Handler,如果要在子线程中new Handler需要做什么工作?

子线程中使用Handler必须使用Looper.prepare() &&Looper.Loop()方法去开启Loop
主线程中一启动,就已经了进行了Looper.prepareMainLooper() &&Looper.Loop()方法相关工作

3.子线程中维护的Looper,当消息队列无消息的时候,处理方案是什么

当消息队列无消息时,应该调用Looper.quitSafe()或者Looper.quit()方法,清空消息队列中的消息,而后清空message的target callback data等内容,可以释放内存,避免内存泄漏

如果不处理,直接阻塞了,具体原因看上面那篇博客

//Message.java
    void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = -1;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }

4.既然可以存在多个handler 往mq中add 数据,那内部是如何确保线程数据安全的?

//MessageQueue.java
    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }
...

上了synchronized的锁

5.一个线程可以有几个handler

如果使用过handler的同学都知道在实际使用过程中可以有无数个handler。

6.一个线程可以有几个looper

只能有一个,每次Looper.prepare会采用类似键值对的形式往threadholder里面扔一个线程和其对应的Looper进去

7.handler的内存泄漏的原因?为什么其他的内部类没有提说过有这个问题?

在调用到Message的enqueueMessage的是否会将 handler赋值给 message的target,而Message 在 messagequeue中等待的时候如果生命周期发生变化但是message中的target不释放就会导致泄漏,毕竟内存泄漏就是生命周期不相等导致的

8.使用Handler的postDelay后消息队列会有什么变化

//Handler.java
   public final boolean postDelayed(Runnable r, long delayMillis)
    {
        return sendMessageDelayed(getPostMessage(r), delayMillis);
    }
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

我们可以看到在调用enqueueMessage的之前都是传入了一个时间值,而在messagequeue的源码中,message也是按照时间顺序排列的 一个队列。在插入之后会查看是否需要wake。如果我们插入的是一个time为0的时候messagequeue会立刻唤醒,如果插入的是一个延迟任务,将不会唤醒messagequeue。

8.looper死循环为什么不会导致应用卡死?

looper的死循环的机制本质是一个for循环,并不是因为消息没有处理导致的死循环
ANR产生的原因是因为将一个事件封装成Msg之后发送出去,计算这个Msg处理事件的回调是否超过五秒,如果超过五秒,就调用Handler进行一个ANR提醒

9.Handler消息遇到紧急消息如何处理(消息机制的同步屏障)

关联问题:同步屏障问题,涉及源码如下:
在Message的next()方法中

if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
  • 开启同步屏障的方法:往消息队列中添加一个msg.target==null的消息
  • 而后Message的next()会一直往后遍历,优先处理异步的消息(msg.isAsynchronous()==true)
  • 而后移除消息屏障

相关源码:viewRootImple

总结

祝自己上岸

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值