Android 使用Google';s分页库

Android 使用Google';s分页库,android,paging,pagedlist,android-paging,android-paging-library,Android,Paging,Pagedlist,Android Paging,Android Paging Library,我在一个回收视图中有一个简单的口袋妖怪列表,只有口袋妖怪的名字和一个“最喜欢的”按钮。我正在使用Android JetPack的分页库和PageKeyedDataSource来检索Pokemon的小块并将它们显示给用户。我只希望在活动未被销毁的情况下数据保持不变(即,我不希望将数据保持到文件室或数据库中,而是希望在ViewModel处于活动状态时数据保持不变) 我希望能够单击任何口袋妖怪项目上的心脏按钮,并将SimpleKeyon模型中的“isFavorite”字段更新为true或false。

我在一个回收视图中有一个简单的口袋妖怪列表,只有口袋妖怪的名字和一个“最喜欢的”按钮。我正在使用Android JetPack的分页库和PageKeyedDataSource来检索Pokemon的小块并将它们显示给用户。我只希望在活动未被销毁的情况下数据保持不变(即,我不希望将数据保持到文件室或数据库中,而是希望在ViewModel处于活动状态时数据保持不变)

我希望能够单击任何口袋妖怪项目上的心脏按钮,并将SimpleKeyon模型中的“isFavorite”字段更新为
true
false
。根据我的理解,如果我想更改该页面列表中的单个项目,我需要使数据源无效,从理论上讲,这应该生成页面列表的新LiveData,该数据可以馈送到适配器并显示在屏幕上

问题:如何使用页面库更新页面列表中的单个项目,而不需要空间或其他数据库?

将来,我想将这个解决方案扩展到一个用户可以喜欢帖子的社交媒体提要,但我不知道在数据库(如Room)中存储社交提要项目是否必要(或有效),因为这些提要项目在不断变化。因此,我选择将它们存储在ViewModel中,然后在用户每次退出应用程序时清除它们

以下是我目前的代码:

SimplePokemon.kt:

data class SimplePokemon(
    @SerializedName("name") val name: String,
    @SerializedName("url") val url: String,
    var isFavorite: Boolean = false
)
class PokemonViewModel(application: Application) : AndroidViewModel(application) {

    private val config = PagedList.Config.Builder()
        .setPageSize(20)
        .setEnablePlaceholders(false)
        .build()

    private fun initializedPagedListBuilder(config: PagedList.Config): LivePagedListBuilder<String, SimplePokemon> {
        val dataSourceFactory = object : DataSource.Factory<String, SimplePokemon>() {
            override fun create(): DataSource<String, SimplePokemon> {
                return PokemonDataSource()
            }
        }
        return LivePagedListBuilder<String, SimplePokemon>(dataSourceFactory, config)
    }

    fun pokemonPagedListLiveData(): LiveData<PagedList<SimplePokemon>> {
        return initializedPagedListBuilder(config).build()
    }
}
class PokemonAdapter :
    PagedListAdapter<SimplePokemon, PokemonAdapter.PokemonViewHolder>(PokemonDiffUtil()) {

    inner class PokemonViewHolder(v: View) : RecyclerView.ViewHolder(v) {
        private val pokemonNameTextView: TextView = v.findViewById(R.id.pokemon_name_text_view)
        private val pokemonFavoriteToggle: ToggleButton =
            v.findViewById(R.id.pokemon_favorite_toggle_button)

        fun bind(data: SimplePokemon) {
            pokemonNameTextView.text = data.name
            pokemonFavoriteToggle.isChecked = data.isFavorite
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PokemonViewHolder {
        val view =
            LayoutInflater.from(parent.context).inflate(R.layout.item_simple_pokemon, parent, false)
        return PokemonViewHolder(view)
    }

    override fun onBindViewHolder(holder: PokemonViewHolder, position: Int) {
        val item = getItem(position)
        item?.let { holder.bind(it) }
    }
}
class PokemonDataSource : PageKeyedDataSource<String, SimplePokemon>() {

    private val api = NetworkService.pokemonNetworkInterface

    override fun loadInitial(
        params: LoadInitialParams<String>,
        callback: LoadInitialCallback<String, SimplePokemon>
    ) {
        api.getPokemon().enqueue(object : Callback<PokeResponse<List<SimplePokemon>>> {

            override fun onFailure(call: Call<PokeResponse<List<SimplePokemon>>>?, t: Throwable?) {
                Log.e("PokemonDataSource", "Failed to fetch data!")
            }

            override fun onResponse(
                call: Call<PokeResponse<List<SimplePokemon>>>?,
                response: Response<PokeResponse<List<SimplePokemon>>>
            ) {
                val listing = response.body()
                val pokemon = listing?.results
                callback.onResult(pokemon ?: listOf(), listing?.previous, listing?.next)
            }
        })
    }

    override fun loadAfter(
        params: LoadParams<String>,
        callback: LoadCallback<String, SimplePokemon>
    ) {
        api.getPokemon(url = params.key)
            .enqueue(object : Callback<PokeResponse<List<SimplePokemon>>> {
                override fun onFailure(
                    call: Call<PokeResponse<List<SimplePokemon>>>?,
                    t: Throwable?
                ) {
                    Log.e("PokemonDataSource", "Failed to fetch data! Oh Noooo!")
                }

                override fun onResponse(
                    call: Call<PokeResponse<List<SimplePokemon>>>?,
                    response: Response<PokeResponse<List<SimplePokemon>>>
                ) {
                    val listing = response.body()
                    val pokemon = listing?.results
                    callback.onResult(pokemon ?: listOf(), listing?.next)
                }
            })
    }

    override fun loadBefore(
        params: LoadParams<String>,
        callback: LoadCallback<String, SimplePokemon>
    ) {
        api.getPokemon(url = params.key)
            .enqueue(object : Callback<PokeResponse<List<SimplePokemon>>> {
                override fun onFailure(
                    call: Call<PokeResponse<List<SimplePokemon>>>?,
                    t: Throwable?
                ) {
                    Log.e("PokemonDataSource", "Failed to fetch data! Oh Noooo!")
                }

                override fun onResponse(
                    call: Call<PokeResponse<List<SimplePokemon>>>?,
                    response: Response<PokeResponse<List<SimplePokemon>>>
                ) {
                    val listing = response.body()
                    val pokemon = listing?.results
                    callback.onResult(pokemon ?: listOf(), listing?.previous)
                }
            })
    }

PokemonViewModel.kt:

data class SimplePokemon(
    @SerializedName("name") val name: String,
    @SerializedName("url") val url: String,
    var isFavorite: Boolean = false
)
class PokemonViewModel(application: Application) : AndroidViewModel(application) {

    private val config = PagedList.Config.Builder()
        .setPageSize(20)
        .setEnablePlaceholders(false)
        .build()

    private fun initializedPagedListBuilder(config: PagedList.Config): LivePagedListBuilder<String, SimplePokemon> {
        val dataSourceFactory = object : DataSource.Factory<String, SimplePokemon>() {
            override fun create(): DataSource<String, SimplePokemon> {
                return PokemonDataSource()
            }
        }
        return LivePagedListBuilder<String, SimplePokemon>(dataSourceFactory, config)
    }

    fun pokemonPagedListLiveData(): LiveData<PagedList<SimplePokemon>> {
        return initializedPagedListBuilder(config).build()
    }
}
class PokemonAdapter :
    PagedListAdapter<SimplePokemon, PokemonAdapter.PokemonViewHolder>(PokemonDiffUtil()) {

    inner class PokemonViewHolder(v: View) : RecyclerView.ViewHolder(v) {
        private val pokemonNameTextView: TextView = v.findViewById(R.id.pokemon_name_text_view)
        private val pokemonFavoriteToggle: ToggleButton =
            v.findViewById(R.id.pokemon_favorite_toggle_button)

        fun bind(data: SimplePokemon) {
            pokemonNameTextView.text = data.name
            pokemonFavoriteToggle.isChecked = data.isFavorite
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PokemonViewHolder {
        val view =
            LayoutInflater.from(parent.context).inflate(R.layout.item_simple_pokemon, parent, false)
        return PokemonViewHolder(view)
    }

    override fun onBindViewHolder(holder: PokemonViewHolder, position: Int) {
        val item = getItem(position)
        item?.let { holder.bind(it) }
    }
}
class PokemonDataSource : PageKeyedDataSource<String, SimplePokemon>() {

    private val api = NetworkService.pokemonNetworkInterface

    override fun loadInitial(
        params: LoadInitialParams<String>,
        callback: LoadInitialCallback<String, SimplePokemon>
    ) {
        api.getPokemon().enqueue(object : Callback<PokeResponse<List<SimplePokemon>>> {

            override fun onFailure(call: Call<PokeResponse<List<SimplePokemon>>>?, t: Throwable?) {
                Log.e("PokemonDataSource", "Failed to fetch data!")
            }

            override fun onResponse(
                call: Call<PokeResponse<List<SimplePokemon>>>?,
                response: Response<PokeResponse<List<SimplePokemon>>>
            ) {
                val listing = response.body()
                val pokemon = listing?.results
                callback.onResult(pokemon ?: listOf(), listing?.previous, listing?.next)
            }
        })
    }

    override fun loadAfter(
        params: LoadParams<String>,
        callback: LoadCallback<String, SimplePokemon>
    ) {
        api.getPokemon(url = params.key)
            .enqueue(object : Callback<PokeResponse<List<SimplePokemon>>> {
                override fun onFailure(
                    call: Call<PokeResponse<List<SimplePokemon>>>?,
                    t: Throwable?
                ) {
                    Log.e("PokemonDataSource", "Failed to fetch data! Oh Noooo!")
                }

                override fun onResponse(
                    call: Call<PokeResponse<List<SimplePokemon>>>?,
                    response: Response<PokeResponse<List<SimplePokemon>>>
                ) {
                    val listing = response.body()
                    val pokemon = listing?.results
                    callback.onResult(pokemon ?: listOf(), listing?.next)
                }
            })
    }

    override fun loadBefore(
        params: LoadParams<String>,
        callback: LoadCallback<String, SimplePokemon>
    ) {
        api.getPokemon(url = params.key)
            .enqueue(object : Callback<PokeResponse<List<SimplePokemon>>> {
                override fun onFailure(
                    call: Call<PokeResponse<List<SimplePokemon>>>?,
                    t: Throwable?
                ) {
                    Log.e("PokemonDataSource", "Failed to fetch data! Oh Noooo!")
                }

                override fun onResponse(
                    call: Call<PokeResponse<List<SimplePokemon>>>?,
                    response: Response<PokeResponse<List<SimplePokemon>>>
                ) {
                    val listing = response.body()
                    val pokemon = listing?.results
                    callback.onResult(pokemon ?: listOf(), listing?.previous)
                }
            })
    }

class PokemonViewModel(应用程序:应用程序):AndroidViewModel(应用程序){
private val config=PagedList.config.Builder()
.setPageSize(20)
.setEnablePlaceholders(false)
.build()
private fun initializedPagedListBuilder(config:PagedList.config):LivePagedListBuilder{
val dataSourceFactory=object:DataSource.Factory(){
重写fun create():数据源{
return pokemondasource()
}
}
返回LivePagedListBuilder(dataSourceFactory,配置)
}
fun pokemonPagedListLiveData():LiveData{
返回initializedPagedListBuilder(config).build()
}
}
PokemonAdapter.kt:

data class SimplePokemon(
    @SerializedName("name") val name: String,
    @SerializedName("url") val url: String,
    var isFavorite: Boolean = false
)
class PokemonViewModel(application: Application) : AndroidViewModel(application) {

    private val config = PagedList.Config.Builder()
        .setPageSize(20)
        .setEnablePlaceholders(false)
        .build()

    private fun initializedPagedListBuilder(config: PagedList.Config): LivePagedListBuilder<String, SimplePokemon> {
        val dataSourceFactory = object : DataSource.Factory<String, SimplePokemon>() {
            override fun create(): DataSource<String, SimplePokemon> {
                return PokemonDataSource()
            }
        }
        return LivePagedListBuilder<String, SimplePokemon>(dataSourceFactory, config)
    }

    fun pokemonPagedListLiveData(): LiveData<PagedList<SimplePokemon>> {
        return initializedPagedListBuilder(config).build()
    }
}
class PokemonAdapter :
    PagedListAdapter<SimplePokemon, PokemonAdapter.PokemonViewHolder>(PokemonDiffUtil()) {

    inner class PokemonViewHolder(v: View) : RecyclerView.ViewHolder(v) {
        private val pokemonNameTextView: TextView = v.findViewById(R.id.pokemon_name_text_view)
        private val pokemonFavoriteToggle: ToggleButton =
            v.findViewById(R.id.pokemon_favorite_toggle_button)

        fun bind(data: SimplePokemon) {
            pokemonNameTextView.text = data.name
            pokemonFavoriteToggle.isChecked = data.isFavorite
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PokemonViewHolder {
        val view =
            LayoutInflater.from(parent.context).inflate(R.layout.item_simple_pokemon, parent, false)
        return PokemonViewHolder(view)
    }

    override fun onBindViewHolder(holder: PokemonViewHolder, position: Int) {
        val item = getItem(position)
        item?.let { holder.bind(it) }
    }
}
class PokemonDataSource : PageKeyedDataSource<String, SimplePokemon>() {

    private val api = NetworkService.pokemonNetworkInterface

    override fun loadInitial(
        params: LoadInitialParams<String>,
        callback: LoadInitialCallback<String, SimplePokemon>
    ) {
        api.getPokemon().enqueue(object : Callback<PokeResponse<List<SimplePokemon>>> {

            override fun onFailure(call: Call<PokeResponse<List<SimplePokemon>>>?, t: Throwable?) {
                Log.e("PokemonDataSource", "Failed to fetch data!")
            }

            override fun onResponse(
                call: Call<PokeResponse<List<SimplePokemon>>>?,
                response: Response<PokeResponse<List<SimplePokemon>>>
            ) {
                val listing = response.body()
                val pokemon = listing?.results
                callback.onResult(pokemon ?: listOf(), listing?.previous, listing?.next)
            }
        })
    }

    override fun loadAfter(
        params: LoadParams<String>,
        callback: LoadCallback<String, SimplePokemon>
    ) {
        api.getPokemon(url = params.key)
            .enqueue(object : Callback<PokeResponse<List<SimplePokemon>>> {
                override fun onFailure(
                    call: Call<PokeResponse<List<SimplePokemon>>>?,
                    t: Throwable?
                ) {
                    Log.e("PokemonDataSource", "Failed to fetch data! Oh Noooo!")
                }

                override fun onResponse(
                    call: Call<PokeResponse<List<SimplePokemon>>>?,
                    response: Response<PokeResponse<List<SimplePokemon>>>
                ) {
                    val listing = response.body()
                    val pokemon = listing?.results
                    callback.onResult(pokemon ?: listOf(), listing?.next)
                }
            })
    }

    override fun loadBefore(
        params: LoadParams<String>,
        callback: LoadCallback<String, SimplePokemon>
    ) {
        api.getPokemon(url = params.key)
            .enqueue(object : Callback<PokeResponse<List<SimplePokemon>>> {
                override fun onFailure(
                    call: Call<PokeResponse<List<SimplePokemon>>>?,
                    t: Throwable?
                ) {
                    Log.e("PokemonDataSource", "Failed to fetch data! Oh Noooo!")
                }

                override fun onResponse(
                    call: Call<PokeResponse<List<SimplePokemon>>>?,
                    response: Response<PokeResponse<List<SimplePokemon>>>
                ) {
                    val listing = response.body()
                    val pokemon = listing?.results
                    callback.onResult(pokemon ?: listOf(), listing?.previous)
                }
            })
    }

class口袋妖怪:
PagedListAdapter(PokemonDiffUtil()){
内部类PokemonViewHolder(v:View):RecyclerView.ViewHolder(v){
private val pokemonNameTextView:TextView=v.findViewById(R.id.pokemon\u name\u text\u视图)
private val PokemonFavoriteTokle:ToggleButton=
v、 findViewById(R.id.pokemon\u favorite\u toggle\u按钮)
趣味绑定(数据:SimplePokemon){
pokemonNameTextView.text=data.name
PokemonFavoriteTokle.isChecked=data.isFavorite
}
}
override fun onCreateViewHolder(父级:ViewGroup,viewType:Int):PokemonViewHolder{
瓦尔视图=
LayoutFlater.from(parent.context).充气(R.layout.item\u simple\u pokemon,parent,false)
返回PokemonViewHolder(视图)
}
覆盖BindViewHolder(支架:PokemonViewHolder,位置:Int){
val item=getItem(位置)
项目?让{holder.bind(it)}
}
}
pokemondasource.kt:

data class SimplePokemon(
    @SerializedName("name") val name: String,
    @SerializedName("url") val url: String,
    var isFavorite: Boolean = false
)
class PokemonViewModel(application: Application) : AndroidViewModel(application) {

    private val config = PagedList.Config.Builder()
        .setPageSize(20)
        .setEnablePlaceholders(false)
        .build()

    private fun initializedPagedListBuilder(config: PagedList.Config): LivePagedListBuilder<String, SimplePokemon> {
        val dataSourceFactory = object : DataSource.Factory<String, SimplePokemon>() {
            override fun create(): DataSource<String, SimplePokemon> {
                return PokemonDataSource()
            }
        }
        return LivePagedListBuilder<String, SimplePokemon>(dataSourceFactory, config)
    }

    fun pokemonPagedListLiveData(): LiveData<PagedList<SimplePokemon>> {
        return initializedPagedListBuilder(config).build()
    }
}
class PokemonAdapter :
    PagedListAdapter<SimplePokemon, PokemonAdapter.PokemonViewHolder>(PokemonDiffUtil()) {

    inner class PokemonViewHolder(v: View) : RecyclerView.ViewHolder(v) {
        private val pokemonNameTextView: TextView = v.findViewById(R.id.pokemon_name_text_view)
        private val pokemonFavoriteToggle: ToggleButton =
            v.findViewById(R.id.pokemon_favorite_toggle_button)

        fun bind(data: SimplePokemon) {
            pokemonNameTextView.text = data.name
            pokemonFavoriteToggle.isChecked = data.isFavorite
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PokemonViewHolder {
        val view =
            LayoutInflater.from(parent.context).inflate(R.layout.item_simple_pokemon, parent, false)
        return PokemonViewHolder(view)
    }

    override fun onBindViewHolder(holder: PokemonViewHolder, position: Int) {
        val item = getItem(position)
        item?.let { holder.bind(it) }
    }
}
class PokemonDataSource : PageKeyedDataSource<String, SimplePokemon>() {

    private val api = NetworkService.pokemonNetworkInterface

    override fun loadInitial(
        params: LoadInitialParams<String>,
        callback: LoadInitialCallback<String, SimplePokemon>
    ) {
        api.getPokemon().enqueue(object : Callback<PokeResponse<List<SimplePokemon>>> {

            override fun onFailure(call: Call<PokeResponse<List<SimplePokemon>>>?, t: Throwable?) {
                Log.e("PokemonDataSource", "Failed to fetch data!")
            }

            override fun onResponse(
                call: Call<PokeResponse<List<SimplePokemon>>>?,
                response: Response<PokeResponse<List<SimplePokemon>>>
            ) {
                val listing = response.body()
                val pokemon = listing?.results
                callback.onResult(pokemon ?: listOf(), listing?.previous, listing?.next)
            }
        })
    }

    override fun loadAfter(
        params: LoadParams<String>,
        callback: LoadCallback<String, SimplePokemon>
    ) {
        api.getPokemon(url = params.key)
            .enqueue(object : Callback<PokeResponse<List<SimplePokemon>>> {
                override fun onFailure(
                    call: Call<PokeResponse<List<SimplePokemon>>>?,
                    t: Throwable?
                ) {
                    Log.e("PokemonDataSource", "Failed to fetch data! Oh Noooo!")
                }

                override fun onResponse(
                    call: Call<PokeResponse<List<SimplePokemon>>>?,
                    response: Response<PokeResponse<List<SimplePokemon>>>
                ) {
                    val listing = response.body()
                    val pokemon = listing?.results
                    callback.onResult(pokemon ?: listOf(), listing?.next)
                }
            })
    }

    override fun loadBefore(
        params: LoadParams<String>,
        callback: LoadCallback<String, SimplePokemon>
    ) {
        api.getPokemon(url = params.key)
            .enqueue(object : Callback<PokeResponse<List<SimplePokemon>>> {
                override fun onFailure(
                    call: Call<PokeResponse<List<SimplePokemon>>>?,
                    t: Throwable?
                ) {
                    Log.e("PokemonDataSource", "Failed to fetch data! Oh Noooo!")
                }

                override fun onResponse(
                    call: Call<PokeResponse<List<SimplePokemon>>>?,
                    response: Response<PokeResponse<List<SimplePokemon>>>
                ) {
                    val listing = response.body()
                    val pokemon = listing?.results
                    callback.onResult(pokemon ?: listOf(), listing?.previous)
                }
            })
    }

class pokemondasource:PageKeyedDataSource(){
private val api=NetworkService.pokemonNetworkInterface
覆盖趣味加载初始值(
params:LoadInitialParams,
回调:LoadInitialCallback
) {
api.getPokemon().enqueue(对象:回调{
覆盖失效时的乐趣(调用:调用?、t:可丢弃?){
Log.e(“pokemondasource”,“无法获取数据!”)
}
覆盖响应(
呼叫:呼叫?,
答复:答复
) {
val listing=response.body()
val pokemon=listing?.results
callback.onResult(pokemon?:listOf(),listing?.previous,listing?.next)
}
})
}
覆盖乐趣加载后(
参数:LoadParams,
回调:LoadCallback
) {
api.getPokemon(url=params.key)
.enqueue(对象:回调{
覆盖故障(
呼叫:呼叫?,
t:可以扔掉吗?
) {
Log.e(“pokemondasource”,“无法获取数据!噢,不!”
}
覆盖响应(
呼叫:呼叫?,
答复:答复
) {
val listing=response.body()
val pokemon=listing?.results
callback.onResult(pokemon?:listOf(),listing?.next)
}
})
}
覆盖有趣的加载之前(
参数:LoadParams,
回调:LoadCallback
) {
api.getPokemon(url=params.key)
.enqueue(对象:回调{
覆盖故障(
呼叫:呼叫?,
t:可以扔掉吗?
) {
Log.e(“pokemondasource”,“无法获取数据!噢,不!”
}
覆盖响应(
呼叫:呼叫?,
答复:答复
) {
val listing=response.body()
val pokemon=listing?.results
callback.onResult(口袋妖怪?:listOf(),listing?.previous)
}
})
}
我还想确保RecyclerView不会在每次更新数据源时跳转到顶部

理想的情况是,只要口袋妖怪活动还活着,就保留一个口袋妖怪列表,并能够在本地更新单个口袋妖怪项目。理论上,我也会向后端发送POST请求,以更新后端的口袋妖怪,但我只是想保留问题的答案