kevinivan05
kevinivan05

Reputation: 364

Firebase+RecyclerView: RecyclerView not displaying on application start

I'm using the Android Studio provided class for a tabbed activity that uses Action Bar Tabs with ViewPager. Inside this activity, I'm trying to initialize a RecyclerView with data from a Firebase database.

Problem: On the app's first run, the RecyclerView is empty as shown below.

App's first run.

If I close and reopen the application from within the emulator, my RecyclerView gets populated as it should, as shown below.

After closing and reopening app.

Any ideas as to why this might be happening? I have a theory but I haven't been able to find a solution. After trying to read the FragmentPagerAdapter page, I got the impression that the fragments must be static (I don't know what the implications of this might be, so if anyone can shed some light on this it would be appreciated). On the app's first run, it initializes the RecyclerView. It then adds the data from the Firebase database but since the RecyclerView has already been initialized it is empty and is never properly updated. I tried calling the notify... methods to no avail.

StudentFragment's onCreateView method:

private View view;
private Context c;
private RecyclerView mRecyclerView;
private LinearLayoutManager manager;
private Firebase mFirebaseRef;
private FirebaseRecyclerAdapter<Student, ViewHolder> firebaseRecyclerAdapter;


public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    view = inflater.inflate(R.layout.fragment_students, container, false);
    mFirebaseRef = new Firebase("<your Firebase link here>");
    c = getContext();

    //Initializes Recycler View and Layout Manager.
    mRecyclerView = (RecyclerView) view.findViewById(R.id.studentRecyclerView);
    manager = new LinearLayoutManager(c);
    mRecyclerView.setHasFixedSize(true);
    firebaseRecyclerAdapter =
            new FirebaseRecyclerAdapter<Student, ViewHolder>(
                    Student.class,
                    R.layout.single_student_recycler,
                    ViewHolder.class,
                    mFirebaseRef
            ) {
                @Override
                protected void populateViewHolder(ViewHolder viewHolder, Student student, int i) {
                    viewHolder.vFirst.setText(student.getFirst());
                    viewHolder.vLast.setText(student.getLast());
                    viewHolder.vDue.setText(Double.toString(student.getCurrentlyDue()));
                    viewHolder.vRadio.setButtonTintList(ColorStateList.valueOf(Color.parseColor(student.getColor())));
                    Log.d(TAG, "populateViewHolder called");
                }
            };

    mRecyclerView.setAdapter(firebaseRecyclerAdapter);
    mRecyclerView.setLayoutManager(manager);


    return view;
}

ViewHolder:

public static class ViewHolder extends RecyclerView.ViewHolder {
    public final TextView vFirst;
    public final TextView vLast;
    public final TextView vDue;
    public final RadioButton vRadio;

    public ViewHolder(View itemView) {
        super(itemView);
        vFirst = (TextView) itemView.findViewById(R.id.recycler_main_text);
        vLast = (TextView) itemView.findViewById(R.id.recycler_sub_text);
        vRadio = (RadioButton) itemView.findViewById(R.id.recycler_radio_button);
        vDue = (TextView) itemView.findViewById(R.id.recycler_due_text);
}

Homescreen's onCreate method:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_homescreen);

    // Create the adapter that will return a fragment for each of the three
    // primary sections of the activity.
    mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

    // Set up the ViewPager with the sections adapter.
    mViewPager = (ViewPager) findViewById(R.id.container);
    mViewPager.setAdapter(mSectionsPagerAdapter);

    TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
    tabLayout.setupWithViewPager(mViewPager);

}

Firebase context is set on another application that starts as soon as the Homescreen activity starts. Any help will be appreciated.

Edit: I was digging through the FirebaseUI GitHub page, which is where the problem most likely lies, and found another user with the exact same problem. It seems that onBindViewHolder isn't called after notifyItemInserted in the FirebaseRecyclerAdapter class. Now to fix it...

Upvotes: 3

Views: 5208

Answers (4)

CodeSlave
CodeSlave

Reputation: 457

In my case this was caused by mRecyclerView.setHasFixedSize(true); If you comment out this line of code the list loads properly. I got my solution from this discussion: https://github.com/firebase/FirebaseUI-Android/issues/204

Upvotes: 4

IslemKms
IslemKms

Reputation: 11

i had the same issue, check the documentation:

https://codelabs.developers.google.com/codelabs/firebase-android/#6

fixed it by adding a data observer:

mFirebaseAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
   @Override
   public void onItemRangeInserted(int positionStart, int itemCount) {
   super.onItemRangeInserted(positionStart, itemCount);
   int friendlyMessageCount = mFirebaseAdapter.getItemCount();
   int lastVisiblePosition =
          mLinearLayoutManager.findLastCompletelyVisibleItemPosition();
   // 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 >= (friendlyMessageCount - 1) &&
                   lastVisiblePosition == (positionStart - 1))) {
       mMessageRecyclerView.scrollToPosition(positionStart);
      }
   }
});

Upvotes: 0

Shubham Sardar
Shubham Sardar

Reputation: 101

 firebaseRecyclerAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            super.onItemRangeInserted(positionStart, itemCount);
            int friendlyMessageCount = firebaseRecyclerAdapter.getItemCount();
            int lastVisiblePosition =
                    linearLayoutManager.findLastCompletelyVisibleItemPosition();
            // 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 >= (friendlyMessageCount - 1) &&
                            lastVisiblePosition == (positionStart - 1))) {
                linearLayoutManager.scrollToPosition(positionStart);
            }
        }
    });
    recyclerListIdeas.setAdapter(firebaseRecyclerAdapter);

** Just add Recyclerview.AdapterDataObserver() . worked for me ! hope it helps :)**

Upvotes: 0

Let me try, as you say on the question title,

RecyclerView not displaying on application start

so, the

Initializes Recycler View and Layout Manager.

should be declared on the onStart

@Override
   public void onStart() {
       super.onStart();
       mFirebaseRef = new Firebase("<your Firebase link here>");
       firebaseRecyclerAdapter = ...
       //and so on

Hope it helps!

Upvotes: 0

Related Questions