使用 Google 的分页库更新 PagedList 中的单个项目

问题描述 投票:0回答:1

我在 RecyclerView 中有一个简单的 Pokemon 列表,其中只有 Pokemon 的名称和一个“收藏夹”切换按钮。我使用 Android JetPack 中的分页库和 PageKeyedDataSource 来检索小块 Pokemon 并将其显示给用户。我只希望数据在 Activity 不被破坏的情况下持续存在(即,我不想将数据保留到 Room 或数据库,而是只要 ViewModel 处于活动状态就让它持续存在)。

应用程序截图

我希望能够单击任何 Pokemon 项目上的心形按钮,并将 SimplePokemon 模型中的“isFavorite”字段更新为

true
false
。根据我的理解,如果我想更改该 PagedList 中的单个项目,我需要使 DataSource 无效,理论上,这应该生成一个可以馈送到适配器并显示在屏幕上的 PagedList 的新 LiveData。

问题:如何使用分页库更新 PagedList 中的单个项目,而不需要 Room 或其他数据库?

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

这是迄今为止我的代码:

简单的Pokemon.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 请求来更新后端的 Pokemon,但我只是想让问题变得简单。

任何帮助将不胜感激。

android android-paging pagedlist android-paging-library
1个回答
0
投票

要更新 PagedListAdapter 中的单个项目,我已在 PagedListAdapter 中添加了此方法。 就我而言。

    // Adapter Class
    public class ChatHistoryAdapter extends PagedListAdapter<ChatHistoryEntity, ChatHistoryAdapter.ViewHolder> {
       
        OnClickListener<ChatHistoryEntity> listener;
    Context mContext;


    public ChatHistoryAdapter(Context context) {
        super(DIFF_CALLBACK);
        mContext = context;
    }

    public void setOnClickListener(OnClickListener<ChatHistoryEntity> listener) {
        this.listener = listener;
    }


    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
        ItemChatHistoryBinding binding =
                ItemChatHistoryBinding.inflate(layoutInflater,parent,false);

        return new ViewHolder(binding);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        ChatHistoryEntity current = getChat(position);
        holder.binding.tvSender.setText(current.getName_or_mobile_or_groupName());
        holder.binding.tvMessage.setText(current.getSubject());
//        holder.binding.tvTimestamp.setText(current.getMessage_date_time().toString());

//        holder.tv_sender.setText(current.getContact_name_or_mobile_or_groupName());
//        holder.tv_message.setText(current.getMessage());

        if (current.isSelected()){
               holder.binding.mainLayout.setBackgroundColor(ContextCompat.getColor(mContext, R.color.item_selection));
//            holder.binding.mainLayout.setBackgroundColor();
        }else {
            holder.binding.mainLayout.setBackgroundColor(0);
        }


        holder.Bind(current,listener,position);

    }

    public ChatHistoryEntity getChat(int position) {
        return getItem(position);
    }

    public void updateItemSelection(int position,boolean isSelect){
        ChatHistoryEntity current = getChat(position);
        current.setSelected(isSelect);
        notifyDataSetChanged();
    }

    public void clearSelection(){
        List<ChatHistoryEntity> collect =  StreamSupport.stream(getCurrentList().snapshot())
                .peek(o -> o.setSelected(false))
                .collect(Collectors.toList());

//        submitList(PagedList<ChatHistoryEntity> list = new PagedList<>());
        notifyDataSetChanged();
    }


    private static final DiffUtil.ItemCallback<ChatHistoryEntity> DIFF_CALLBACK =
            new DiffUtil.ItemCallback<ChatHistoryEntity>() {
                @Override
                public boolean areItemsTheSame(@NonNull ChatHistoryEntity oldItem,
                                               @NonNull ChatHistoryEntity newItem) {
                    return oldItem.getId() == newItem.getId();
                }

                @Override
                public boolean areContentsTheSame(@NonNull ChatHistoryEntity    oldItem,
                                                  @NonNull ChatHistoryEntity   newItem) {
                    return oldItem.getId() == newItem.getId()
                            && oldItem.getName_or_mobile_or_groupName()
                            .equalsIgnoreCase(newItem.getName_or_mobile_or_groupName());
                }
            };

    public static class ViewHolder extends RecyclerView.ViewHolder {

        ItemChatHistoryBinding binding;

        public ViewHolder(ItemChatHistoryBinding binding) {
            super(binding.getRoot());
            this.binding =binding;

        }


        void Bind(ChatHistoryEntity chatEntity,   OnClickListener<ChatHistoryEntity> mOnCharacterClick,
                  int position) {

            binding.mainLayout.setOnClickListener(v ->
                    mOnCharacterClick.OnClick(chatEntity,"",position));
        }
    }

    }

    // Activity or fragument Class.
     public class MainActivity extends AppCompatActivity {

         mAdapter.setOnClickListener((currentObj, mode, position) -> {
             // This is how you update single item in PagedListAdapter list.
             mAdapter.updateItemSelection(position,!currentObj.isSelected())
        });


    }
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.