/
FragmentStateListAdapter.kt
154 lines (137 loc) · 5.33 KB
/
FragmentStateListAdapter.kt
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package com.github.panpf.assemblyadapter.pager2
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
import androidx.recyclerview.widget.AdapterListUpdateCallback
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.AsyncListDiffer.ListListener
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.adapter.FragmentStateAdapter
/**
* [AsyncListDiffer] version of [FragmentStateAdapter], similar to [ListAdapter]
*/
abstract class FragmentStateListAdapter<DATA> : FragmentStateAdapter {
val mDiffer: AsyncListDiffer<DATA>
private val mListener: ListListener<DATA> = ListListener<DATA> { previousList, currentList ->
onCurrentListChanged(previousList, currentList)
}
constructor(
fragmentManager: FragmentManager,
lifecycle: Lifecycle,
diffCallback: DiffUtil.ItemCallback<DATA>
) : super(fragmentManager, lifecycle) {
mDiffer = AsyncListDiffer<DATA>(
AdapterListUpdateCallback(this),
AsyncDifferConfig.Builder(diffCallback).build()
)
mDiffer.addListListener(mListener)
}
constructor(
fragment: Fragment,
diffCallback: DiffUtil.ItemCallback<DATA>
) : this(fragment.childFragmentManager, fragment.lifecycle, diffCallback)
constructor(
activity: FragmentActivity,
diffCallback: DiffUtil.ItemCallback<DATA>
) : this(activity.supportFragmentManager, activity.lifecycle, diffCallback)
constructor(
fragmentManager: FragmentManager,
lifecycle: Lifecycle,
config: AsyncDifferConfig<DATA>
) : super(fragmentManager, lifecycle) {
mDiffer = AsyncListDiffer(AdapterListUpdateCallback(this), config)
mDiffer.addListListener(mListener)
}
constructor(
fragment: Fragment,
config: AsyncDifferConfig<DATA>
) : this(fragment.childFragmentManager, fragment.lifecycle, config)
constructor(
activity: FragmentActivity,
config: AsyncDifferConfig<DATA>
) : this(activity.supportFragmentManager, activity.lifecycle, config)
/**
* Submits a new list to be diffed, and displayed.
*
*
* If a list is already being displayed, a diff will be computed on a background thread, which
* will dispatch Adapter.notifyItem events on the main thread.
*
* @param list The new list to be displayed.
*/
open fun submitList(list: List<DATA>?) {
mDiffer.submitList(list)
}
/**
* Set the new list to be displayed.
*
*
* If a List is already being displayed, a diff will be computed on a background thread, which
* will dispatch Adapter.notifyItem events on the main thread.
*
*
* The commit callback can be used to know when the List is committed, but note that it
* may not be executed. If List B is submitted immediately after List A, and is
* committed directly, the callback associated with List A will not be run.
*
* @param list The new list to be displayed.
* @param commitCallback Optional runnable that is executed when the List is committed, if
* it is committed.
*/
open fun submitList(list: List<DATA>?, commitCallback: Runnable?) {
mDiffer.submitList(list, commitCallback)
}
protected fun getItem(position: Int): DATA {
return mDiffer.currentList[position]
}
override fun getItemCount(): Int {
return mDiffer.currentList.size
}
/**
* Note: [getItemId] is final, because stable IDs are unnecessary and therefore unsupported.
*
* [FragmentStateListAdapter]'s async diffing means that efficient change animations are handled for
* you, without the performance drawbacks of [RecyclerView.Adapter.notifyDataSetChanged].
* Instead, the diffCallback parameter of the [FragmentStateListAdapter] serves the same
* functionality - informing the adapter and [RecyclerView] how items are changed and moved.
*/
final override fun getItemId(position: Int): Long {
return super.getItemId(position)
}
/**
* Get the current List - any diffing to present this list has already been computed and
* dispatched via the ListUpdateCallback.
*
*
* If a `null` List, or no List has been submitted, an empty list will be returned.
*
*
* The returned list may not be mutated - mutations to content must be done through
* [.submitList].
*
* @return The list currently being displayed.
*
* @see .onCurrentListChanged
*/
val currentList: List<DATA>
get() = mDiffer.currentList
/**
* Called when the current List is updated.
*
*
* If a `null` List is passed to [.submitList], or no List has been
* submitted, the current List is represented as an empty List.
*
* @param previousList List that was displayed previously.
* @param currentList new List being displayed, will be empty if `null` was passed to
* [.submitList].
*
* @see .getCurrentList
*/
open fun onCurrentListChanged(previousList: List<DATA>, currentList: List<DATA>) {
}
}