FirebaseRecyclerAdapter's populateViewHolder()

2020-04-30 18:13发布

问题:

I am using FirebaseUI's FirebaseRecyclerAdapter in my app to fetch some data from a FirebaseDatabase reference and show it in a RecyclerView. I'm completing this task successfully.

Here's my code:

private void attachRecyclerViewAdapter() {
        Query lastFifty = mDatabase.child(rID).limitToFirst(50);
        mRecyclerViewAdapter = new FirebaseRecyclerAdapter<AModelClass, AModelClass.ViewHolder>(
                AModelClass.class, R.layout.a_player_layout, APlayersModelClass.ViewHolder.class, lastFifty) {

            @Override
            protected void populateViewHolder(AModelClass.ViewHolder viewHolder, AsModelClass model, int position) {

                String key = this.getRef(position).getKey();
                aReference.child(requestID).child(key).addListenerForSingleValueEvent(new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {
                        if (dataSnapshot.getValue() != null) {

                            Map<String, String> map = (Map<String, String>) dataSnapshot.getValue();
                            pA = map.get("pName");
                            uA = map.get("pUrl"); 
                            // error on line below
                            String cLatS = map.get("cLat").trim();
                            currentLtAU = Double.parseDouble(cLatS);
                            String cLngS = map.get("cLng").trim();
                            currentLnAU = Double.parseDouble(cLngS);

                            viewHolder.setPName(pA);
                            viewHolder.setPUrl(uA);
                            viewHolder.setCurrentLatAU(String.valueOf(currentLtAU));
                            viewHolder.setCurrentLngAU(String.valueOf(currentLnAU));

                        } else {
                            Snackbar snackbar = Snackbar
                                    .make(coordinatorLayout, "Some error occurred. Please retry!", Snackbar.LENGTH_SHORT);
                            snackbar.show();
                            onBackPressed();
                        }
                    }

                    @Override
                    public void onCancelled(DatabaseError databaseError) {

                    }
                });

            }
        };

        aList.setAdapter(mRecyclerViewAdapter);
    }

Here's database structure's representation:

-app
  -requestID
    -uniqueKey1
      -key: value
      -key: value
      -cLat: value
    -uniqueKey2
      -key: value
      -key: value
      -cLat: value

The problem is that as soon as I remove uniqueKey1 from the database, the code inside the populateViewHolder() method is called and the data under uniqueKey1 don't gets removed completely and thus aReference.child(requestID).child(key) takes the uniqueKey1 again but this time some of the data, specifically cLat is removed from here and thus the app crashes giving java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.String.trim()' on a null object reference error on the line specified in the code.

What I want to know is how can I let the the code inside populateViewHolder() called only when the uniqueKey1 along with the data under it is completely removed and then the aReference.child(requestID).child(key) takes only uniqueKey2 (remaining key(s)) as parameter to load data again and show in recyclerview?

回答1:

Well, I think I figured out a way.

Just placed some conditions in the code.

Here's the updated code:

    if (dataSnapshot.getValue() != null) {

         if (dataSnapshot.hasChild("pName") && dataSnapshot.hasChild("pUrl") && dataSnapshot.hasChild("cLat") && dataSnapshot.hasChild("cLng")) {

                 Map<String, String> map = (Map<String, String>) dataSnapshot.getValue();
                 pA = map.get("pName");
                 uA = map.get("pUrl");
                 String cLatS = map.get("cLat").trim();
                 currentLtAU = Double.parseDouble(cLatS);
                 String cLngS = map.get("cLng").trim();
                 currentLnAU = Double.parseDouble(cLngS);

                 viewHolder.setPName(pA);
                 viewHolder.setPUrl(uA);
                 viewHolder.setCurrentLatAU(String.valueOf(currentLtAU));
                 viewHolder.setCurrentLngAU(String.valueOf(currentLnAU));

          }
     }

and now everything works perfectly fine!