有很多例子说明如何在LiveData更改时将新列表推送到适配器。
我试图在巨大的列表中更新一行(例如,帖子的评论数量)。将整个列表重置为仅更改一个字段将是愚蠢的。
我可以添加观察者onBindViewHolder,但我无法理解何时应该删除观察者
@Override
public void onBindViewHolder(ViewHolder vh, int position) {
Post post = getPost(position);
vh.itemView.setTag(post);
post.getLiveName().observeForever(vh.nameObserver);
...
}
答案 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 adapter和list 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