Страницы

Поиск по вопросам

пятница, 31 января 2020 г.

Как изменять содержимое CardView элементов в RecyclerView

#java #android #recyclerview


Задача:

У меня есть RecyclerView, который я заполняю карточками, содержание которых берется
с сервера. Эти карточки - диалоги. 

И в этих карточках есть специальное поле - последнее сообщение. Когда пользователь
отправляет мне сообщение это поле должно измениться на это последнее сообщение соответственно.

Проблема:

Мне как-то нужно реализовать динамическое изменение этих элементов RecyclerView. 

Подробности:

Меня интересует именно вопрос изменения элементов в реальном времени, а не способ
реализации отправки сообщений.

Если диалоги, я могу добавить adapter.addAll(data);, то вот как их изменять я не
знаю. Причем это, как я сказал ранее, должно происходить динамически, то есть на глазах
пользователя (без перезагрузки Activity или Fragment или самого приложения)

Код, адаптер и холдер

 private class RecyclerAdapter extends 
 RecyclerView.Adapter {
    private ArrayList items = new ArrayList<>();

    void addAll(List fakeItems) {
        int pos = getItemCount();
        this.items.addAll(fakeItems);
        notifyItemRangeInserted(pos, this.items.size());
    }

    @Override
    public int getItemViewType(int position)
    {
        return 0;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        RecyclerView.ViewHolder vh=null;
        View itemLayoutView;

        switch (getItemViewType(viewType))
        {
            case 0:
                itemLayoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.dialog_structure,
parent, false);
                vh = new RecyclerViewHolder(itemLayoutView);
                break;

        }
        return vh;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        switch (this.getItemViewType(position))
        {
            case 0:
                RecyclerViewHolder simple = (RecyclerViewHolder) holder;
                simple.bind(items.get(position));
                break;
        }
    }


    @Override
    public int getItemCount() {
        return items.size();
    }

}

private class RecyclerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
    //simple
    private TextView name;
    private TextView time;
    private CircleImageView circleImageView;
    private TextView lastMessage;

    RecyclerViewHolder(View itemView) {
        super(itemView);
        name = itemView.findViewById(R.id.person_name);
        time = itemView.findViewById(R.id.message_time);
        circleImageView = itemView.findViewById(R.id.person_photo);
        lastMessage = itemView.findViewById(R.id.last_message);

    }

    void bind(DialogInfo modelItem) {

        try {
            Picasso.with(getActivity().getApplicationContext()).load("http://46.173.213.127/media?t=avatar&query="+modelItem.getPhoto()).into(circleImageView);
        } catch (Exception ignored) {
        }

        name.setText(modelItem.getName());
        time.setText(modelItem.getTime());
        lastMessage.setText(modelItem.getLastMessage());
    }

    @Override
    public void onClick(View view) {

    }
}


Добавление элементов:

for(int i = 0; i < contacts.size(); i++){
        data.add(new DialogInfo("lol",contacts.get(i), "lol","lol"));

    }

    adapter = new RecyclerAdapter();
    rv.setAdapter(adapter);
    adapter.addAll(data);
    data.set(1, new DialogInfo("lol",contacts.get(1), "keke","kek"));//вот здесь
я пытался изменить нужный мне элемент, но он не изменяется в реальном времени.




Заранее, за все предложенные варианты добрыми людьми, говорю спасибо!

ДОПОЛНЕНИЕ:

adapter = new RecyclerAdapter();
    rv.setAdapter(adapter);
    adapter.addAll(data);
    data.set(1, new DialogInfo("lol",contacts.get(1), "keke","kek"));
    adapter.notifyDataSetChanged();

    


Ответы

Ответ 1



Ваша проблема заключается в том, что списки у вас разные. Первый вариант: вам надо редактировать один список, т.е. в фрагменте/активити держите список и его же передаете в адаптер. class MainActivity ... { . ... private List data = new ArrayList<>(); void initAdapter(){ adapter = new RecyclerAdapter(); adapter.setItems(data); rv.setAdapter(adapter); } void onClick(View view){ switch(view.getId()){ case R.id.edit: editItem(1, new DialogInfo("lol",contacts.get(1), "keke","kek")); break; case R.id.add: addItem(new DialogInfo("lol",contacts.get(1), "keke","kek")); break; } } private void editItem(int position, DialogInfo value) { data.set(position, value); adapter.notifyItemChange(position); } private void addItem(DialogInfo value) { data.add(value); adapter.notifyItemInserted(data.size()-1); } } private class RecyclerAdapter ... { private List items; ... public void setItems(List data){ this.items = data; } ... } Второй вариант: реализуете методы добавления, удаления, редактирования в адаптере. class MainActivity ... { . ... private List data = new ArrayList<>(); void initAdapter(){ adapter = new RecyclerAdapter(); adapter.addItems(data); rv.setAdapter(adapter); } void onClick(View view){ switch(view.getId()){ case R.id.edit: adapter.editItem(1, new DialogInfo("lol",contacts.get(1), "keke","kek")); break; case R.id.add: adapter.addItem(new DialogInfo("lol",contacts.get(1), "keke","kek")); break; } } } private class RecyclerAdapter ... { private List items = new ArrayList<>(); ... public void addItems(List data){ int pos = getItemCount(); this.items.addAll(data); notifyItemRangeInserted(pos, this.items.size()-1); } public void editItem(int position, DialogInfo value) { items.set(position, value); notifyItemChange(position); } public void addItem(int position, DialogInfo value) { items.add(value); items.notifyItemInserted(items.size()-1); } ... } Некоторые сложности будут, если вы захотите инициировать редактирование из holder'ов, вам надо будет в первом случае пробросить до активити/фрагмента вызов соответствующих колбэков, во втором случае логика редактирования в адаптере может выглядеть неуместной, и колбэки все равно будут. Особенно это хорошо будет видно на вашем примере, когда все классы у вас отдельные (не вложенные).

Ответ 2



Если я правильно понял Вам надо перерисовать Ресайкл. У адаптера есть метод adapter.notifyDataSetChanged() - который перерисовывает данные. Т.е. вам надо перезаписать data и потом дергать adapter.notifyDataSetChanged()

Ответ 3



Для обновления данных для определенного итема желательно использовать adapter.notifiyItemChanged(int position) Вызывать перерисовку списка, обновляя адаптер notifyDataSetChanged() это должно быть последним, что вы должны сделать, так как это полностью рефрешит структуру списка. Это два разных класса. Данные рекомендации описаны в оф документации. Дополнительно: CardView сложный элемент и предназначен для отображения сложных по структуре ячеек. Также в адаптере очень часто к item привязывают слушатели, аттачат обсерверы etc, поэтому я рекомендую более правильно обновлять данные, бонус ко всему, только с помощью таких манипуляций вы можете обеспечить правильное обновление и анимировать ваши ячейки. Обновляя список полностью вам необходимо также обеспечить целостность данных, если они имеет связность или даже транзитивность, то может возникнуть визуальная коллизия, это уже зависит от реализации и правильной архитектуры.

Комментариев нет:

Отправить комментарий