10

I currently have a FirebaseListAdapter that populates a ListView with the last 5 items:

@Override
public void onViewCreated(View view, Bundle savedInstanceState){

    FirebaseListAdapter<HashMap> adapter = new FirebaseListAdapter<HashMap>(getParentFragment().getActivity(),HashMap.class,R.layout.list_item,firebase.limitToLast(5)) {
        @Override
        protected void populateView(View view, HashMap hashMap, int i) {
            String title = hashMap.get("title").toString();
            String body = hashMap.get("body").toString();

            TextView title_txt = (TextView)view.findViewById(R.id.title);
            TextView body_txt = (TextView)view.findViewById(R.id.body);

            title_txt.setText(title);
            body_txt.setText(body);
        }
    };

    listView.setAdapter(adapter);
}

The problem I have is that when a new item is pushed to Firebase, it is added to the bottom of the list. I want the newest items at the top of the list.

Is it possible to achieve this?

Any help is greatly appreciated, thanks!

Reaz Murshed
  • 23,691
  • 13
  • 78
  • 98
Alex Boullé
  • 431
  • 5
  • 17
  • Why would you bother to use Firebase adapter in the first place? I just had a look at Firebase Adapter and its just a simple adapter that extends from BaseAdapter. I highly recommend you to create your own adapter if you need to customize things. – abeikverdi May 23 '16 at 16:53
  • Well, I am very new to Firebase and also not overly experienced in Java for android development. I saw that the FirebaseListAdapter was quick and easy to implement, so initially I decided it would be a good idea to use that. – Alex Boullé May 23 '16 at 17:08
  • 2
    @abeikverdi the adapters in FirebaseUI hide quite some complexity behind fairly little code. Based on what experience do you recommend writing your own? – Frank van Puffelen May 23 '16 at 19:22
  • 1
    @AlexBoullé here's a question about reversing the `FirebaseRecyclerAdapter`: http://stackoverflow.com/questions/33830387/how-reverse-the-data-fetched-with-firebaseui-android. For `FirebaseListAdapter` see https://github.com/firebase/FirebaseUI-Android/issues/90 – Frank van Puffelen May 23 '16 at 19:25
  • @FrankvanPuffelen do I need to add more than setStackFromBottom(true) because all this does is makes the listview start from the bottom, not the top. What I need is it to add new items to the top of the listview, and be able to scroll down to older items like you would in a regular listview. Thanks. – Alex Boullé May 23 '16 at 19:34
  • Are you using `RecyclerView`? – Reaz Murshed May 23 '16 at 19:44
  • @ReazMurshed No, I am currently using a ListView – Alex Boullé May 23 '16 at 19:50
  • @FrankvanPuffelen OP needs a simple reversed list. Android provides recycleview and it does pretty much all the complex caching and loading stuff efficiently. Why would would you want to use Firebase adapter that extends old BaseAdapter? That really ties your hands. – abeikverdi May 24 '16 at 03:26
  • OP needs an inverted list that comes from the Firebase Database, which synchronizes data changes in realtime. This leads to numerous fun edge cases, which FirebaseUI handles. Have a look at the code of the [FirebaseListAdapter](https://github.com/firebase/FirebaseUI-Android/blob/master/database/src/main/java/com/firebase/ui/database/FirebaseListAdapter.java) and its underlying [FirebaseArray](https://github.com/firebase/FirebaseUI-Android/blob/master/database/src/main/java/com/firebase/ui/database/FirebaseArray.java). Then try to write one from scratch: it may be small, but it's not simple :-) – Frank van Puffelen May 24 '16 at 04:10

2 Answers2

17

This is not the exact solution of your problem of getting the data from firebase in a reverse order, but anyway, we've other work arounds.

The first work around is mentioned in a comment of using a custom adapter for your list.

To achieve the behaviour you need to get the firebase data in a list and then you've to reverse it yourself before passing it to an adapter. Simple!

The second work around is easy as pie and I think if you're using RecyclerView it could do the trick for you and I see it as the simplest way you can do the job.

Here's I'm modifying some of my code with RecyclerView

// Declare the RecyclerView and the LinearLayoutManager first
private RecyclerView listView;
private LinearLayoutManager mLayoutManager;

...

@Override
public void onViewCreated(View view, Bundle savedInstanceState){

    // Use FirebaseRecyclerAdapter here

    // Here you modify your LinearLayoutManager
    mLayoutManager = new LinearLayoutManager(MainActivity.this);
    mLayoutManager.setReverseLayout(true);
    mLayoutManager.setStackFromEnd(true);

    // Now set the layout manager and the adapter to the RecyclerView
    listView.setLayoutManager(mLayoutManager);
    listView.setAdapter(adapter);
}

By setting mLayoutManager.setReverseLayout(true); - you're reversing your layout and mLayoutManager.setStackFromEnd(true); positions the view to the top of your list.

Migrating to RecyclerView is simple. Your layout will be something like this

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/my_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>

And in your build.gradle

dependencies {
    compile 'com.android.support:recyclerview-v7:23.4.0'
}

You need to have FirebaseRecyclerAdapter can be found here in FirebaseUI library.

Note: Do not use RecyclerView.LayoutManager as the setReverseLayout and setStackFromEnd functions won't be found in RecyclerView.LayoutManager. Use LinearLayoutManager as stated.

Update

Here's how you can handle the click events of your items in the list.

You had to declare a ViewHolder to implement the RecyclerView right? Just add another function inside your ViewHolder class like the example below and call this function after the setText functions you've got there.

public static class MyViewHolder extends RecyclerView.ViewHolder {
    View mView;

    public MyViewHolder(View itemView) {
        super(itemView);
        mView = itemView;
    }

    public void setClickEvent() {
        // Set the onClickListener on mView
        // mView.setOnClickListener(new OnClickListener)...
    }
}
Reaz Murshed
  • 23,691
  • 13
  • 78
  • 98
  • 1
    I'm having some issues with the RecyclerView. I'm guessing where you have used my original code, the listView is the RecyclerView? When I do setAdapter(adapter) on the recyclerView, it does not work: set adapter (android.support.v7.widget.recyclerview.adapter) cannot be applied to (com.firebase.ui..FirebaseListAdapter) – Alex Boullé May 23 '16 at 20:18
  • Yes your `listView` is `RecyclerView`, you guessed it right. And sorry I put another little mistake. Please see this answer from @FrankVanPuffelen http://stackoverflow.com/a/31122788/3145960 to see how to use `FirebaseRecyclerAdapter` to work with `RecyclerView`. I'm editing the answer. – Reaz Murshed May 23 '16 at 20:24
  • 1
    This seems to be working, as in, it adds the newest to the top. I am still a bit stuck on how to detect click events on the items in the RecyclerVIew. Would you be able to explain briefly how to detect click events? Basically, I need to open a new fragment when one of the items is clicked. I had it working with ListView. Thanks for the help. – Alex Boullé May 23 '16 at 20:49
  • Updated the answer. Please have a look. – Reaz Murshed May 23 '16 at 21:13
6

Since you're already extending FirebaseListAdapter to implement populateView, you can go ahead and override getItem as well to invert the item lookup:

@Override
public HashMap getItem(int pos) {
    return super.getItem(getCount() - 1 - pos);
}

If you're not using RecyclerView this is a simple way to reverse the data without extending any more classes than necessary. Obviously this will reverse any AdapterView subclass backed by this adapter, if you choose to reuse it.

Travis Christian
  • 2,412
  • 2
  • 24
  • 41