LiveData<List<Obj>> 中的更改未显示在 recyclerView 中,它在 LiveData<List> 上订阅
Changes in LiveData<List<Obj>> aren't shown in recyclerView, which is subscrived on the LiveData<List>
当我点击一个项目时,OnItemListener.onItemClick(参见适配器代码)起作用,并删除
分别来自 LiveData mListLivedata(参见 ViewModel)。
问题是这不会更新 recyclerView,尽管事实上有一个
订阅此 LiveData 的观察者。 recyclerView 中仍然有 4 个视图,但是如果
如果我点击视图中的最后一个项目(之前已经点击过任何项目),
它崩溃是因为 Livedata> 中已经少了一个对象(因为上一次点击有
删除了一个对象)。因此,点击后 LiveData 中的对象数量减少了一个(这
是我需要的),但视图中的项目数量保持不变(这是错误,我不明白
我的错误在哪里)。
我的错误在哪里,解决方法是什么?
在视图模型中:
public class PersonViewModel extends AndroidViewModel {
private PersonRepository mRepository;
private CompositeDisposable composite = new CompositeDisposable();
private Single<List<Person>> mThreePersons;
private ArrayList<Person> mList = new ArrayList<>();
private MutableLiveData<List<Person>> mListLivedata = new MutableLiveData<>();
public PersonViewModel(@NonNull Application application) {
super(application);
mRepository = new PersonRepository(application);
mThreePersons = mRepository.getThreePersons();
mThreePersons.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<List<Person>>() {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "onSubscribe(Disposable d): called");
composite.add(d);
}
@Override
public void onSuccess(List<Person> people) {
Log.d(TAG, "onSuccess: called");
mList.addAll(people);
mListLivedata.setValue(mList);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "onError: called");
Toast.makeText(application, "NO DATA", Toast.LENGTH_SHORT).show();
}
});
}
LiveData<List<Person>> getListLivedata() {
return mListLivedata;
}
public void removePerson(Person person) {
mList.remove(person);
mListLivedata.setValue(mList);
Log.d(TAG, "removePerson: called");
}
}
在Activity中:
public class PersonRecyclerActivity extends AppCompatActivity implements PersonRecyclerAdapter.OnItemListener {
private PersonViewModel personRecyclerViewModel;
private PersonRecyclerAdapter personRecyclerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recycler_simple_layout);
RecyclerView personRecyclerView = findViewById(R.id.recycler_view);
personRecyclerAdapter =
new MudakRecyclerAdapter(new PersonRecyclerAdapter.PersonRecyclerDiff(), this);
personRecyclerView.setAdapter(personRecyclerAdapter);
personRecyclerView.setLayoutManager(new LinearLayoutManager(this));
personRecyclerViewModel = new ViewModelProvider(this,
ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication()))
.get(PersonViewModel.class);
personRecyclerViewModel.getListLivedata().observe(this, personList -> personRecyclerAdapter.submitList(personList));
}
@Override
public void onItemClick(int position) {
Log.d(TAG, "onItemClick: called for " + personRecyclerAdapter.getPersonAt(position).getName() + ", at the position " + position);
personRecyclerViewModel.removePerson(personRecyclerAdapter.getPersonAt(position));
}
}
在适配器中:
public class PersonRecyclerAdapter extends ListAdapter<Person, PersonRecyclerAdapter.PersonRecyclerViewHolder> {
private OnItemListener mOnItemListener;
public interface OnItemListener {
void onItemClick(int position);
}
protected PersonRecyclerAdapter(@NonNull DiffUtil.ItemCallback<Person> diffCallback, OnItemListener onItemListener) {
super(diffCallback);
mOnItemListener = onItemListener;
}
public class PersonRecyclerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private final TextView mrName;
private final TextView mrStatus;
OnItemListener onItemListener;
public PersonRecyclerViewHolder(@NonNull View itemView, OnItemListener onItemListener) {
super(itemView);
mrName = itemView.findViewById(R.id.tv_rec_name);
mrStatus = itemView.findViewById(R.id.tv_rec_status);
this.onItemListener = onItemListener;
itemView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
onItemListener.onItemClick(getAdapterPosition());
}
}
public Person getPersonAt(int position) {
return getItem(position);
}
@NonNull
@Override
public MudakRecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycler_simple_item, parent, false);
return new MudakRecyclerAdapter.MudakRecyclerViewHolder(view, mOnItemListener);
}
@Override
public void onBindViewHolder(@NonNull MudakRecyclerViewHolder holder, int position) {
Person currentPerson = getItem(position);
holder.mrName.setText(currentPerson.getName());
holder.mrStatus.setText(currentPerson.getStatus());
}
static class PersonRecyclerDiff extends DiffUtil.ItemCallback<Person> {
@Override
public boolean areItemsTheSame(@NonNull Person oldItem, @NonNull Person newItem) {
return oldItem == newItem;
}
@Override
public boolean areContentsTheSame(@NonNull Person oldItem, @NonNull Person newItem) {
return oldItem.getName().equals(newItem.getName());
}
}
}
如果您向 ListAdapter 提交它之前使用的相同列表实例,ListAdapter 将不会执行任何操作,因为它旨在比较两个不同的列表以了解它们之间的差异。您应该使 removePerson()
方法创建一个新的 List 实例并删除该项目并将其传递给 LiveData。
示例:
public void removePerson(Person person) {
mList = new ArrayList(mList); // create a new list with same contents
mList.remove(person); // remove the item from the new list.
mListLivedata.setValue(mList);
Log.d(TAG, "removePerson: called");
}
当我点击一个项目时,OnItemListener.onItemClick(参见适配器代码)起作用,并删除
分别来自 LiveData mListLivedata(参见 ViewModel)。
问题是这不会更新 recyclerView,尽管事实上有一个
订阅此 LiveData 的观察者。 recyclerView 中仍然有 4 个视图,但是如果
如果我点击视图中的最后一个项目(之前已经点击过任何项目),
它崩溃是因为 Livedata
> 中已经少了一个对象(因为上一次点击有
删除了一个对象)。因此,点击后 LiveData 中的对象数量减少了一个(这
是我需要的),但视图中的项目数量保持不变(这是错误,我不明白
我的错误在哪里)。
我的错误在哪里,解决方法是什么?
在视图模型中:
public class PersonViewModel extends AndroidViewModel {
private PersonRepository mRepository;
private CompositeDisposable composite = new CompositeDisposable();
private Single<List<Person>> mThreePersons;
private ArrayList<Person> mList = new ArrayList<>();
private MutableLiveData<List<Person>> mListLivedata = new MutableLiveData<>();
public PersonViewModel(@NonNull Application application) {
super(application);
mRepository = new PersonRepository(application);
mThreePersons = mRepository.getThreePersons();
mThreePersons.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<List<Person>>() {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "onSubscribe(Disposable d): called");
composite.add(d);
}
@Override
public void onSuccess(List<Person> people) {
Log.d(TAG, "onSuccess: called");
mList.addAll(people);
mListLivedata.setValue(mList);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "onError: called");
Toast.makeText(application, "NO DATA", Toast.LENGTH_SHORT).show();
}
});
}
LiveData<List<Person>> getListLivedata() {
return mListLivedata;
}
public void removePerson(Person person) {
mList.remove(person);
mListLivedata.setValue(mList);
Log.d(TAG, "removePerson: called");
}
}
在Activity中:
public class PersonRecyclerActivity extends AppCompatActivity implements PersonRecyclerAdapter.OnItemListener {
private PersonViewModel personRecyclerViewModel;
private PersonRecyclerAdapter personRecyclerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recycler_simple_layout);
RecyclerView personRecyclerView = findViewById(R.id.recycler_view);
personRecyclerAdapter =
new MudakRecyclerAdapter(new PersonRecyclerAdapter.PersonRecyclerDiff(), this);
personRecyclerView.setAdapter(personRecyclerAdapter);
personRecyclerView.setLayoutManager(new LinearLayoutManager(this));
personRecyclerViewModel = new ViewModelProvider(this,
ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication()))
.get(PersonViewModel.class);
personRecyclerViewModel.getListLivedata().observe(this, personList -> personRecyclerAdapter.submitList(personList));
}
@Override
public void onItemClick(int position) {
Log.d(TAG, "onItemClick: called for " + personRecyclerAdapter.getPersonAt(position).getName() + ", at the position " + position);
personRecyclerViewModel.removePerson(personRecyclerAdapter.getPersonAt(position));
}
}
在适配器中:
public class PersonRecyclerAdapter extends ListAdapter<Person, PersonRecyclerAdapter.PersonRecyclerViewHolder> {
private OnItemListener mOnItemListener;
public interface OnItemListener {
void onItemClick(int position);
}
protected PersonRecyclerAdapter(@NonNull DiffUtil.ItemCallback<Person> diffCallback, OnItemListener onItemListener) {
super(diffCallback);
mOnItemListener = onItemListener;
}
public class PersonRecyclerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private final TextView mrName;
private final TextView mrStatus;
OnItemListener onItemListener;
public PersonRecyclerViewHolder(@NonNull View itemView, OnItemListener onItemListener) {
super(itemView);
mrName = itemView.findViewById(R.id.tv_rec_name);
mrStatus = itemView.findViewById(R.id.tv_rec_status);
this.onItemListener = onItemListener;
itemView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
onItemListener.onItemClick(getAdapterPosition());
}
}
public Person getPersonAt(int position) {
return getItem(position);
}
@NonNull
@Override
public MudakRecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycler_simple_item, parent, false);
return new MudakRecyclerAdapter.MudakRecyclerViewHolder(view, mOnItemListener);
}
@Override
public void onBindViewHolder(@NonNull MudakRecyclerViewHolder holder, int position) {
Person currentPerson = getItem(position);
holder.mrName.setText(currentPerson.getName());
holder.mrStatus.setText(currentPerson.getStatus());
}
static class PersonRecyclerDiff extends DiffUtil.ItemCallback<Person> {
@Override
public boolean areItemsTheSame(@NonNull Person oldItem, @NonNull Person newItem) {
return oldItem == newItem;
}
@Override
public boolean areContentsTheSame(@NonNull Person oldItem, @NonNull Person newItem) {
return oldItem.getName().equals(newItem.getName());
}
}
}
如果您向 ListAdapter 提交它之前使用的相同列表实例,ListAdapter 将不会执行任何操作,因为它旨在比较两个不同的列表以了解它们之间的差异。您应该使 removePerson()
方法创建一个新的 List 实例并删除该项目并将其传递给 LiveData。
示例:
public void removePerson(Person person) {
mList = new ArrayList(mList); // create a new list with same contents
mList.remove(person); // remove the item from the new list.
mListLivedata.setValue(mList);
Log.d(TAG, "removePerson: called");
}