2

Hi David and the Firebase team, I am trying to order the tabs in a FragmentStatePagerAdapter by most recent "scout." It seems really hard to insert an item into a FragmentStatePagerAdapter and get it to refresh properly. So instead of doing that, it would make my life way easier if Firebase just gave me the keys in descending order instead of ascending (most recent first). If this is not possible, consider this a feature request for orderByKeyDescending() :) Any help would be appreciated! Thanks!

Here is my desired listener BTW:

scoutRef.orderByKeyDescending().addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                mSectionsPagerAdapter.mKeyPosition.add(dataSnapshot.getKey());
                mSectionsPagerAdapter.notifyDataSetChanged();
            }

            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String s) {

            }

            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {

            }

            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String s) {

            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                FirebaseCrash.report(databaseError.toException());
            }
        });
SUPERCILEX
  • 3,929
  • 4
  • 32
  • 61

6 Answers6

1

Firebase Query is used for sorting.

Sort by key

Sort by child

Sort by value

Sort by priority

UPDATE

It is not possible to sort the values in descending order directly from Firebase.

However, you can create a custom layout and create the view in reverse order.

LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setReverseLayout(true);
layoutManager.setStackFromEnd(true);

source(They have used a RecyclerView)

Community
  • 1
  • 1
Geet Choubey
  • 1,069
  • 7
  • 23
0

Add every child at top of the list instead of adding them to end.

scoutRef.orderByKeyDescending().addChildEventListener(new ChildEventListener() {

        @Override
        public void onChildAdded(DataSnapshot dataSnapshot, String s) {
            mSectionsPagerAdapter.mKeyPosition.add(0, dataSnapshot.getKey());
            mSectionsPagerAdapter.notifyDataSetChanged();
        }

        ...
    });
Muzaffer
  • 1,457
  • 1
  • 13
  • 22
  • I tried that, but it doesn't work because of how the FragmentStatePagerAdapter uses notifyDataSetChanged(). For some reason, it won't refresh the pages already in memory. This means that all pages will have identical contents: 1st page loads content with oldest post, 2nd page also loads content with oldest post because that first key was moved to position 2 in the list, and so on. – SUPERCILEX Jul 28 '16 at 15:05
  • 1
    Changing firebase order is impossible. So you have to fix pager adapter. This link should help you -> http://stackoverflow.com/questions/7263291/viewpager-pageradapter-not-updating-the-view – Muzaffer Jul 29 '16 at 08:39
0

I found a somewhat reasonable way to do it, but it doesn't work properly when a new item is added to the database and the ViewPager is still active (same as the other problem, it doesn't refresh and you get duplicates. See my comment: How to use orderByKey() in descending order instead of ascending #Askfirebase).

Here my somewhat broken solution:

final List<String> tmpKeyList = new ArrayList<>();
scoutReference.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                tmpKeyList.clear();

                for (DataSnapshot child : dataSnapshot.getChildren()) {
                    if (tmpKeyList.size() < dataSnapshot.getChildrenCount() - 1) {
                        tmpKeyList.add(0, child.getKey());
                    } else {
                        tmpKeyList.add(0, child.getKey());
                        mSectionsPagerAdapter.setKeyPositionList(tmpKeyList);
                    }
                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                FirebaseCrash.report(databaseError.toException());
            }
        });

And my FragmentStatePagerAdapter:

public class SectionsPagerAdapter extends FragmentStatePagerAdapter {

        List<String> mKeyPosition = new ArrayList<>();

        public SectionsPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            // getItem is called to instantiate the fragment for the given page.
            // Return a PlaceholderFragment (defined as a static inner class below).
            return PlaceholderFragment.newInstance(mKeyPosition.get(position));
        }

        @Override
        public int getCount() {
            return mKeyPosition.size();
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return "SCOUT " + (getCount() - position);
        }

        public void setKeyPositionList(List<String> list) {
            mKeyPosition = new ArrayList<>(list);
            notifyDataSetChanged();
        }
    }
Community
  • 1
  • 1
SUPERCILEX
  • 3,929
  • 4
  • 32
  • 61
0

Huge thanks to wisemann!!!

TL;DR You can't get data in descending order with Firebase, period. You have to do it on the client side.

The solution on the client side for me was to to return POSITION_NONE (-2) in getItemPosition. If you want to be more performant, you can read more about tags here: ViewPager PagerAdapter not updating the View.

Here is the full adapter:

public class SectionsPagerAdapter extends FragmentStatePagerAdapter {

    List<String> mKeyPosition = new ArrayList<>();

    public SectionsPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

    @Override
    public Fragment getItem(int position) {
        // getItem is called to instantiate the fragment for the given page.
        // Return a PlaceholderFragment (defined as a static inner class below).
        return PlaceholderFragment.newInstance(mKeyPosition.get(position));
    }

    @Override
    public int getCount() {
        return mKeyPosition.size();
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return "SCOUT " + (getCount() - position);
    }

    public void add(String key) {
        mKeyPosition.add(0, key);
        notifyDataSetChanged();
    }
}

And the Firebase listener:

public void updateScouts(final CurrentScoutActivity.SectionsPagerAdapter mSectionsPagerAdapter) {
    scoutReference.addChildEventListener(new ChildEventListener() {
        @Override
        public void onChildAdded(DataSnapshot dataSnapshot, String s) {
            mSectionsPagerAdapter.add(dataSnapshot.getKey());
        }

        @Override
        public void onChildChanged(DataSnapshot dataSnapshot, String s) {
           //...
        }

        @Override
        public void onChildRemoved(DataSnapshot dataSnapshot) {
           //...
        }

        @Override
        public void onChildMoved(DataSnapshot dataSnapshot, String s) {
           //...
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            FirebaseCrash.report(databaseError.toException());
        }
    });
}
Community
  • 1
  • 1
SUPERCILEX
  • 3,929
  • 4
  • 32
  • 61
0

I couldn't get my data from firebase in descending order instead I reversed my recycler view layout! hope it helps someone.

//reversing recycler view to get recent data at the top
    LinearLayoutManager mLayoutManager = new LinearLayoutManager(this);
    mLayoutManager.setReverseLayout(true);
    mLayoutManager.setStackFromEnd(true);
    // Set the layout manager to your recyclerview
    recyclerView.setLayoutManager(mLayoutManager);
Timchang Wuyep
  • 629
  • 7
  • 10
0

Late answer but simple one

scoutRef.orderByKey().addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                mSectionsPagerAdapter.insert(dataSnapshot.getKey(), 0);
                mSectionsPagerAdapter.notifyDataSetChanged();
            }
Amr Salah
  • 85
  • 9