@@ -5,6 +5,20 @@ import android.view.View
55import android.view.ViewGroup
66import androidx.recyclerview.widget.DiffUtil
77import androidx.recyclerview.widget.RecyclerView
8+ import com.devrapid.adaptiverecyclerview.MessageType.MESSAGE_ADD_LIST
9+ import com.devrapid.adaptiverecyclerview.MessageType.MESSAGE_ADD_SINGLE
10+ import com.devrapid.adaptiverecyclerview.MessageType.MESSAGE_APPEND_LIST
11+ import com.devrapid.adaptiverecyclerview.MessageType.MESSAGE_APPEND_SINGLE
12+ import com.devrapid.adaptiverecyclerview.MessageType.MESSAGE_DROP_ALL
13+ import com.devrapid.adaptiverecyclerview.MessageType.MESSAGE_DROP_RANGE
14+ import com.devrapid.adaptiverecyclerview.MessageType.MESSAGE_DROP_SINGLE
15+ import com.devrapid.adaptiverecyclerview.MessageType.MESSAGE_REPLACE_ALL
16+ import kotlinx.coroutines.Dispatchers
17+ import kotlinx.coroutines.GlobalScope
18+ import kotlinx.coroutines.launch
19+ import kotlinx.coroutines.runBlocking
20+ import kotlinx.coroutines.withContext
21+ import java.util.ArrayDeque
822
923/* *
1024 * An adaptive [RecyclerView] which accepts multiple type layout.
@@ -14,6 +28,9 @@ import androidx.recyclerview.widget.RecyclerView
1428 */
1529abstract class AdaptiveAdapter <VT : ViewTypeFactory , M : IVisitable <VT >, VH : RecyclerView .ViewHolder > :
1630 RecyclerView .Adapter <VH >() {
31+ protected abstract var typeFactory: VT
32+ protected abstract var dataList: MutableList <M >
33+ // region Header and Footer
1734 var headerEntity: M ? = null
1835 set(value) {
1936 if (field == value) return // If the same, we don't do operations as the following below.
@@ -56,7 +73,8 @@ abstract class AdaptiveAdapter<VT : ViewTypeFactory, M : IVisitable<VT>, VH : Re
5673 }
5774 field = value
5875 }
59- open var diffUtil: AdaptiveDiffUtil <VT , M > = MultiDiffUtil ()
76+ // endregion
77+ open var diffUtil: AdaptiveDiffUtil <VT , M > = DefaultMultiDiffUtil ()
6078 open var useDiffUtilUpdate = true
6179 val dataItemCount: Int
6280 get() {
@@ -66,23 +84,7 @@ abstract class AdaptiveAdapter<VT : ViewTypeFactory, M : IVisitable<VT>, VH : Re
6684
6785 return size
6886 }
69-
70- protected abstract var typeFactory: VT
71- protected abstract var dataList: MutableList <M >
72-
73- inner class MultiDiffUtil : AdaptiveDiffUtil <VT , M >() {
74- override var oldList = mutableListOf<M >()
75- override var newList = mutableListOf<M >()
76-
77- override fun getOldListSize () = oldList.size
78-
79- override fun getNewListSize () = newList.size
80-
81- override fun areItemsTheSame (oldItemPosition : Int , newItemPosition : Int ) =
82- oldList[oldItemPosition].hashCode() == newList[newItemPosition].hashCode()
83-
84- override fun areContentsTheSame (oldItemPosition : Int , newItemPosition : Int ) = true
85- }
87+ private val queue = ArrayDeque <Message <M >>()
8688
8789 // region Necessary override methods.
8890 override fun getItemCount () = dataList.size
@@ -102,39 +104,98 @@ abstract class AdaptiveAdapter<VT : ViewTypeFactory, M : IVisitable<VT>, VH : Re
102104
103105 fun listDescription () = dataList.joinToString(" \n " ) { it.toString() }
104106
105- open fun appendList (list : MutableList <M >) {
107+ open fun append (list : MutableList <M >) {
108+ queue.add(Message <M >().also {
109+ it.type = MESSAGE_APPEND_LIST
110+ it.newList = list
111+ })
112+ runUpdateTask()
113+ }
114+
115+ open fun append (item : M ) {
116+ queue.add(Message <M >().also {
117+ it.type = MESSAGE_APPEND_SINGLE
118+ it.newItem = item
119+ })
120+ runUpdateTask()
121+ }
122+
123+ open fun add (position : Int , list : MutableList <M >) {
124+ queue.add(Message <M >().also {
125+ it.type = MESSAGE_ADD_LIST
126+ it.position = position
127+ it.newList = list
128+ })
129+ runUpdateTask()
130+ }
131+
132+ open fun add (position : Int , item : M ) {
133+ queue.add(Message <M >().also {
134+ it.type = MESSAGE_ADD_SINGLE
135+ it.newItem = item
136+ })
137+ runUpdateTask()
138+ }
139+
140+ open fun dropRange (range : IntRange ) {
141+ queue.add(Message <M >().also {
142+ it.type = MESSAGE_DROP_RANGE
143+ it.range = range
144+ })
145+ runUpdateTask()
146+ }
147+
148+ open fun dropAt (index : Int ) {
149+ queue.add(Message <M >().also {
150+ it.type = MESSAGE_DROP_SINGLE
151+ it.position = index
152+ })
153+ runUpdateTask()
154+ }
155+
156+ open fun clearList (header : Boolean = true, footer : Boolean = true) {
157+ queue.add(Message <M >().also {
158+ it.type = MESSAGE_DROP_ALL
159+ it.header = header
160+ it.footer = footer
161+ })
162+ runUpdateTask()
163+ }
164+
165+ open fun replaceWholeList (newList : MutableList <M >) {
166+ queue.add(Message <M >().also {
167+ it.type = MESSAGE_REPLACE_ALL
168+ it.newList = newList
169+ })
170+ runUpdateTask()
171+ }
172+
173+ // region Inner operations
174+ protected open fun _append (list : MutableList <M >): MutableList <M > {
106175 var startIndex = dataList.size
107176 if (footerEntity != null )
108177 startIndex--
109178 // [toMutableList()] will create a new [ArrayList].
110- val newList = dataList.toMutableList().apply { addAll(startIndex, list) }
111- updateList { newList }
179+ return dataList.toMutableList().apply { addAll(startIndex, list) }
112180 }
113181
114- open fun append (item : M ) {
115- val newList = dataList.toMutableList().apply {
116- if (footerEntity != null ) add(dataList.size - 1 , item) else add(item)
117- }
118- updateList { newList }
182+ protected open fun _append (item : M ) = dataList.toMutableList().apply {
183+ if (footerEntity != null ) add(dataList.size - 1 , item) else add(item)
119184 }
120185
121- open fun add (position : Int , item : M ) {
186+ protected open fun _add (position : Int , list : MutableList <M >) = dataList.toMutableList().apply {
187+ addAll(position + (if (headerEntity == null ) 0 else 1 ), list)
188+ }
189+
190+ protected open fun _add (position : Int , item : M ): MutableList <M > {
122191 if (dataItemCount <= 0 ) throw IndexOutOfBoundsException ()
123192
124- val newList = dataList.toMutableList().apply {
193+ return dataList.toMutableList().apply {
125194 add(position + (if (headerEntity == null ) 0 else 1 ), item)
126195 }
127- updateList { newList }
128- }
129-
130- open fun add (position : Int , list : MutableList <M >) {
131- val newList = dataList.toMutableList().apply {
132- addAll(position + (if (headerEntity == null ) 0 else 1 ), list)
133- }
134- updateList { newList }
135196 }
136197
137- open fun dropRange (range : IntRange ) {
198+ protected open fun _dropRange (range : IntRange ): MutableList < M > {
138199 var start = range.start
139200
140201 when {
@@ -148,20 +209,22 @@ abstract class AdaptiveAdapter<VT : ViewTypeFactory, M : IVisitable<VT>, VH : Re
148209 // Count the range.
149210 if (headerEntity != null ) start++
150211 repeat(range.count()) { newList.removeAt(start) }
151- updateList { newList }
152- }
153212
154- open fun dropAt (index : Int ) {
155- dropRange(index.. index)
213+ return newList
156214 }
157215
158- open fun clearList (header : Boolean = true, footer : Boolean = true): Boolean {
159- if (header) headerEntity = null
160- if (footer) footerEntity = null
216+ protected open fun _dropAt (index : Int ) = _dropRange (index.. index)
161217
162- dropRange(0 .. (dataItemCount - 1 ))
218+ protected open fun _clearList (header : Boolean = true, footer : Boolean = true): MutableList <M > = runBlocking {
219+ withContext(Dispatchers .Main ) {
220+ if (header) headerEntity = null
221+ if (footer) footerEntity = null
222+ }
163223
164- return true
224+ mutableListOf<M >().apply {
225+ headerEntity?.let (::add)
226+ footerEntity?.let (::add)
227+ }
165228 }
166229
167230 /* *
@@ -170,25 +233,47 @@ abstract class AdaptiveAdapter<VT : ViewTypeFactory, M : IVisitable<VT>, VH : Re
170233 *
171234 * @param newList
172235 */
173- open fun replaceWholeList (newList : MutableList <M >) {
174- val withHeaderAndFooterList = newList.toMutableList().apply {
175- headerEntity?.let { add(0 , it) }
176- footerEntity?.let { add(newList.size, it) }
177- }
178- updateList { withHeaderAndFooterList }
236+ protected open fun _replaceWholeList (newList : MutableList <M >) = newList.toMutableList().apply {
237+ headerEntity?.let { add(0 , it) }
238+ footerEntity?.let { add(newList.size + (if (headerEntity == null ) 0 else 1 ), it) }
239+ }
240+ // endregion
241+
242+ // region Real doing update task
243+ private fun runUpdateTask () {
244+ if (queue.size > 1 ) return
245+ update(queue.peek())
179246 }
180247
181- open fun updateList (getNewListBlock : () -> MutableList <M >) {
182- val newList = getNewListBlock()
183- val res = DiffUtil .calculateDiff(diffUtil.apply {
184- oldList = dataList
185- this .newList = newList
186- })
248+ private fun update (message : Message <M >) {
249+ GlobalScope .launch {
250+ val list = extractUpdateList(message)
251+ val res = DiffUtil .calculateDiff(diffUtil.apply {
252+ oldList = dataList
253+ newList = list
254+ })
255+
256+ withContext(Dispatchers .Main ) {
257+ dataList = list
258+ res.dispatchUpdatesTo(this @AdaptiveAdapter)
259+ queue.remove()
260+ // Check the queue is still having message.
261+ if (queue.size > 0 )
262+ update(queue.peek())
263+ }
264+ }
265+ }
187266
188- dataList = newList
189- if (useDiffUtilUpdate)
190- res.dispatchUpdatesTo(this )
191- else
192- notifyDataSetChanged()
267+ private fun extractUpdateList (message : Message <M >) = when (message.type) {
268+ MESSAGE_APPEND_LIST -> _append (message.newList)
269+ MESSAGE_APPEND_SINGLE -> _append (requireNotNull(message.newItem))
270+ MESSAGE_ADD_LIST -> _add (message.position, message.newList)
271+ MESSAGE_ADD_SINGLE -> _add (message.position, requireNotNull(message.newItem))
272+ MESSAGE_DROP_RANGE -> _dropRange (message.range)
273+ MESSAGE_DROP_SINGLE -> _dropAt (message.position)
274+ MESSAGE_DROP_ALL -> _clearList (message.header, message.footer)
275+ MESSAGE_REPLACE_ALL -> _replaceWholeList (message.newList)
276+ else -> mutableListOf ()
193277 }
278+ // endregion
194279}
0 commit comments