0

I am attempting to pull data from Firebase Database into a RecyclerView and properly order them. I am successfully getting the data into the recyclerview but the ordering is wrong.

What I am getting: Android Screenshot

Essentially it's ordering them:

  • Small

  • Enterprise

  • Large

  • Micro

  • Medium

My Firebase DB


It orders like this in the app MOST of the time, although one time it ordered correctly which leaves me to believe it is somewhat random depending on which task is finishing first.

I had originally looked up ordering of arraylist(How to sort ArrayList<Long> in Java in decreasing order?) and then ordering of firebase(https://firebase.google.com/docs/database/android/lists-of-data#sort_data) and wasn't sure if there is something else I'm missing?

How is the combination of the asynchronous onDataChange and the Callback decide which finishes first? It's not doing it in the order I have them in the code.


I would like them to be ordered by lowest price first, so:

  1. Micro
  2. Small
  3. Medium
  4. Large
  5. Enterprise

Here is my code:

RegisterSubscriptionActivity.java:

public class RegisterSubscriptionActivity extends Activity {

    //Firebase Database References
    DatabaseReference mDatabase;
    DatabaseReference mDatabaseMicro;
    DatabaseReference mDatabaseSmall;
    DatabaseReference mDatabaseMedium;
    DatabaseReference mDatabaseLarge;
    DatabaseReference mDatabaseEnterprise;
    DatabaseReference mListItemRef;

    ArrayList subscriptionInfo;

    //Subscription (String) values
    String name, number, price;


    //RECYCLERVIEW ITEMS
    private Context mContext;
    LinearLayout mLinearLayout;
    private RecyclerView mRecyclerView;
    private MyAdapterSubscription mAdapter = new MyAdapterSubscription(this);
    private RecyclerView.LayoutManager mLayoutManager;
    //ArrayList<LinearLayout> linearLayoutList = new ArrayList<LinearLayout>();

    ArrayList<Subscription> myListItems;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_register_subscription);

        myListItems = new ArrayList<Subscription>();

        //CALLBACK SO YOU CAN GET THE DATA (FROM) THE ASYNC CALL AND USE IT OUTSIDE OF THE CALL, OTHERWISE IT WILL SHOW AS NULL
        final DataSnapshotCallback callback = new DataSnapshotCallback() {
            @Override
            public void gotDataSnapshot(DataSnapshot snapshot) {
                Subscription subscription = new Subscription(snapshot);
                myListItems.add(subscription);
                mAdapter.updateDataSet(myListItems);
                Log.i("ARRAY LIST CONTENTS", myListItems.get(0).getName());
                Log.i("DATA","Name: " + subscription.getName() + " Price: " + subscription.getPrice() + " Number: " + subscription.getNumber());

            }
    };


        mDatabase = FirebaseDatabase.getInstance().getReference("Subscription");
        mDatabaseMicro = mDatabase.child("Micro");
        mDatabaseSmall = mDatabase.child("Small");
        mDatabaseMedium = mDatabase.child("Medium");
        mDatabaseLarge = mDatabase.child("Large");
        mDatabaseEnterprise = mDatabase.child("Enterprise");

        ValueEventListener eventListener = new ValueEventListener() {

            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {

                callback.gotDataSnapshot(dataSnapshot);  //CALLS THE CALLBACK AND SENDS THE DATASNAPSHOT TO IT

            }


            @Override
            public void onCancelled(DatabaseError databaseError) {
                Log.d("Cancelled",databaseError.toString());
            }
        };  //END of ValueEventListener


        mDatabaseMicro.addListenerForSingleValueEvent(eventListener);
        mDatabaseSmall.addListenerForSingleValueEvent(eventListener);
        mDatabaseMedium.addListenerForSingleValueEvent(eventListener);
        mDatabaseLarge.addListenerForSingleValueEvent(eventListener);
        mDatabaseEnterprise.addListenerForSingleValueEvent(eventListener);
        //Log.i("DATA ITEMS", "NAME: " + name + " / " + "NUMBER: " + number + " / " + "PRICE: " + price); //Will get Null because not in Callback
        //Log.i("LIST OF DATA: ", myListItems.toString()); //Same


        //RECYCLERVIEW STUFF
        mRecyclerView = (RecyclerView) findViewById(R.id.s_recycler_view);

        mContext = getApplicationContext(); // Get the application context

        // Define a layout for RecyclerView
        mLayoutManager = new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false);        
        mRecyclerView.setLayoutManager(mLayoutManager);

        // Set the adapter for RecyclerView
        mRecyclerView.setAdapter(mAdapter);


    } //END OF ONCREATE

    interface DataSnapshotCallback {
        void gotDataSnapshot(DataSnapshot snapshot);
    }

}

Subscription.java:

public class Subscription {

    String name, number;
    Long price;

    public Subscription(DataSnapshot dataSnapshot) {

        name = dataSnapshot.child("name").getValue(String.class);
        number = dataSnapshot.child("number").getValue(String.class);
        price = dataSnapshot.child("price").getValue(Long.class);
    }

    public String getName() {
        return name;
    }


    public String getNumber() {
        return number;
    }


    public Long getPrice() {
        return price;
    }


}

MyAdapterSubscription.java:

 class MyAdapterSubscription extends RecyclerView.Adapter<MyAdapterSubscription.ViewHolder> {
    private ArrayList<Subscription> mDataSet = new ArrayList<>();
    private Context mContext;

    MyAdapterSubscription(Context context){
        mContext = context;
    }

     static class ViewHolder extends RecyclerView.ViewHolder{

        TextView nameTV, numberTV, priceTV;
         ViewHolder(View v){
            super(v);
            nameTV = (TextView) v.findViewById(R.id.subNameTV);
            numberTV = (TextView) v.findViewById(R.id.subNumberTV);
            priceTV = (TextView) v.findViewById(R.id.subPriceTV);
        }
    }

    void updateDataSet(ArrayList<Subscription> myArrayList) {
        mDataSet = myArrayList;
        // TODO: 12/13/2017 Sort array list by price. Lowest to highest.
        //Collections.sort(mDataSet);
        // TODO: 12/14/2017 Let it be clickable and link to payment
        notifyDataSetChanged();
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
        // Create a new View
        View v = LayoutInflater.from(mContext).inflate(R.layout.subscription_row_layout,parent,false);
        return new ViewHolder(v);
    }

    //A ViewHolder object stores each of the component views inside the tag field of the Layout, so you can immediately access them without the need to look them up repeatedly.
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Subscription subscription = mDataSet.get(position);
        holder.nameTV.setText(subscription.getName());
        holder.numberTV.setText(subscription.getNumber());
        holder.priceTV.setText(String.format(mContext.getResources().getString(R.string.subscriptionAdapterPrice), subscription.getPrice()));
    }

    @Override
    public int getItemCount(){
        return mDataSet.size();
    }

}
ImTheNun
  • 167
  • 1
  • 10
  • you can use predicates just look at this link for hep http://guidogarcia.net/blog/2011/10/29/java-different-ways-filter-collection/ – Adeel Turk Dec 14 '17 at 07:49

2 Answers2

0

When Firebase loads data in the order first node -> last node. Since in your structure, the order was enterprise ->...-> small, so it loads the data that way. So given if you already 5 five fixed node, you may want to reorder your structure as small -> micro -> medium -> large -> enterprise. You can also use several Sort Data Method that firebase provided.
In your case, since you only have 5 nodes, you probably can just do a Collections.sort(arraylist, Collections.reverseOrder()) if you're reading them into an ArrayList

Kim G Pham
  • 145
  • 6
  • I was thinking in the direction of using Collections.sort. I did the following: Collections.sort(mDataSet, new Comparator() { @Override public int compare(Subscription p1, Subscription p2) { return p1.getPrice().intValue()- p2.getPrice().intValue(); // Ascending //Compares its two arguments for order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. } }); – ImTheNun Dec 14 '17 at 16:08
  • Yeah, you can use Collections.sort, but since you're only comparing the price, you can user Firebase's orderByChild() method like this ref.orderByChild("price").on("child_added", function(snapshot) { //do sth to snapshot }); – Kim G Pham Dec 14 '17 at 20:43
-1

It is simple

Since you are using firebase datastore.

You can sort the values by these 3 methods in it. orderByChild()
orderByKey() orderByValue()

Shadab K
  • 1,677
  • 1
  • 16
  • 25