问题描述
我正在设置一个RecyclerView,它使用ListAdapter来计算更改时的动画. RecyclerView通过ViewModel接收数据,该ViewModel通过Firebase获取列表.显示的项目为Mensa
类型. Mensa物品可以更改其可见性,占用率或显示的距离.
I'm setting up a RecyclerView that uses a ListAdapter to calculate animations on changes. The RecyclerView is receiving data through a ViewModel that fetches a list via Firebase. The items shown are of the Mensa
kind. A Mensa item can change its visibility, its occupancy, or the distance displayed.
我想实现两个按钮,它们收藏/隐藏项目,因此更改了它们在列表中的位置.每个项目中的两个按钮允许用户收藏或隐藏一个项目.这将根据排序策略将项目移至列表的顶部/底部,该方法将收藏夹"放在第一位,默认设置在第二位,隐藏在最后.
I want to implement two buttons that favorite/hide items, therefore changing their position in the list. Two buttons in every item allow the user to favorite or hide an item. This will move an item to the top / to the bottom of a list, in accordance with the sorting strategy, which places favorites first, defaults second, and hiddens last.
但是,当我单击一个按钮时,列表将重新排列,但是单击的项目不会重新绑定.按钮保留其旧状态(和OnClickListeners),只有滚动列表才会调用onBind方法. DiffUtil.Callback是我的问题吗?我真的不知道我的代码有什么问题.
However, when I click on a button, the list will rearrange, but the item clicked won't rebind. Buttons retain their old state (and OnClickListeners), and only scrolling the list will call the onBind method. Is my problem with the DiffUtil.Callback? I really don't know what is wrong with my code.
我已经在适配器的commitList方法中提供了一个新列表(本例中另一个stackoverflow问题的建议启用了动画),但是单击的项目仍然不会重绘.
I am already providing a new list in the submitList method of the adapter (this suggestion from another stackoverflow question enabled animations in my case), but the clicked item still won't redraw.
在MensaListActivity.java中
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mensa_list);
viewModel = ViewModelProviders.of(this).get(MensaListModel.class);
final RecyclerView recyclerView =findViewById(R.id.mensa_list_recyclerview);
final MensaListAdapter adapter = new MensaListAdapter(this, new MensaListAdapter.ItemButtonsListener() {
@Override
public void visibilityButtonClicked(Mensa mensa, VisibilityPreference newVisibility) {
viewModel.visibilityChanged(mensa, newVisibility);
}
});
recyclerView.setAdapter(adapter);
recyclerView.setHasFixedSize(false);
recyclerView.setLayoutManager(new GridLayoutManager(this, 1, RecyclerView.VERTICAL, false));
viewModel.getMensaData().observe(this, new Observer<LinkedList<Mensa>>() {
@Override
public void onChanged(LinkedList<Mensa> mensas) {
adapter.submitList(new LinkedList<>(mensas));
}
});
在MensaListModel.java中
public LiveData<LinkedList<Mensa>> getMensaData() {
return mensaData;
}
// ...
public void visibilityChanged(Mensa changedItem, VisibilityPreference newVisibility) {
LinkedList<Mensa> newData = getMensaData().getValue();
int index = newData.indexOf(changedItem);
newData.remove(index);
newData.add(changedItem);
sortMensaData(newData);
// sortMensaData calls postValue method
MensaListAdapter.java
public class MensaListAdapter extends ListAdapter<Mensa, MensaListAdapter.MensaViewHolder> {
private final ItemButtonsListener listener;
private final Context context;
class MensaViewHolder extends RecyclerView.ViewHolder {
TextView nameLabel;
TextView addressLabel;
TextView restaurantTypeLabel;
TextView occupancyLabel;
TextView distanceLabel;
ImageButton favoriteButton;
ImageButton hideButton;
public MensaViewHolder(@NonNull View itemView) {
super(itemView);
// a bunch of assignments
}
public void bindData(final Mensa newMensa) {
nameLabel.setText(newMensa.getName());
addressLabel.setText(newMensa.getAddress());
restaurantTypeLabel.setText(newMensa.getType().toString());
String occText = "Occupancy: " + newMensa.getOccupancy().toInt();
occupancyLabel.setText(occText);
if (newMensa.getDistance() != -1) {
distanceLabel.setVisibility(View.VISIBLE);
distanceLabel.setText(Double.toString(newMensa.getDistance()));
} else {
distanceLabel.setVisibility(View.INVISIBLE);
}
switch(newMensa.getVisibility()){
case FAVORITE:
favoriteButton.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(), R.drawable.favorite_active, null));
favoriteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.visibilityButtonClicked(newMensa, VisibilityPreference.DEFAULT);
}
}); break;
case DEFAULT:
favoriteButton.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(), R.drawable.favorite_inactive, null));
favoriteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.visibilityButtonClicked(newMensa, VisibilityPreference.FAVORITE);
}
}); break;
case HIDDEN:
favoriteButton.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(), R.drawable.favorite_inactive, null));
favoriteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.visibilityButtonClicked(newMensa, VisibilityPreference.FAVORITE);
}
}); break;
// removed hidebutton assignments, as they're identical to the favoritebutton assignment
}
}
}
public MensaListAdapter(Context context, ItemButtonsListener listener) {
super(DIFF_CALLBACK);
this.context = context;
this.listener = listener;
}
private static final DiffUtil.ItemCallback<Mensa> DIFF_CALLBACK =
new DiffUtil.ItemCallback<Mensa>() {
@Override
public boolean areItemsTheSame(@NonNull Mensa oldItem, @NonNull Mensa newItem) {
return oldItem.equals(newItem);
}
@Override
public boolean areContentsTheSame(@NonNull Mensa oldItem, @NonNull Mensa newItem) {
return oldItem.getDistance() == newItem.getDistance()
&& oldItem.getOccupancy().equals(newItem.getOccupancy())
&& oldItem.getVisibility().equals(newItem.getVisibility());
}
};
@Override
public int getItemViewType(int position) {
return R.layout.mensa_list_item;
}
@NonNull
@Override
public MensaViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
return new MensaViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MensaViewHolder holder, int position) {
holder.bindData(getItem(position));
}
public interface ItemButtonsListener{
void visibilityButtonClicked(Mensa mensa, VisibilityPreference newVisibility);
}
}
Mensa.java
public class Mensa {
private String uID;
private String name;
private String address;
private Occupancy occupancy;
private RestaurantType type;
private VisibilityPreference visibility;
private double latitude;
private double longitude;
// distance is calculated lazily as soon as location coordinates are available, -1 means not calculated.
private double distance = -1;
public Mensa() {
}
// generated by android studio
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Mensa mensa = (Mensa) o;
return uID.equals(mensa.uID);
}
@Override
public int hashCode() {
return Objects.hash(uID);
}
// a bunch of getters and setters
}
单击收藏夹"按钮(心形)之前的列表.相关的是心脏和眼睛按钮.
The list before clicking the favorite button (heart). Relevant are the heart and eye buttons.
收藏了Akademiestraße"项目之后的列表.它已经改变了位置,但是心脏图标没有改变,并且OnClickListeners仍然相同.
The list after favoriting the "Akademiestraße" item. It has changed positions, but the heart icon has not changed and the OnClickListeners are still the same.
滚动并返回列表顶部后的列表.现在,心已充满,并且OnClickListeners已更改.
The list after scrolling and returning to the top of the list. The heart is now filled, and OnClickListeners are changed.
推荐答案
在我看来,您的数据正在更新,但RecyclerView仅更新订单,而不更新项目的视图.更新视图中的项目后,尝试调用适配器的notifyDataSetChanged()
.
It seems to me that your data is updating but the RecyclerView is only updating the order and not the item's view. Try calling your adapter's notifyDataSetChanged()
after you update an item in your view.
这篇关于Recyclerview + Listadapter中的项目不会在更新时重绘的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!