Coupling FirebaseRecyclerViewAdapter to a Boolean/String Map.Entry

我怕爱的太早我们不能终老 提交于 2019-11-26 04:51:57

问题


I\'m using the FirebaseRecyclerViewAdapter from the com.firebaseui:firebase-ui:0.2.0 library in many locations of my app. My question is how to apply it in situations where the query argument returns a number of \'index\' entry values (Map.Entry).

As indicated in the Firebase documentation (https://www.firebase.com/docs/android/guide/structuring-data.html), I\'m using indexes to keep the data structure flat. This leads to a situation in which I need to bind these indexes to my ViewHolder. Within the populate view method, I\'m using the key of the index to retrieve the data to fill the viewholder with.

I\'m having trouble to create the adapter, not sure how to define \'modelClass\' argument in case of a Boolean/String Map.Entry:

mAdapter = new FirebaseRecyclerViewAdapter<Map.Entry<String, Boolean>, ItemViewHolder>(???.class, R.layout.my_card, ItemViewHolder.class, getItemIndexQuery(mKey) ) {
...
}

回答1:


Your value is a Boolean, not a Map. So your comment is correct: you will need to specify Boolean/Boolean.class for the value type. To be able to then look up the key, you will need to upgrade to FirebaseUI-Android 0.2.2. In that release we added a populateViewHolder(VH, T, int) overload that gets the position of the item as a parameter. With that, you can look up the key of the item.

Say this is your JSON structure:

{
  "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
  }
}

So we store strings representing date/times and have an index to select a subset of these items.

We can now load the nodes from the index, then load the items that those nodes refer to and display them in the views with:

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) { }
        });
    }
};

The output on screen:

For the full code, see Activity34559171 in this repo.




回答2:


I faced the same issue and finally i found this class: FirebaseIndexRecyclerAdapter Which works perfectly for me.




回答3:


Edit 4

I gave up on the code below, it was garbage. :( Please don't use it. I rewrote the database part of Firebase-UI, so please use that instead.

Edits 1, 2, and 3

Since addListenerForSingleValueEvent means the data will be static (unless you change the value at the key), here's my way of preventing static data without changing the key's value:

Create a list of event listeners and holder objects:

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

The 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);

In your OnDestroy:

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

    for (DatabaseReference databaseReference : mValueEventListeners.keySet()) {
                databaseReference.removeEventListener(mValueEventListeners.get(databaseReference));
    }
}


来源:https://stackoverflow.com/questions/34559171/coupling-firebaserecyclerviewadapter-to-a-boolean-string-map-entry

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!