首页
社区
课程
招聘
[原创]微信Duilib的List优化和代价
发表于: 2024-7-13 11:19 2788

[原创]微信Duilib的List优化和代价

2024-7-13 11:19
2788

Duilib

Duilib是Windows上一个小巧的C++界面库
微信和企业微信PC端的界面都是基于Duilib魔改
企业微信Duilib魔改出bug:[原创]企业微信转发卡bug的漏洞分析
微信Duilib魔改List达到十倍甚至百倍的优化,可惜没开源,好奇分析了一下


RecyclerView

数据较多但界面有限的问题,比如100个好友最多显示10个
原生Duilib是界面上准备100个位子,10个可见,90个不可见
微信Duilib则是界面上准备10个位子,轮流给10个可见的好友用
上面一个位子空出来,回收成最后一个位子,这就是RecyclerView
图片描述


继承关系

1、原生Duilib的List是:
CListUI -> CVerticalLayoutUI -> CContainerUI

1
2
3
class UILIB_API CListUI : public CVerticalLayoutUI
 
class UILIB_API CVerticalLayoutUI : public CContainerUI

2、微信Duilib的List是:
mmListView -> mmVirtualViewBase -> CVerticalLayoutUI -> CContainerUI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int __thiscall sub_AE21A0(int this)
    sub_AEB0E0(this);
    *this = &mmListView::`vftable';
 
char *__thiscall sub_AEB0E0(char *this)
    sub_1EEFFA0(this);
    *this = &mmVirtualViewBase::`vftable';
 
char *__thiscall sub_1EEFFA0(char *this)
    sub_1ED3C30(this);
    *this = &DuiLib::CVerticalLayoutUI::`vftable';
 
char *__thiscall sub_1ED3C30(char *this)
    sub_1EC8CC0(this);
    *this = &DuiLib::CContainerUI::`vftable';

微信Duilib比原生Duilib多了一层mmVirtualViewBase,实际上就是RecyclerView
因为mmListView和CListUI都继承CVerticalLayoutUI ,布局文件XML可以无缝替换

1
2
<List>...</List>
<mmListView>...</mmListView>

此外,mmGridView和mmGroupTileView也是继承mmVirtualViewBase

1
2
3
4
5
6
7
int __thiscall sub_ADBA00(int this)
    sub_AEB0E0(this);
    *this = &mmGridView::`vftable';
 
char *__thiscall sub_AEB0E0(char *this)
    sub_1EEFFA0(this);
    *this = &mmVirtualViewBase::`vftable';
1
2
3
4
5
6
7
int __thiscall sub_ADDB90(int this)
    sub_AEB0E0(this);
    *this = &mmGroupTileView::`vftable';
 
char *__thiscall sub_AEB0E0(char *this)
    sub_1EEFFA0(this);
    *this = &mmVirtualViewBase::`vftable';

界面滚动

1、原生Duilib只是更新坐标

1
2
3
4
5
6
7
8
9
void CContainerUI::SetScrollPos(SIZE szPos, bool bMsg)
    for( int it2 = 0; it2 < m_items.GetSize(); it2++ )
        CControlUI* pControl = static_cast<CControlUI*>(m_items[it2]);
        RECT rcPos = pControl->GetPos();
        rcPos.left -= cx;
        rcPos.right -= cx;
        rcPos.top -= cy;
        rcPos.bottom -= cy;
        pControl->SetPos(rcPos);

2、微信Duilib则是更新坐标和回收复用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int __thiscall sub_AEC570(char *this, int offset)
    // 1、更新坐标
    while ( index < GetSize(v4) )
        // GetItem
        v8 = sub_1EB5090(v7, index);
        // GetPos
        v9 = (*(*v8 + 88))(v8);
        // SetPos
        (*(*v8 + 92))(v8, *v9 - 0.0, v9[1] - offset, v9[2] - 0.0, v9[3] - offset);
     
    // 2、回收复用
    (*(v10 + 784))(v2, 1); // sub_AE3C70
 
int __thiscall sub_AE3C70(float *this, char a2)
    // 元素在列表上面,需要回收
    if ( rcItem.bottom < rcList.top )

列表变动

1、原生Duilib是修改计数

1
2
3
4
5
6
7
8
9
10
11
CStdPtrArray m_items;
 
class CStdPtrArray
{
  LPVOID* m_ppVoid;
  int m_nCount;
  int m_nAllocated;
}
 
bool CStdPtrArray::Add(LPVOID pData)
    ++m_nCount

2、微信Duilib是修改指针
图片描述


元素变动

数据上可以直观看到回收复用
图片描述
细节1:界面显示6个,第7个预备着
细节2:第1个回收,直接复用为第8个
也就是列表下面总有一个准备好的元素
图片描述


异类元素

如果元素类型都一样,可以直接回收复用
但如果元素类型不一样,插入异类元素,就得特殊处理
微信Duilib的处理方法是:创建异类元素(黄色),保留原始元素(红色)
图片描述
简单粗暴的方法是把多种元素整合成复合元素,代价就是控件空闲率更高
目前微信Duilib控件空闲率比较高:(1843-496)/1843=73%
图片描述
而企业微信Duilib控件空闲率更高:(3210-761)/3210=76%
图片描述


带来代价

有意思的是,微信Duilib的优化也带来了代价
RecyclerView需要先空出位置,才能加入新元素
这就导致滚动的偏移上限不能超过一个元素的大小
微信Duilib需要处理的次数也就变多,用时间换空间
图片描述


架构模式

RecyclerView解决的问题是数据多界面小
解决这个问题的的办法就是把数据和界面分离开
对应的架构模式就可以从MVC变成MVI,安全性更好
微信用的是MVI:if(model.status == SELECTED)
企业微信用的是MVC:if(view.status == SELECTED)
当界面view出漏洞时,MVI不依赖view的数据而变得更安全


相互借鉴

1、电脑端借鉴移动端
微信Duilib里面有字符串:"Recyclebin::addActiveView"
搜索了一下发现是移动端Android源码里面ListView的内部类RecycleBin
ListView的优化版RecyclerView在微信Duilib里面没搜到,改名成mmVirtualViewBase

 

2、移动端借鉴电脑端
再搜索VirtualView,发现了阿里Android的Tangram框架提供VirtualView
VirtualView的核心思想是:编写xml样式文件,在客户端解析直接绘制出界面
这个设计思想和电脑端的Duilib一样:DirectUI,在主界面上直接绘制出所有控件


参考资料

实战 | 认识 RecyclerView
图解 RecyclerView 的缓存机制
RecyclerView  |  Android Developers
ListView源码阅读:RecycleBin缓存机制以及二次onLayout_activeview引用


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2024-7-27 16:13 被GhHei编辑 ,原因:
收藏
免费 2
支持
分享
最新回复 (2)
雪    币: 128
活跃值: (947)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
网易 Duilib 的虚拟列表 也不错啊几十万也还行就是占用内存大
2024-7-13 21:44
0
雪    币: 761
活跃值: (628)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
学习了
2024-7-24 14:35
0
游客
登录 | 注册 方可回帖
返回
//