使用Android LiveData更新RecyclerView

时间:2017-06-11 22:09:53

标签: android recycler-adapter android-livedata

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

我试图在巨大的列表中更新一行(例如,帖子的评论数量)。将整个列表重置为仅更改一个字段将是愚蠢的。

我可以添加观察者onBindViewHolder,但我无法理解何时应该删除观察者

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

5 个答案:

答案 0 :(得分:11)

像@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() {...}
        ...
    }
}

答案 1 :(得分:9)

使用DiffUtil可能有助于更新巨大列表中的一行。然后,您可以让LiveData包含注释列表,而不是注释的单个注释或属性。

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

答案 2 :(得分:3)

使用Transformations.switchMap()交换基础Post对象。然后,当电池被回收时,无需移除和重新添加观察者。

@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);
    }
}

答案 3 :(得分:0)

我认为您应该将 LiveAdapter 用于 RecyclerView Adapter 而不是为适配器创建额外的类。

它也有 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)

答案 4 :(得分:-1)

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

然后聪明地将context投射到AppCompactActivity

livedata.observe(context as AppCompatActivity, Observer {it ->

        //perform action on it(livedata.value)
    })

从任何地方adapter调用activity时,fragment会将context传递到adpater