Элементы в Recyclerview + Listadapter не будут перерисовываться при обновлении - PullRequest
0 голосов
/ 14 июня 2019

Я настраиваю RecyclerView, который использует ListAdapter для расчета анимации изменений.RecyclerView получает данные через ViewModel, которая получает список через Firebase.Показанные предметы имеют вид Mensa.Элемент Mensa может изменять свою видимость, его занятость или отображаемое расстояние.

Я хочу реализовать две кнопки, которые предпочитают / скрывают элементы, поэтому меняя их положение в списке.Две кнопки в каждом элементе позволяют пользователю добавить в избранное или скрыть элемент.Это переместит элемент в верхнюю / нижнюю часть списка в соответствии со стратегией сортировки, которая помещает избранное в первую очередь, по умолчанию - вторую, а скрытые - в последнюю.

Однако, когда я нажимаю на кнопку,список будет перегруппирован, но нажатый элемент не будет перепривязан.Кнопки сохраняют свое старое состояние (и OnClickListeners), и только прокрутка списка вызовет метод onBind.У меня проблема с DiffUtil.Callback?Я действительно не знаю, что не так с моим кодом.

Я уже предоставляю новый список в методе submitList адаптера (это предложение из другого вопроса stackoverflow включило анимацию в моем случае), но щелкнулэлемент по-прежнему не будет перерисовываться.

в 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

}

1

Список до нажатиялюбимая кнопка (сердце).Соответствующими являются кнопки «сердце» и «глаз».

2

Список после добавления в список "Akademiestraße".Он изменил позиции, но значок сердца не изменился, и OnClickListeners остались прежними.

3

Список после прокрутки и возврата в начало списка.Сердце заполнено, и OnClickListeners изменены.

1 Ответ

0 голосов
/ 14 июня 2019

Мне кажется, что ваши данные обновляются, но RecyclerView обновляет только порядок, а не вид элемента.Попробуйте позвонить вашему адаптеру notifyDataSetChanged() после обновления элемента в вашем представлении.

...