【问题标题】:update RecyclerView with Android LiveData使用 Android LiveData 更新 RecyclerView
【发布时间】:2017-06-11 22:09:52
【问题描述】:

有很多示例如何在 LiveData 更改时将新列表推送到适配器。

我正在尝试更新庞大列表中的一行(例如帖子的 cmets 数量)。重置整个列表以仅更改一个字段是愚蠢的。

我可以在 BindViewHolder 上添加观察者,但我不明白什么时候应该删除观察者

@Override
public void onBindViewHolder(ViewHolder vh, int position) {
    Post post = getPost(position);
    vh.itemView.setTag(post);
    post.getLiveName().observeForever(vh.nameObserver);
    ... 
}

【问题讨论】:

    标签: android android-recyclerview android-livedata


    【解决方案1】:

    就像@Lyla所说,你应该在Fragment或Activity中观察整个列表作为LiveData,当接收到变化时,你应该通过DiffUtil将整个列表设置为适配器。

    假码:

    PostViewModel {
        LiveData<List<Post>> posts;  // posts comes from DAO or Webservice
    }
    
    MyFragment extends LifecycleFragment {
        PostAdapter postAdapter;
    
        ...
    
        void onActivityCreated() {
            ...
            postViewModel.posts.observer(this, (postList) -> {
                postAdapter.setPosts(postList);
            }
        }       
    }
    
    PostAdapter {
        void setPosts(List<Post> postList) {
            DiffUtil.DiffResult result = DiffUtil.calculateDiff(new DiffUtil.Callback() {...}
            ...
        }
    }
    

    【讨论】:

    • 不推荐在观察者中使用 MyFragment 作为 'this'。这背后的原因是当片段进入回栈时,片段没有被销毁。因此,具有不同实例的同一片段将观察此实时数据。更好的方法是使用 getViewLifecycleOwner。
    【解决方案2】:

    使用DiffUtil 可能有助于更新庞大列表中的一行。然后,您可以让 LiveData 包装 cmets 列表,而不是单个评论或评论的属性。

    这是在 RecyclerView adapterlist LiveData observation code in the fragment 中使用 DiffUtil 的示例。

    【讨论】:

    • 您好 Lyla,您指向“片段中的 LiveData Observaion 代码列表”的链接不起作用。它在 URL 中缺少“/ui/”。正确的 URL 是 ProductListFragment.java#L75 - Luke
    • 修复了链接!谢谢!
    【解决方案3】:

    使用Transformations.switchMap() 交换底层Post 对象。那么在cell被回收的时候就不需要再移除和重新添加observers了。

    @Override
    public void onBindViewHolder(PostViewHolder vh, int position) {
        Post post = getPost(position);
        vh.bind(post);
    }
    

    然后在你的 ViewHolder 类中

    public class PostViewHolder extends RecyclerView.ViewHolder {
        private final MutableLiveData<Post> post = new MutableLiveData<>();
    
        public PostViewHolder(View itemView) {
            super(itemView);
    
            LiveData<String> name = Transformations.switchMap(post, new Function<Post, LiveData<String>>() {
                @Override
                public LiveData<String> apply(Post input) {
                    return input.getLiveName();
                }
            });
    
            name.observeForever(new Observer<String>() {
                @Override
                public void onChanged(@Nullable String name) {
                    // use name
                }
            });
        }
    
        public void bind(Post post) {
            post.setValue(post);
        }
    }
    

    【讨论】:

    • input.getLiveName() 看起来如何工作? Post 不是实体类吗?或者它也可以返回 LiveDatas?
    • 我可以使用它从异构ViewHolder 之一的适配器发布更新RecyclerView
    【解决方案4】:

    我认为你应该为 RecyclerView 适配器使用LiveAdapter,而不是为适配器创建一个额外的类。

    它也有 DiffUtil 实现,所以只会更新单个项目。 并且无需调用 notifyDatasetChange。

    // Kotlin sample
    LiveAdapter(
                data = liveListOfItems,
                lifecycleOwner = this@MainActivity,
                variable = BR.item )
               .map<Header, ItemHeaderBinding>(R.layout.item_header) {
                   onBind{
    
                   }
                   onClick{
    
                   }
                   areContentsTheSame { old: Header, new: Header ->
                       return@areContentsTheSame old.text == new.text
                   }
                   areItemSame { old: Header, new: Header ->
                       return@areContentsTheSame old.text == new.text
                   }
               }
               .map<Point, ItemPointBinding>(R.layout.item_point) {
                   onBind{
    
                   }
                   onClick{
    
                   }
                   areContentsTheSame { old: Point, new: Point ->
                       return@areContentsTheSame old.id == new.id
                   }
                   areItemSame { old: Header, new: Header ->
                       return@areContentsTheSame old.text == new.text
                   }
               }
               .into(recyclerview)
    

    【讨论】:

      【解决方案5】:

      context 添加到您的adapterClass 委托人:AdpaterClass(context: Context)

      然后将context 智能转换为AppCompactActivity

      livedata.observe(context as AppCompatActivity, Observer {it ->
      
              //perform action on it(livedata.value)
          })
      

      当从任何地方activity 调用adapter 时,fragmentcontext 传递给adpater

      【讨论】:

        猜你喜欢
        • 2018-11-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-26
        • 1970-01-01
        • 2020-10-23
        相关资源
        最近更新 更多