Я использую FirebaseRecyclerViewAdapter из библиотеки com.firebaseui:firebase-ui:0.2.0 во многих местах моего приложения. Мой вопрос заключается в том, как применить его в ситуациях, когда аргумент запроса возвращает несколько значений ввода индекса (Map.Entry).

Как указано в документации Firebase (https://www.firebase.com/ docs / android / guide / structuring-data.html), я использую индексы, чтобы структура данных оставалась плоской. Это приводит к ситуации, когда мне нужно привязать эти индексы к моему ViewHolder. В методе заполнения представления я использую ключ индекса для извлечения данных для заполнения держателя просмотра.

У меня проблемы с созданием адаптера, я не знаю, как определить аргумент modelClass в случае Boolean / String Map.Entry:

mAdapter = new FirebaseRecyclerViewAdapter<Map.Entry<String, Boolean>, ItemViewHolder>(???.class, R.layout.my_card, ItemViewHolder.class, getItemIndexQuery(mKey) ) {
...
}
5
Peter 1 Янв 2016 в 22:12

3 ответа

Лучший ответ

Ваша ценность - Boolean, а не Map. Итак, ваш комментарий правильный: вам нужно будет указать Boolean / Boolean.class в качестве типа значения. Чтобы затем найти ключ, вам необходимо перейти на FirebaseUI-Android 0.2.2. В этом выпуске мы добавили перегрузку populateViewHolder(VH, T, int), которая получает позицию элемента в качестве параметра. При этом вы можете найти ключ к предмету.

Скажите, что это ваша структура JSON:

{
  "items": {
    "pushid1": "Fri Jan 01 2016 16:40:54 GMT-0800 (PST)",
    "pushid2": "Fri Jan 01 2016 16:41:07 GMT-0800 (PST)",
    "pushid3": "Fri Jan 01 2016 16:41:25 GMT-0800 (PST)",
    "pushid4": "Fri Jan 01 2016 16:41:37 GMT-0800 (PST)",
    "pushid5": "Fri Jan 01 2016 16:42:04 GMT-0800 (PST)"
  },
  "index": {
    "pushid1": true,
    "pushid3": true,
    "pushid5": true
  }
}

Таким образом, мы храним строки, представляющие дату / время, и имеем индекс для выбора подмножества этих элементов.

Теперь мы можем загрузить узлы из индекса, затем загрузить элементы, на которые ссылаются эти узлы, и отобразить их в представлениях с помощью:

FirebaseRecyclerViewAdapter<Boolean, ItemViewHolder> adapter = 
    new FirebaseRecyclerViewAdapter<Boolean, ItemViewHolder>(
        Boolean.class, android.R.layout.two_line_list_item, ItemViewHolder.class, ref.child("index")){
    protected void populateViewHolder(final ItemViewHolder viewHolder, Boolean model, int position) {
        String key = this.getRef(position).getKey();
        ref.child("items").child(key).addListenerForSingleValueEvent(new ValueEventListener() {
            public void onDataChange(DataSnapshot dataSnapshot) {
                String date = dataSnapshot.getValue(String.class);
                ((TextView)viewHolder.itemView.findViewById(android.R.id.text1)).setText(date);
            }

            public void onCancelled(FirebaseError firebaseError) { }
        });
    }
};

Вывод на экран:

Android app showing three dates

Полный код см. В разделе Activity34559171 в этом репозитории.

10
Frank van Puffelen 2 Янв 2016 в 01:30

Редактировать 4

Я отказался от приведенного ниже кода, это был мусор. :( Пожалуйста, не используйте его. Я переписал часть базы данных Firebase-UI, поэтому используйте ее.

Правки 1, 2 и 3

Поскольку addListenerForSingleValueEvent означает, что данные будут статическими (если вы не измените значение в ключе), вот мой способ предотвратить статические данные без изменения значения ключа:

Создайте список слушателей событий и объектов-держателей:

private Map<DatabaseReference, ValueEventListener> mValueEventListeners = new ArrayMap<>();
private List<TeamInfo> mTeamInfoList = new ArrayList<>();

FirebaseRecyclerAdapter:

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.content_main_recycler_view);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        mRecyclerViewAdapter = new FirebaseRecyclerAdapter<Long, TeamHolder>(
                Long.class,
                R.layout.activity_main_row_layout,
                TeamHolder.class,
                Utils.getDatabase()
                        .getReference()
                        .child(Constants.FIREBASE_TEAM_INDEXES)
                        .child(mUser.getUid())
                        .orderByValue()) {
            @Override
            public void populateViewHolder(final TeamHolder teamHolder,
                                           Long teamNumberDoNotUse,
                                           final int position) {
                DatabaseReference databaseReference = Utils.getDatabase()
                        .getReference()
                        .child(Constants.FIREBASE_TEAMS)
                        .child(getRef(position).getKey());

                if (!mValueEventListeners.containsKey(databaseReference)) {
                    ValueEventListener valueEventListener = new ValueEventListener() {
                        public void onDataChange(DataSnapshot dataSnapshot) {
                            if (dataSnapshot.getValue() != null) {
                                TeamInfo teamInfo = dataSnapshot.getValue(TeamInfo.class);

                                if (position >= mTeamInfoList.size()) {
                                    String teamNumber = teamInfo.getNumber();

                                    teamHolder.setTeamNumber(teamNumber);
                                    teamHolder.setTeamName(teamInfo.getName(),
                                                           MainActivity.this.getString(R.string.no_name));
                                    teamHolder.setTeamLogo(teamInfo.getMedia(), MainActivity.this);
                                    teamHolder.setListItemClickListener(teamNumber,
                                                                        MainActivity.this,
                                                                        dataSnapshot.getKey());
                                    teamHolder.setCreateNewScoutListener(teamNumber,
                                                                         MainActivity.this,
                                                                         dataSnapshot.getKey());

                                    mTeamInfoList.add(teamInfo);
                                } else {
                                    mTeamInfoList.set(position, teamInfo);
                                    notifyItemChanged(position);
                                }
                            } else {
                                // This should never happen since we are caching this offline
                                FirebaseCrash.report(new IllegalStateException(
                                        "MainActivity RecyclerView event listener had null value (ref: " + dataSnapshot.getRef() + "pointed to non existent data)"));
                            }
                        }

                        public void onCancelled(DatabaseError databaseError) {
                            FirebaseCrash.report(databaseError.toException());
                        }
                    };

                    databaseReference.addValueEventListener(valueEventListener);
                    mValueEventListeners.put(databaseReference, valueEventListener);
                } else {
                    String teamNumber = mTeamInfoList.get(position).getNumber();

                    teamHolder.setTeamNumber(teamNumber);
                    teamHolder.setTeamName(mTeamInfoList.get(position).getName(),
                                           MainActivity.this.getString(R.string.no_name));
                    teamHolder.setTeamLogo(mTeamInfoList.get(position).getMedia(), MainActivity.this);
                    teamHolder.setListItemClickListener(teamNumber, MainActivity.this, getRef(position).getKey());
                    teamHolder.setCreateNewScoutListener(teamNumber, MainActivity.this, getRef(position).getKey());
                }
            }
        };

        recyclerView.setAdapter(mRecyclerViewAdapter);

В вашем OnDestroy:

@Override
protected void onDestroy() {
    super.onDestroy();
    if (mRecyclerViewAdapter != null) {
        mRecyclerViewAdapter.cleanup();
    }

    for (DatabaseReference databaseReference : mValueEventListeners.keySet()) {
                databaseReference.removeEventListener(mValueEventListeners.get(databaseReference));
    }
}
0
SUPERCILEX 1 Сен 2016 в 06:31

Я столкнулся с той же проблемой и, наконец, нашел этот класс: FirebaseIndexRecyclerAdapter Что отлично работает для меня.

1
Shirane85 8 Май 2017 в 22:42