Просмотр Recycler отображается только после нажатия кнопки редактирования текста

#android #android-fragments #android-recyclerview

#Android #android-фрагменты #android-recyclerview

Вопрос:

У меня есть фрагмент с панелью поиска (редактировать текст) и представлением recycler внизу. Для отображения моего представления recycler я использую адаптер. Я пытаюсь отобразить всех друзей пользователя. Проблема в том, что элементы представления recycler не отображаются, если я не нажму на панель поиска (ничего не вводя).
Кроме того, при загрузке изображений из моей базы данных в просмотр изображений они путаются.
Моя база данных выглядит следующим образом:

 {
 "Friends": {
            "id3":{
                "id1": "name1",
                "id2": "name2",
                ...
            },
            "id4":{
                "id1": "name1",
                "id3": "name3",
                ...
            }, ...
 },
 "Users": {
          "id1":{
             info about user1
          },
          "id2":{
             info about user2
          },
          "id3":{
             info about user3
          },
          "id4":{
             info about user4
          }, ...
 }
}
 

Я немного отладил и обнаружил, что мой onCreateViewHolder никогда не вызывается при создании фрагмента (не уверен, актуально ли это).
Я также попытался использовать другой запрос, который просто отображает всех пользователей в базе данных (поэтому просто перебирает дочерние элементы узла «Пользователи»). Это сработало, поэтому я полагаю, что проблема связана с моими запросами. Однако я не могу понять, где я ошибаюсь.

Как я связываю свое представление recycler с моим адаптером:

 recyclerView = view.findViewById(R.id.frag_invite_recycler);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));

searchBar = view.findViewById(R.id.frag_invite_search_bar);

mUsers = new ArrayList<>();
mAdapter = new EventUserAdapter(getContext(),mUsers);
recyclerView.setAdapter(mAdapter);
 

Запрос моих друзей:

 Query friends = FirebaseDatabase.getInstance().getReference("Friends").child(firebaseUser.getUid()).orderByValue();

friends.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                mUsers.clear();

                for (DataSnapshot snp : dataSnapshot.getChildren()) {

                    Query users = FirebaseDatabase.getInstance().getReference("Users").child(snp.getKey());

                    users.addValueEventListener(new ValueEventListener() {
                        @Override
                        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                            User user = dataSnapshot.getValue(User.class);

                            assert user != null;
                            mUsers.add(user);
                        }
                        @Override
                        public void onCancelled(@NonNull DatabaseError databaseError) {
                        }
                    });
                }
                mAdapter.notifyDataSetChanged();
            }
            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {
            }
        });
 

Мой адаптер:

 @NonNull
    @Override
    public EventViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.user_event, viewGroup, false);

        return new EventViewHolder(view, mListener);
    }

    @Override
    public void onBindViewHolder(@NonNull EventViewHolder eventViewHolder, int i) {
        firebaseUser = FirebaseAuth.getInstance().getCurrentUser();

        final User user = mUsers.get(i);

        eventViewHolder.username.setText(user.getUsername());
        if (user.getImgURL() != null) Glide.with(eventViewHolder.icon.getContext()).load(user.getImgURL()).into(eventViewHolder.icon);

    }

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

Мой ViewHolder:

 public class EventViewHolder extends RecyclerView.ViewHolder {

        public TextView username;
        public ImageView check;
        public CircleImageView icon;

        public EventViewHolder(@NonNull View itemView, final onItemClickListener listner) {
            super(itemView);
            username = itemView.findViewById(R.id.user_event_name);
            icon = itemView.findViewById(R.id.user_event_image);
            check = itemView.findViewById(R.id.user_event_check);
    }
}
 

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

1. Я не понимаю вашего вопроса, работает это или нет, и в чем проблема. Не могли бы вы перефразировать?

2. Что ж, когда я открываю фрагмент, представление recycler пусто. Затем всякий раз, когда я нажимаю на строку поиска (ничего не записывая), представление recycler заполняется. Однако я хочу, чтобы все данные появлялись сразу после создания фрагмента (а не только после нажатия на строку поиска).

3. Но вы сказали, что как только вы добавили запрос, который отображает всех пользователей, приложение работает должным образом. С того места, где я сижу, первоначальная проблема заключалась в том, что вы не заполняли свой recyclerview контент после создания его EventUserAdapter адаптера, а только при использовании editText . Таким образом, запрос, который изначально отображает всех пользователей, решает эту проблему. Что еще вам нужно?

4. Приведенный выше запрос вызывается изначально перед OnTextChange из EditText. Значит, он должен появиться до того, как я введу его в строке поиска, верно? Я также заметил, что mAdapter.notifyDataSetChanged() не обновляет значения внутри адаптера до тех пор, пока я не использую панель поиска.

5. Если вы вызываете запрос при создании activity (onCreate, OnStart и т. Д.), Он должен отображаться независимо от того, ввели вы что-либо в editText или нет. Когда вы вызываете mAdapter.notifyDataSetChanged() , это фактически вызывает onBindViewHolder отображаемые в данный момент представления. onBindViewHolder Мне кажется, что ваш метод подходит, вы получаете свои данные из позиции текущего представления и правильно обновляете представление. Проверьте, вызывается ли этот метод даже после того, как вы это сделаете notifyDataSetChanged (с журналами или отладкой). Если он вызывается, проблема, вероятно, где-то в другом месте.

Ответ №1:

Я думаю, что проблема связана с расположением mAdapter.notifyDataSetChanged();
в разделе запросов моих друзей.
Вы вызываете команду вне внутреннего обратного users.addValueEventListener вызова, и это может быть слишком рано, ваш массив пользователей только что очищен и еще не заполнен.

Попробуйте сделать что-то вроде:

 friends.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        mUsers.clear();
        mAdapter.notifyDataSetChanged(); // for the current views actually reset
        // you could also do mAdpater.notifyItemRangeRemoved(0, mUsers.size()) but before clearing the list of course

        for (DataSnapshot snp : dataSnapshot.getChildren()) {

            Query users = FirebaseDatabase.getInstance().getReference("Users").child(snp.getKey());

            users.addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                    User user = dataSnapshot.getValue(User.class);

                    assert user != null;
                    mUsers.add(user);
                    mAdapter.notifyItemInserted(mUsers.size() - 1); // to display the current user in the recyclerview
                }
                @Override
                public void onCancelled(@NonNull DatabaseError databaseError) {
                }
            });
        }
    }
    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {
    }
});
 

Если все еще не работает, возможно, вы используете два разных списка пользователей: один в activity, а второй в адаптере? проверьте, сохраняете ли вы ссылку на исходный список или создаете новую на основе значений оригинала (в конструкторе adpater). Тогда обновление списка действий не повлияет на список адаптеров.

Я надеюсь, что это решит вашу проблему!

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

1. Действительно, похоже, что я назвал свой notifyDataSetChanged в неправильном месте. Я также внес некоторые улучшения, чтобы вы могли просто вызвать mAdapter.add(item), который затем добавляет непосредственно элемент в список в адаптере, который, в свою очередь, вызывает notifyDataSetChanged . Большое вам спасибо за помощь 🙂