面试 - handle之详谈Message(2)

面试handler系列:
上一篇:面试 - handle使用及原理(1)

Message的创建方式

面试的时候如果问你Message有几种创建方式 ?

  1. Message msg = New Message()
    这种方式就不用怎么多说 直接就是创建了一个Message对象出来

  2. myHander.obtainMessage();myHandlerHandler类型的

直接使用该方法就可以创建一个Message,看一下这源码

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

里面调用了我们要提到了第三个创建Message的方法

  1. Message.obtain():
public static Message obtain(Handler h) {
        Message m = obtain();
        m.target = h;

        return m;
    }

   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();
    }

上面的obtain()源码中,使用了一个链表结构存储Message作为一个缓存池,这样子可以避免重复创建多个实现对象。

第二种创建方法,只是先调用第三种从缓存池中获取到Message的对象再将Handler赋值入给Message.target
以上三种都是创建Message的方法

Message缓存池相关

Message的数据结构中

public final class Message implements Parcelable {
        ......
    /*package*/ Message next;
}

这个很明显是一个链表的结构,我们来看一下

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();
    }

解析一下上面的源码:
如果sPool这条Message的单链表不为null,取出链表头的Message,重置一下sPoolsPoolSize(记录链表的长度)减一
如果sPoolnull则返回一个新的Message对象

看一下添加MessagesPool的这个方法

    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++;
            }
        }
    }

解释一下上面的源码:
清除一些变量信息,然后判断一下链表没有没超过最大值,没有就添加到链头并将链表大小加一

    private static final int MAX_POOL_SIZE = 50;

链表的最大值为50

这个Message的细节就差不多看完了,主要是理解一下这种缓存池设计的一个思想吧,对于频繁创建的对象,我们最好是可以增加一个缓存池,需要对象的时候直接在里面获取到之前已经创建过的对象。而不是每次都是直接去创建。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`drag-handle` 和 `right-handle` 属性通常是自定义的 CSS 类,它们可能被用于实现拖拽功能。实现拖拽功能的关键在于监听鼠标事件,然后根据鼠标的位置和移动距离,将元素的位置进行相应的调整。 以下是一个简单的实现拖拽功能的示例代码: ```html <div class="drag-handle right-handle"></div> <script> const handle = document.querySelector('.drag-handle.right-handle'); handle.addEventListener('mousedown', (event) => { event.preventDefault(); // 防止默认行为,比如选中文本 const startX = event.clientX; // 记录鼠标按下时的位置 const startY = event.clientY; const element = handle.parentElement; // 获取需要拖拽的元素 const handleMouseMove = (event) => { const deltaX = event.clientX - startX; // 计算鼠标移动的距离 const deltaY = event.clientY - startY; element.style.transform = `translate(${deltaX}px, ${deltaY}px)`; // 调整元素的位置 }; const handleMouseUp = () => { document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); }; document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', handleMouseUp); }); </script> ``` 该示例代码监听了 `mousedown` 事件,当鼠标按下时保存了鼠标的位置和需要拖拽的元素,然后添加了 `mousemove` 和 `mouseup` 事件的监听器,当鼠标移动时计算出鼠标移动的距离并改变元素的位置,当鼠标松开时移除监听器。 当然,这只是一个简单的示例代码,实际的拖拽功能可能需要更多的处理,比如限制拖拽的范围、处理元素与其他元素的碰撞等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值