前言
在维护 Android Framework 层时,常常能看到对 KeyedVector
与 DefaultKeyedVector
的使用。并且我们内部的服务框架也有用到 KeyedVector
这个结构。但在维护项目的过程中,我们发现它可能会导致数据处理顺序出现混乱的情况,我认为这一定是因为我们对这个结构不够了解导致的。关于这个结构内部的具体实现,我觉得我有必要去了解清楚,以便在后续的使用中能够发挥出它的最大功效,并且避免一些出问题的情况。
根据引用的头文件名,我们可以到 Android 源码目录下的 system/core/libutils/include
中找到相应的头文件。
浏览相关头文件,可以看到在 Android 内置的 Utils 中,有四种可用的 Vector 结构:
Vector
SortedVector
KeyedVector
DefaultKeyedVector
这些类之间的关系如下图:
由图可知:
Vector
与SortedVector
分别继承自抽象类VectorImpl
与SortedVectorImpl
(而后者又是前者的子类),这两个抽象类实现了一些重要的底层操作。Vector
与SortedVector
之间具有依赖关系(后者成员函数中有前者类型的参数)。KeyedVector
相对独立,它与SortedVector
是关联关系(前者有一个后者类型的成员变量)。DefaultKeyedVector
继承自KeyedVector
,而根据代码来看,它们之间没有多少差异。
首先要读懂 VectorImpl
与 SortedVectorImpl
,然后再看 Vector
与 SortedVector
。最后就要看我的重点 KeyedVector
,这时候应该就有一个比较清晰的理解了。DefaultKeyedVector
差别不大,和 KeyedVector
一起看就行。
相关文章
- Android Utils 之 Vector 学习笔记(一)—— VectorImpl 代码分析
- Android Utils 之 Vector 学习笔记(二)—— SortedVectorImpl 代码分析
- Android Utils 之 Vector 学习笔记(三)—— Vector 与 SortedVector 代码分析
- Android Utils 之 Vector 学习笔记(四,完结)—— KeyedVector 与 DefaultKeyedVector 代码分析
头文件
文件路径:system\core\libutils\include\utils\VectorImpl.h
概览:
- 开头的注释内容:这个类是实现
Vector
类的核心部分。它能保证逆向二进制兼容,并且减少代码量。考虑性能原因,将mStorage
与mCount
两个内部字段暴露出来,它们是固定不变的。 - 第 13~17 行:传入构造函数的标志位,表示是否为
trivial
类型。其中,ctor
表示构造函数,dtor
即是析构,copy
则表示拷贝。 - 第 24 行:子类析构时必须调用的函数,涉及到内存空间的释放与内部成员重置。
- 第 29 行:用于以 C 语言数组风格返回 Vector 的访问指针,但不能对其进行编辑操作。
- 第 30 行:用于以 C 语言数组风格返回 Vector,并且可以对内容进行编辑。
- 第 40~43 行:用于往当前 Vector 中插入(或末尾追加)另一个 Vector(或数组)。
- 第 46~57 行:用于增加、插入、替换以及删除 Vector 中的单个元素。
- 第 58 行:用于清空(重置) Vector。
- 第 60、61 行:用于查找
index
位置对应的元素,注意名带 edit 的返回的是可编辑的结果。 - 第 63~66 行:定义两个函数指针,用于指向自定义的比较函数。
sort
函数则是基于比较函数进行排序。 - 第 70 行:用于释放
mStorage
的存储空间。 - 第 72~77 行:一组纯虚函数,在子类中必须进行具体实现。
- 第 80、81 行:用于从 Vector 的
where
位置开始扩充(或收缩)。 - 第 83~88 行:这些内联函数与前面的那组纯虚函数是一一对应的,各自的功能已经由其函数名表述清楚了。
- 第 92~96 行:内部成员变量,分别存储了 Vector 数据首地址、元素总数、关于
trivial
类型的标志,以及单个元素的数据大小。
/*!
* Implementation of the guts of the vector<> class
* this ensures backward binary compatibility and
* reduces code size.
* For performance reasons, we expose mStorage and mCount
* so these fields are set in stone.
*
*/
class VectorImpl
{
public:
enum { // flags passed to the ctor
HAS_TRIVIAL_CTOR = 0x00000001,
HAS_TRIVIAL_DTOR = 0x00000002,
HAS_TRIVIAL_COPY = 0x00000004,
};
VectorImpl(size_t itemSize, uint32_t flags);
VectorImpl(const VectorImpl& rhs);
virtual ~VectorImpl();
/*! must be called from subclasses destructor */
void finish_vector();
VectorImpl& operator = (const VectorImpl& rhs);
/*! C-style array access */
inline const void* arrayImpl() const { return mStorage; }
void* editArrayImpl();
/*! vector stats */
inline size_t size() const { return mCount; }
inline bool isEmpty() const { return mCount == 0; }
size_t capacity() const;
ssize_t setCapacity(size_t size);
ssize_t resize(size_t size);
/*! append/insert another vector or array */
ssize_t insertVectorAt(const VectorImpl& vector, size_t index);
ssize_t appendVector(const VectorImpl& vector);
ssize_t insertArrayAt(const void* array, size_t index, size_t length);
ssize_t appendArray(const void* array, size_t length);
/*! add/insert/replace items */
ssize_t insertAt(size_t where, size_t numItems = 1);
ssize_t insertAt(const void* item, size_t where, size_t numItems = 1);
void pop();
void push();
void push(const void* item);
ssize_t add();
ssize_t add(const void* item);
ssize_t replaceAt(size_t index);
ssize_t replaceAt(const void* item, size_t index);
/*! remove items */
ssize_t removeItemsAt(size_t index, size_t count = 1);
void clear();
const void* itemLocation(size_t index) const;
void* editItemLocation(size_t index);
typedef int (*compar_t)(const void* lhs,