Ensure DragAndDropDiffer works sequentially

pull/1064/head
Alex Baker 4 years ago
parent a2202dce41
commit 754b6c7e8c

@ -201,15 +201,13 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
(recyclerView.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false (recyclerView.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
recyclerView.layoutManager = LinearLayoutManager(context) recyclerView.layoutManager = LinearLayoutManager(context)
listViewModel.observe(this) { listViewModel.observe(this) {
lifecycleScope.launch { submitList(it)
submitList(it) if (it.isEmpty()) {
if (it.isEmpty()) { swipeRefreshLayout.visibility = View.GONE
swipeRefreshLayout.visibility = View.GONE emptyRefreshLayout.visibility = View.VISIBLE
emptyRefreshLayout.visibility = View.VISIBLE } else {
} else { swipeRefreshLayout.visibility = View.VISIBLE
swipeRefreshLayout.visibility = View.VISIBLE emptyRefreshLayout.visibility = View.GONE
emptyRefreshLayout.visibility = View.GONE
}
} }
} }
setupRefresh(swipeRefreshLayout) setupRefresh(swipeRefreshLayout)
@ -222,8 +220,8 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
return parent return parent
} }
private suspend fun submitList(tasks: List<TaskContainer>) { private fun submitList(tasks: List<TaskContainer>) {
if (tasks is PagedList<*>) { if (tasks is PagedList<TaskContainer>) {
if (recyclerAdapter !is PagedListRecyclerAdapter) { if (recyclerAdapter !is PagedListRecyclerAdapter) {
setAdapter( setAdapter(
PagedListRecyclerAdapter( PagedListRecyclerAdapter(
@ -233,7 +231,7 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
} else if (recyclerAdapter !is DragAndDropRecyclerAdapter) { } else if (recyclerAdapter !is DragAndDropRecyclerAdapter) {
setAdapter( setAdapter(
DragAndDropRecyclerAdapter( DragAndDropRecyclerAdapter(
lifecycleScope, taskAdapter, recyclerView, viewHolderFactory, this, tasks, preferences)) taskAdapter, recyclerView, viewHolderFactory, this, tasks, preferences))
return return
} }
recyclerAdapter?.submitList(tasks) recyclerAdapter?.submitList(tasks)

@ -16,6 +16,9 @@ import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.api.FilterListItem import com.todoroo.astrid.api.FilterListItem
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.subjects.PublishSubject import io.reactivex.subjects.PublishSubject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.asCoroutineDispatcher
import org.tasks.LocalBroadcastManager import org.tasks.LocalBroadcastManager
import org.tasks.activities.DragAndDropDiffer import org.tasks.activities.DragAndDropDiffer
import org.tasks.billing.Inventory import org.tasks.billing.Inventory
@ -26,6 +29,7 @@ import org.tasks.locale.Locale
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.themes.ColorProvider import org.tasks.themes.ColorProvider
import java.util.* import java.util.*
import java.util.concurrent.Executors
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.max import kotlin.math.max
@ -47,6 +51,8 @@ class NavigationDrawerAdapter @Inject constructor(
override val updates: Queue<Pair<MutableList<FilterListItem>, DiffUtil.DiffResult?>> = LinkedList() override val updates: Queue<Pair<MutableList<FilterListItem>, DiffUtil.DiffResult?>> = LinkedList()
override var items = initializeDiffer(ArrayList()) override var items = initializeDiffer(ArrayList())
override var dragging = false override var dragging = false
override val scope: CoroutineScope =
CoroutineScope(Executors.newSingleThreadExecutor().asCoroutineDispatcher() + Job())
fun setOnClick(onClick: (FilterListItem?) -> Unit) { fun setOnClick(onClick: (FilterListItem?) -> Unit) {
this.onClick = onClick this.onClick = onClick
@ -60,6 +66,10 @@ class NavigationDrawerAdapter @Inject constructor(
selected = savedInstanceState.getParcelable(TOKEN_SELECTED) selected = savedInstanceState.getParcelable(TOKEN_SELECTED)
} }
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
super.dispose()
}
override fun getItemId(position: Int) = position.toLong() override fun getItemId(position: Int) = position.toLong()
override fun getItemCount() = items.size override fun getItemCount() = items.size

@ -7,8 +7,9 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import io.reactivex.subjects.PublishSubject import io.reactivex.subjects.PublishSubject
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.withContext import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import java.util.* import java.util.*
interface DragAndDropDiffer<T, R> : ListUpdateCallback { interface DragAndDropDiffer<T, R> : ListUpdateCallback {
@ -17,12 +18,13 @@ interface DragAndDropDiffer<T, R> : ListUpdateCallback {
val disposables: CompositeDisposable val disposables: CompositeDisposable
var items: R var items: R
var dragging: Boolean var dragging: Boolean
val scope: CoroutineScope
suspend fun submitList(list: List<T>) { fun submitList(list: List<T>) {
val transform = withContext(Dispatchers.Default) { scope.launch {
transform(list) val transform = transform(list)
publishSubject.onNext(transform)
} }
publishSubject.onNext(transform)
} }
fun calculateDiff(last: Pair<R, DiffUtil.DiffResult?>, next: R): Pair<R, DiffUtil.DiffResult?> { fun calculateDiff(last: Pair<R, DiffUtil.DiffResult?>, next: R): Pair<R, DiffUtil.DiffResult?> {
@ -51,7 +53,7 @@ interface DragAndDropDiffer<T, R> : ListUpdateCallback {
fun initializeDiffer(list: List<T>): R { fun initializeDiffer(list: List<T>): R {
val initial = transform(list) val initial = transform(list)
disposables.add(publishSubject disposables.add(publishSubject
.observeOn(Schedulers.computation()) .observeOn(Schedulers.single())
.scan(Pair(initial, null), { last: Pair<R, DiffUtil.DiffResult?>, next: R -> .scan(Pair(initial, null), { last: Pair<R, DiffUtil.DiffResult?>, next: R ->
calculateDiff(last, next) calculateDiff(last, next)
}) })
@ -64,4 +66,9 @@ interface DragAndDropDiffer<T, R> : ListUpdateCallback {
fun transform(list: List<T>): R fun transform(list: List<T>): R
fun diff(last: R, next: R): DiffUtil.DiffResult fun diff(last: R, next: R): DiffUtil.DiffResult
fun dispose() {
disposables.dispose()
scope.cancel()
}
} }

@ -2,7 +2,6 @@ package org.tasks.tasklist
import android.graphics.Canvas import android.graphics.Canvas
import android.view.ViewGroup import android.view.ViewGroup
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.ItemTouchHelper.* import androidx.recyclerview.widget.ItemTouchHelper.*
@ -13,16 +12,19 @@ import com.todoroo.astrid.adapter.TaskAdapter
import com.todoroo.astrid.utility.Flags import com.todoroo.astrid.utility.Flags
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.subjects.PublishSubject import io.reactivex.subjects.PublishSubject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.tasks.activities.DragAndDropDiffer import org.tasks.activities.DragAndDropDiffer
import org.tasks.data.TaskContainer import org.tasks.data.TaskContainer
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import java.util.* import java.util.*
import java.util.concurrent.Executors
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
class DragAndDropRecyclerAdapter( class DragAndDropRecyclerAdapter(
private val scope: LifecycleCoroutineScope,
private val adapter: TaskAdapter, private val adapter: TaskAdapter,
private val recyclerView: RecyclerView, private val recyclerView: RecyclerView,
viewHolderFactory: ViewHolderFactory, viewHolderFactory: ViewHolderFactory,
@ -43,6 +45,8 @@ class DragAndDropRecyclerAdapter(
override val updates: Queue<Pair<SectionedDataSource, DiffUtil.DiffResult?>> = LinkedList() override val updates: Queue<Pair<SectionedDataSource, DiffUtil.DiffResult?>> = LinkedList()
override var dragging = false override var dragging = false
override var items = initializeDiffer(tasks) override var items = initializeDiffer(tasks)
override val scope: CoroutineScope =
CoroutineScope(Executors.newSingleThreadExecutor().asCoroutineDispatcher() + Job())
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val viewType = getItemViewType(position) val viewType = getItemViewType(position)
@ -59,7 +63,7 @@ class DragAndDropRecyclerAdapter(
override fun getItemViewType(position: Int) = if (items.isHeader(position)) 1 else 0 override fun getItemViewType(position: Int) = if (items.isHeader(position)) 1 else 0
override suspend fun submitList(list: List<TaskContainer>) { override fun submitList(list: List<TaskContainer>) {
super.submitList(list) super.submitList(list)
} }
@ -95,8 +99,8 @@ class DragAndDropRecyclerAdapter(
} }
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
super.dispose()
itemTouchHelper.attachToRecyclerView(null) itemTouchHelper.attachToRecyclerView(null)
disposables.dispose()
} }
override fun getTaskCount() = items.taskCount override fun getTaskCount() = items.taskCount

@ -14,15 +14,17 @@ class PagedListRecyclerAdapter(
private val recyclerView: RecyclerView, private val recyclerView: RecyclerView,
viewHolderFactory: ViewHolderFactory, viewHolderFactory: ViewHolderFactory,
taskList: TaskListFragment, taskList: TaskListFragment,
list: List<TaskContainer>, list: PagedList<TaskContainer>,
preferences: Preferences) : TaskListRecyclerAdapter(adapter, viewHolderFactory, taskList, preferences) { preferences: Preferences
) : TaskListRecyclerAdapter(adapter, viewHolderFactory, taskList, preferences) {
private val differ: AsyncPagedListDiffer<TaskContainer> = private val differ: AsyncPagedListDiffer<TaskContainer> =
AsyncPagedListDiffer(this, AsyncDifferConfig.Builder(ItemCallback()).build()) AsyncPagedListDiffer(this, AsyncDifferConfig.Builder(ItemCallback()).build())
override fun getItem(position: Int) = differ.getItem(position) override fun getItem(position: Int) = differ.getItem(position)
override suspend fun submitList(list: List<TaskContainer>) = differ.submitList(list as PagedList<TaskContainer>) override fun submitList(list: List<TaskContainer>) =
differ.submitList(list as PagedList<TaskContainer>)
override fun onMoved(fromPosition: Int, toPosition: Int) { override fun onMoved(fromPosition: Int, toPosition: Int) {
val recyclerViewState = recyclerView.layoutManager!!.onSaveInstanceState() val recyclerViewState = recyclerView.layoutManager!!.onSaveInstanceState()
@ -37,8 +39,6 @@ class PagedListRecyclerAdapter(
override fun getTaskCount() = itemCount override fun getTaskCount() = itemCount
init { init {
if (list is PagedList<*>) { differ.submitList(list as PagedList<TaskContainer>?)
differ.submitList(list as PagedList<TaskContainer>?)
}
} }
} }

@ -44,7 +44,7 @@ abstract class TaskListRecyclerAdapter internal constructor(
abstract fun dragAndDropEnabled(): Boolean abstract fun dragAndDropEnabled(): Boolean
abstract suspend fun submitList(list: List<TaskContainer>) abstract fun submitList(list: List<TaskContainer>)
override fun onInserted(position: Int, count: Int) { override fun onInserted(position: Int, count: Int) {
notifyItemRangeInserted(position, count) notifyItemRangeInserted(position, count)

Loading…
Cancel
Save