1

I am in the sitatuion where I have to get firebase database ref from Callback. It is working pretty fine since I am able to read/write to the database.

public void readData(final MyCallback myCallback) {
    mCurrentUserDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            String university = dataSnapshot.child("university").getValue().toString();
            String groupid = dataSnapshot.child("groupid").getValue().toString();
            //Having acquired university and group ID, now we can get reference to group members list
            mMembersDatabase = FirebaseDatabase.getInstance().getReference().child("Universities").child(university).child("Groups").child(groupid).child("Members");
            myCallback.onCallback(mMembersDatabase);
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {}
    });
}

Then, in onStart() method of my activity, I am creating my FirebaseRecyclerAdapter. Since it requires 4 parameters:

  • model class
  • resource layout file
  • view holder class
  • firebase database reference

I need to pass the firebase database ref i am getting from the my Callback as a parameter. I tried the following in onStart(), but it is not working.

    readData(new MyCallback() {
        @Override
        public void onCallback(DatabaseReference databaseReference) {


           FirebaseRecyclerAdapter<Groupmates, GroupmatesViewHolder> firebaseRecyclerAdapter =
            new FirebaseRecyclerAdapter <Groupmates, GroupmatesViewHolder> (
                    Groupmates.class,
                    R.layout.users_single_layout,
                    GroupmatesViewHolder.class,
                    databaseReference
            ) {
                @Override
                protected  void populateViewHolder(final GroupmatesViewHolder groupmatesViewHolder, final Groupmates groupmates, final int position) {
                                 //SOME LOGIC HERE
                }
            };
    //Finally, setting the ready adapter to the RecyclerView
    mGroupmatesList.setAdapter(firebaseRecyclerAdapter);

        }
    });

I am receiving null object reference exception if I try to create FirebaseRecyclerAdapter outside of my Callback.

I can't really get my way out of it. Any suggestions would be helpful.

Azizjon Kholmatov
  • 1,136
  • 1
  • 13
  • 26

2 Answers2

1

If I were you, I'll move the declaration of FirebaseRecyclerAdapter inside onDataChange() so you can easily pass the mMembersDatabase to the constructor and then change the callback like this:

public interface MyCallback {
    void onCallback(FirebaseRecyclerAdapter firebaseRecyclerAdapter);
}

The use the following code:

public void readData(final MyCallback myCallback) {
    mCurrentUserDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        String university = dataSnapshot.child("university").getValue().toString();
        String groupid = dataSnapshot.child("groupid").getValue().toString();
        //Having acquired university and group ID, now we can get reference to group members list
        mMembersDatabase = FirebaseDatabase.getInstance().getReference().child("Universities").child(university).child("Groups").child(groupid).child("Members");

        FirebaseRecyclerAdapter<Groupmates, GroupmatesViewHolder> firebaseRecyclerAdapter =
        new FirebaseRecyclerAdapter <Groupmates, GroupmatesViewHolder> (
            Groupmates.class,
            R.layout.users_single_layout,
            GroupmatesViewHolder.class,
            mMembersDatabase
        ) {
             @Override
             protected  void populateViewHolder(final GroupmatesViewHolder groupmatesViewHolder, final Groupmates groupmates, final int position) {
                 //SOME LOGIC HERE
             }
        };
        myCallback.onCallback(firebaseRecyclerAdapter);
    }

    @Override
        public void onCancelled(DatabaseError databaseError) {}
    });
}

And then in your onStart(), use this:

readData(new MyCallback() {
    @Override
    public void onCallback(FirebaseRecyclerAdapter firebaseRecyclerAdapter) {
        mGroupmatesList.setAdapter(firebaseRecyclerAdapter);
    }
});
Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • It is still not working even though I did as you suggested. My fragment did not get populated with group members. I received the following in RUN section: `E/RecyclerView: No adapter attached; skipping layout` – Azizjon Kholmatov Jan 09 '18 at 19:59
  • This is not happening because of the callback. That error is showing when you are switching between tabs. Assuming you have a viewPager and let's say 3 tabs, please use the following code: `viewPager.setOffscreenPageLimit(2);` – Alex Mamo Jan 09 '18 at 20:02
  • Actually, group members list in my `TabLayout` is the first tab. So, I am not switching (there is no need) between tabs. When my activity loads it is just showing an empty screen. No data at all. – Azizjon Kholmatov Jan 09 '18 at 20:08
  • Check [here](https://www.google.ro/search?q=E%2FRecyclerView%3A+No+adapter+attached%3B+skipping+layout) the reasons for that error. It's not about the callback. – Alex Mamo Jan 09 '18 at 20:10
  • Unfortunately, It did not help. I spent a lot of time on debugging. I have tested my `FirebaseRecyclerAdapter` with a dummy database reference and same random values. Suprisingly, it is working. So, i am coming to conclusions that there is still problem with `mMembersDatabase` which is coming from `Callback`. – Azizjon Kholmatov Jan 10 '18 at 04:46
  • `mMembersDatabase` isn't coming from Callback anymore, `firebaseRecyclerAdapter` is. The logic behind id the same as for getting `mMembersDatabase` from the callback. – Alex Mamo Jan 10 '18 at 11:12
0

After spending a day of researching, I finally found the solution. I would like to thank @Alex Mamo for the correct guidence and direction he provided. However, it was NOT enough to solve the problem. That's why I am answering my own question.

After getting the FirebaseDatabaseReference from Callback, my recycler view was still not getting populated. Thus, simply getting database ref via Callback might not be enough to see the final result. With the help of answer to this question and combination of suggestions and guidence provided by @Alex Mamo, I was able to solve the issue.

So answer is simple: I just called my Callback inside onCreateView(). Then created my FirebaseReyclerAdapter inside the Callback Method. When the adapter is being created, before setting the adapter to RecyclerView there was a need to add AdapterDataObsever to the adapter.

firebaseRecyclerAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
                @Override
                public void onItemRangeInserted(int positionStart, int itemCount) {
                    super.onItemRangeInserted(positionStart, itemCount);
                    int groupmate_count = firebaseRecyclerAdapter.getItemCount();
                    int lastVisiblePosition = mLinearLayoutManager.findLastVisibleItemPosition();
                    // If the recycler view is initially being loaded or the
                    // user is at the bottom of the list, scroll to the bottom
                    // of the list to show the newly added message.
                    if (lastVisiblePosition == -1 ||  (positionStart >= (groupmate_count - 1) && lastVisiblePosition == (positionStart - 1))) {
                        mGroupmatesList.scrollToPosition(positionStart);
                    }
                }
            });

This is working pretty nice. Hope it helps others too.

Azizjon Kholmatov
  • 1,136
  • 1
  • 13
  • 26