背景

工作中经常会遇到 最近 等类似功能,这些功能都需要保存相应的对象信息,但是由于这些对象在每次重新启动后都会再次初始化加载到内存中,可以通过只保存对象的某种唯一标志简单快速实现 最近 等类似功能。

原理

  1. 当需要保存 最近 对应的对象信息时,只保存对象的 key 信息,将 key 集合信息通过 , 连接转换成一个字符串后,通过 SP 保存
  2. 当 App 初始化 最近 相关的对象时,将这些对象根据 key 保存在一个 Map 中
  3. 当需要加载 最近 信息时,根据 SP 中存储的 key 信息和上面 Map 中存储的对象信息可以得出想要的 最近 对应的对象信息

实现

基类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
open class XLItemStore(private val context: Context, private val storeKey: String) {
private val executor = Executors.newSingleThreadExecutor(XLThreadFactory())
private val key2ObjectMap = mutableMapOf<String, StorableItem>()

fun addKeyToObject(item: StorableItem) {
if (key2ObjectMap.containsKey(item.key)) {
return
}
key2ObjectMap[item.key] = item
}

fun clearKeyToObject() {
key2ObjectMap.clear()
}

protected fun saveItem(items: Collection<StorableItem>) {
executor.submit {
val itemKeys = StringBuilder("")
items.forEach {
if (itemKeys.isNotEmpty()) {
itemKeys.append(",")
}
itemKeys.append(it.key)
}
saveBySp(itemKeys.toString())
}
}

protected fun loadItems(container: MutableSet<StorableItem>) {
val keyList = getKeysBySp().split(",")
keyList.forEach {
(key2ObjectMap[it])?.let { item ->
container.add(item)
}
}
}

private fun saveBySp(value: String) {
val sp = context.getSharedPreferences("xl_item", Context.MODE_PRIVATE)
sp.edit().putString(storeKey, value).apply()
}

private fun getKeysBySp(): String {
val sp = context.getSharedPreferences("xl_item", Context.MODE_PRIVATE)
return sp.getString(storeKey, "") ?: ""
}
}

private class XLThreadFactory : ThreadFactory {
private val namePrefix = "XL.Thread"
private val group = Thread.currentThread().threadGroup!!
private val threadNumber = AtomicInteger(1)

override fun newThread(r: Runnable?): Thread {
val thread = Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0)
if (thread.isDaemon) {
thread.isDaemon = false
}
if (thread.priority != Thread.NORM_PRIORITY) {
thread.priority = Thread.NORM_PRIORITY
}
return thread
}
}

interface StorableItem {
val key: String
}

最近

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class RecentItemStore(context: Context, storeKey: String) : XLItemStore(context, storeKey) {
private val displayNum = -1
private val recentItems = LinkedHashSet<StorableItem>()

fun restore() {
if (recentItems.isNotEmpty()) {
recentItems.clear()
}
loadItems(recentItems)
}

fun getRecentItems(): Set<StorableItem> {
return recentItems
}

fun saveRecentItem(item: StorableItem) {
val oldItem = recentItems.firstOrNull { it.key == item.key }
recentItems.remove(oldItem)
recentItems.add(item)

if (recentItems.size > displayNum && displayNum > 0) {
recentItems.remove(recentItems.iterator().next())
}
saveItem(recentItems)
}

fun removeRecentItems() {
clearKeyToObject()
recentItems.clear()
}
}

具体使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 初始化存储类
val store = RecentItemStore(...)

// App 加载数据的时候将相关的对象加入到 Map 中
store.addKeyToObject(...)

// 具体使用前,需要先加载数据
store.restore()

// 获取最近数据
store.getRecentItems()

// 当需要添加新的最近数据时
store.saveRecentItem(...)