Merge pull request #530 from tzugen/diff

Use DiffUtil for better performance when refreshing the data..
This commit is contained in:
tzugen 2021-06-21 18:49:17 +02:00 committed by GitHub
commit d6594b8ec4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 51 additions and 10 deletions

View File

@ -1,7 +1,19 @@
package org.moire.ultrasonic.domain
abstract class GenericEntry {
// TODO Should be non-null!
// TODO: Should be non-null!
abstract val id: String?
open val name: String? = null
// These are just a formality and will never be called,
// because Kotlin data classes will have autogenerated equals() and hashCode() functions
override operator fun equals(other: Any?): Boolean {
return this === other
}
override fun hashCode(): Int {
var result = id?.hashCode() ?: 0
result = 31 * result + (name?.hashCode() ?: 0)
return result
}
}

View File

@ -49,8 +49,9 @@ class AlbumListFragment : GenericListFragment<MusicDirectory.Entry, AlbumRowAdap
if (args == null) throw IllegalArgumentException("Required arguments are missing")
val refresh = args.getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH)
val append = args.getBoolean(Constants.INTENT_EXTRA_NAME_APPEND)
return listModel.getAlbumList(refresh, refreshListView!!, args)
return listModel.getAlbumList(refresh or append, refreshListView!!, args)
}
/**

View File

@ -13,7 +13,8 @@ import org.moire.ultrasonic.util.Util
class AlbumListModel(application: Application) : GenericListModel(application) {
val albumList: MutableLiveData<List<MusicDirectory.Entry>> = MutableLiveData()
val albumList: MutableLiveData<List<MusicDirectory.Entry>> = MutableLiveData(listOf())
var lastType: String? = null
private var loadedUntil: Int = 0
fun getAlbumList(
@ -21,8 +22,14 @@ class AlbumListModel(application: Application) : GenericListModel(application) {
swipe: SwipeRefreshLayout,
args: Bundle
): LiveData<List<MusicDirectory.Entry>> {
// Don't reload the data if navigating back to the view that was active before.
// This way, we keep the scroll position
val albumListType = args.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE)!!
backgroundLoadFromServer(refresh, swipe, args)
if (refresh || albumList.value!!.isEmpty() || albumListType != lastType) {
lastType = albumListType
backgroundLoadFromServer(refresh, swipe, args)
}
return albumList
}

View File

@ -30,13 +30,17 @@ import org.moire.ultrasonic.service.MusicService
* Provides ViewModel which contains the list of available Artists
*/
class ArtistListModel(application: Application) : GenericListModel(application) {
private val artists: MutableLiveData<List<Artist>> = MutableLiveData()
private val artists: MutableLiveData<List<Artist>> = MutableLiveData(listOf())
/**
* Retrieves all available Artists in a LiveData
*/
fun getItems(refresh: Boolean, swipe: SwipeRefreshLayout): LiveData<List<Artist>> {
backgroundLoadFromServer(refresh, swipe)
// Don't reload the data if navigating back to the view that was active before.
// This way, we keep the scroll position
if (artists.value!!.isEmpty() || refresh) {
backgroundLoadFromServer(refresh, swipe)
}
return artists
}

View File

@ -16,20 +16,24 @@ import android.widget.ImageView
import android.widget.PopupMenu
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import org.moire.ultrasonic.R
import org.moire.ultrasonic.data.ActiveServerProvider
import org.moire.ultrasonic.domain.GenericEntry
import org.moire.ultrasonic.domain.MusicFolder
import org.moire.ultrasonic.view.SelectMusicFolderView
/*
* An abstract Adapter, which can be extended to display a List of <T> in a RecyclerView
*/
abstract class GenericRowAdapter<T>(
abstract class GenericRowAdapter<T : GenericEntry>(
val onItemClick: (T) -> Unit,
val onContextMenuClick: (MenuItem, T) -> Boolean,
private val onMusicFolderUpdate: (String?) -> Unit
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
) : ListAdapter<T, RecyclerView.ViewHolder>(GenericDiffCallback()) {
open var itemList: List<T> = listOf()
protected abstract val layout: Int
protected abstract val contextMenuLayout: Int
@ -40,11 +44,12 @@ abstract class GenericRowAdapter<T>(
var selectedFolder: String? = null
/**
* Sets the data to be displayed in the RecyclerView
* Sets the data to be displayed in the RecyclerView,
* using DiffUtil to efficiently calculate the minimum required changes..
*/
open fun setData(data: List<T>) {
submitList(data)
itemList = data
notifyDataSetChanged()
}
/**
@ -136,5 +141,17 @@ abstract class GenericRowAdapter<T>(
companion object {
internal const val TYPE_HEADER = 0
internal const val TYPE_ITEM = 1
/**
* Calculates the differences between data sets
*/
class GenericDiffCallback<T : GenericEntry> : DiffUtil.ItemCallback<T>() {
override fun areContentsTheSame(oldItem: T, newItem: T): Boolean {
return oldItem == newItem
}
override fun areItemsTheSame(oldItem: T, newItem: T): Boolean {
return oldItem.id == newItem.id
}
}
}
}