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
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:
- Micro
- Small
- Medium
- Large
- 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();
}
}