【发布时间】:2020-06-01 22:24:27
【问题描述】:
我在 RecyclerView 中有一个简单的 Pokemon 列表,其中只有 Pokemon 的名称和“Favorite”切换按钮。我正在使用带有 PageKeyedDataSource 的 Android JetPack 的分页库来检索小块 Pokemon 并将它们显示给用户。只要 Activity 没有被破坏,我只希望数据保持不变(即,我不想将数据保持到 Room 或数据库,而是只要 ViewModel 还活着就让它保持不变)。
我希望能够单击任何 Pokemon 项目上的心形按钮并将 SimplePokemon 模型中的“isFavorite”字段更新为 true 或 false。据我了解,如果我想更改该 PagedList 中的单个项目,我需要使 DataSource 无效,并且理论上应该生成一个 PagedList 的新 LiveData,可以将其提供给 Adapter 并显示在屏幕上。
问题:如何在不需要 Room 或其他数据库的情况下使用分页库更新 PagedList 中的单个项目?
将来,我想将此解决方案扩展到社交媒体供稿,用户可以在其中点赞帖子,但我不知道将社交供稿项存储在诸如 Room 之类的数据库中是否必要(或有效),因为这些供稿物品是不断变化的。所以我选择将它们存储在 ViewModel 中,然后在每次用户退出应用时清除它们。
到目前为止,这是我的代码:
SimplePokemon.kt:
data class SimplePokemon(
@SerializedName("name") val name: String,
@SerializedName("url") val url: String,
var isFavorite: Boolean = false
)
PokemonViewModel.kt:
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()
}
}
PokemonAdapter.kt:
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) }
}
}
PokemonDataSource.kt:
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)
}
})
}
我还想确保每次更新 DataSource 时 RecyclerView 都不会跳到顶部。
理想的情况是,只要 Activity 处于活动状态,就保留一个 Pokemon 列表,并且能够在本地更新单个 Pokemon 项目。理论上,我还会向后端发送一个 POST 请求以更新后端的口袋妖怪,但我只是想让问题保持简单。
任何帮助将不胜感激。
【问题讨论】:
-
你找到解决办法了吗?
标签: android paging pagedlist android-paging android-paging-library