0

I am trying to pass a String (userID) from the onBindViewHolder to my ViewHolder class. The reason behind this is that I need the position to allocate the correct postID. This postID is used in the ViewHolder as a reference to set up a Firebase valueEventListener. However, when running the app I get a NullPointerException on the postID. Is this due to synchronization? Is the valueEventListener called before postID is set?

public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    final PostViewHolder holder1 = (PostViewHolder) holder;
    holder1.postID = getPostId(position)

    //...
}

//...

public class PostViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{

    private DatabaseReference mNoOfLikesRef;
    public String postID;
    //...

    public PostViewHolder(View itemView, postClickListener listener){
        super(itemView);

        //This line causes the NullPointerException on postID
        mNoOfLikesRef = FirebaseDatabase.getInstance().getReference().child("likes").child(postID);
        ValueEventListener valueEventListener = new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                //...
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
            }

        };
        mNoOfLikesRef.addListenerForSingleValueEvent(valueEventListener);

    }
P. Wulf
  • 18
  • 7
  • Post your get postId(position) source code – Fazal Hussain Apr 05 '18 at 14:56
  • Thanks for your comments. @ADM, yes the postID is different for each item. The reason I did not set it in `onBindViewHolder` is that I'm trying to prevent a call to the Firebase database on each view binding. I understood that it needs to be set in `onCreateViewHolder`, but again it is dependent on the position which I do not have at that stage. – P. Wulf Apr 05 '18 at 15:01
  • A listener for each list item seems pretty hectic to me . Whats the need for it ? If you have 100 list items then there will 100 listeners. IMHO you should register a single listener on root and use [DiffUtil](https://developer.android.com/reference/android/support/v7/util/DiffUtil.html) to notify changes to adapter . If this cover your need ! If not then you have to manage listeners when a row view is recycled during scroll. – ADM Apr 05 '18 at 15:06
  • @ADM, what I actually have is the following: I use Firestore to save messages, timestamps etc. and pass these as a List to the Adapter. Each of these posts can be liked or disliked and I have a like/dislike counter on Firebase RTDB (many operations and to use Transactions). Using DiffUtil at root will be triggered for each like/dislike on any post :(. – P. Wulf Apr 05 '18 at 15:16
  • Ok . What if new post added ? How are adding new post to adapter? Or there will be no new post in same root? – ADM Apr 05 '18 at 15:37
  • More information on my code is [here](https://stackoverflow.com/questions/49561360/using-data-from-firestore-and-firebase-rtdb-in-single-recyclerview?noredirect=1&lq=1) if anyone is interested. So far, I have not found a "proper" solution for the like/dislike functionality with firebase, it generated huge amounts of protocol overhead (as checked with [Stackdriver](https://cloud.google.com/stackdriver/)), due to the frequent requests. – P. Wulf Apr 06 '18 at 08:13

2 Answers2

0

Yes, you're calling it in PostViewHolder's constructor which is invoked by onCreateViewHolder method before onBindViewHolder.

Alexander Perfilyev
  • 6,739
  • 2
  • 17
  • 30
0

create a method inside ViewHolder class and call it from onBindViewHolder

public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    final PostViewHolder holder1 = (PostViewHolder) holder;
    holder1.doYourTask(getPostId(position));

    //...
}

public class PostViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{

//...

public void doYourTask(String postID){
    DatabaseReference mNoOfLikesRef = FirebaseDatabase.getInstance().getReference().child("likes").child(postID);
    ValueEventListener valueEventListener = new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            //...
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
        }

    };
    mNoOfLikesRef.addListenerForSingleValueEvent(valueEventListener);
}

}

  • This is what is was trying to say. I tried to write it first but Shalauddin Ahamad Shuza was faster. If you get a `NullPointerException` isn't because you are passing it wrong, it means that `getPostId(position)` does not return the right value. – Alex Mamo Apr 05 '18 at 15:07
  • When using this approach the `SingleValueEventListener` is triggered every time a new View is bound, right? I somehow wanted to prevent that by calling it in the ViewHolder itself. Is there any way of doing that? – P. Wulf Apr 05 '18 at 15:07