I have an Android Fragment (in Java) that displays recyclerview. Now I would like to read the data for the items in the recyclerview from a firebase database. They should be stored into an array list orderList
. For this purpose, I would like to use LiveData and a ViewModel because I read several times that this is the recommended way of implementing it. Further, I would like the Fragment to update the recyclerview automatically whenever new data is stored in the firebase database.
I tried to follow the steps that are described in the offical Firebase Blog (https://firebase.googleblog.com/2017/12/using-android-architecture-components.html) but unfortunately the result is always an empty list. No elements are being displayed altough there are some relevant entries in the database that should be returned and displayed. The implementation of the recyclerview itself is correct (I checked that by manually adding items into the recylcerview).
Here is my Fragment that holds the recyclerview:
public class FR_Orders extends Fragment {
private FragmentOrdersBinding binding;
//Define variables for the RecyclerView
private RecyclerView recyclerView_Order;
private RV_Adapter_Orders adapter_Order;
private RecyclerView.LayoutManager layoutManager_Order;
private ArrayList<RV_Item_Order> orderList;
public FR_Orders() {
// Required empty public constructor
}
public static FR_Orders newInstance(String param1, String param2) {
FR_Orders fragment = new FR_Orders();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
orderList = new ArrayList<RV_Item_Order>();
// Obtain a new or prior instance of ViewModel_FR_Orders from the ViewModelProviders utility class.
ViewModel_FR_Orders viewModel = new ViewModelProvider(this).get(ViewModel_FR_Orders.class);
LiveData<DataSnapshot> liveData = viewModel.getDataSnapshotLiveData();
liveData.observe(this, new Observer<DataSnapshot>() {
@Override
public void onChanged(@Nullable DataSnapshot dataSnapshot) {
for(DataSnapshot ds: dataSnapshot.getChildren()) {
if (dataSnapshot != null) {
String drinkName = "";
String drinkSize = "";
String orderDate = "";
String orderStatus = "";
int orderDateInMilliseconds = 0;
int orderID = 0;
int quantity = 0;
int tableNumber = 0;
// update the UI here with values in the snapshot
if( dataSnapshot.child("drinkName").getValue(String.class)!=null) {
drinkName = dataSnapshot.child("drinkName").getValue(String.class);
}
if(dataSnapshot.child("drinkSize").getValue(String.class)!=null) {
drinkSize = dataSnapshot.child("drinkSize").getValue(String.class);
}
if(dataSnapshot.child("orderDate").getValue(String.class)!=null) {
orderDate = dataSnapshot.child("orderDate").getValue(String.class);
}
if(dataSnapshot.child("orderStatus").getValue(String.class)!=null) {
orderStatus = dataSnapshot.child("orderStatus").getValue(String.class);
}
if(dataSnapshot.child("orderDateInMilliseconds").getValue(Integer.class)!=null) {
orderDateInMilliseconds = dataSnapshot.child("orderDateInMilliseconds").getValue(Integer.class);
}
if(dataSnapshot.child("quantity").getValue(Integer.class)!=null) {
quantity = dataSnapshot.child("quantity").getValue(Integer.class);
}
if(dataSnapshot.child("orderID").getValue(Integer.class)!=null) {
orderID = dataSnapshot.child("orderID").getValue(Integer.class);
}
if(dataSnapshot.child("tableNumber").getValue(Integer.class)!=null) {
tableNumber = dataSnapshot.child("tableNumber").getValue(Integer.class);
}
orderList.add(new RV_Item_Order(drinkName, drinkSize, orderDateInMilliseconds, orderDate, tableNumber, orderStatus, quantity, orderID));
;
}
}
}
});
}// end onCreate
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentOrdersBinding.inflate(inflater, container, false);
buildRecyclerView();
return binding.getRoot();
}
public void buildRecyclerView() {
recyclerView_Order = binding.rvDrinksToBeDisplayed;
recyclerView_Order.setHasFixedSize(true);
layoutManager_Order = new LinearLayoutManager(this.getContext());
adapter_Order = new RV_Adapter_Orders(orderList);
recyclerView_Order.setLayoutManager(layoutManager_Order);
recyclerView_Order.setAdapter(adapter_Order);
adapter_Order.setOnItemClickListener(new RV_Adapter_Orders.OnItemClickListener() {
/*
Define what happens when clicking on an item in the RecyclerView
*/
@Override
public void onItemClick(int position) {
}
});
}//end build recyclerView
}//End class
Here is the LiveData class
public class LiveData_FirebaseOrder extends LiveData<DataSnapshot> {
private static final String LOG_TAG = "LiveData_FirebaseOrder";
private final Query query;
private final MyValueEventListener listener = new MyValueEventListener();
public LiveData_FirebaseOrder(Query query) {
this.query = query;
}
public LiveData_FirebaseOrder(DatabaseReference ref) {
this.query = ref;
}
@Override
protected void onActive() {
Log.d(LOG_TAG, "onActive");
query.addValueEventListener(listener);
}
@Override
protected void onInactive() {
Log.d(LOG_TAG, "onInactive");
query.removeEventListener(listener);
}
private class MyValueEventListener implements ValueEventListener {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
setValue(dataSnapshot);
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.e(LOG_TAG, "Can't listen to query " + query, databaseError.toException());
}
}
}
Here is the ViewModel class (the full name of the database is not given because of privacy issues).
public class ViewModel_FR_Orders extends ViewModel {
private static final DatabaseReference ORDERS_REF =
FirebaseDatabase.getInstance("https://....firebasedatabase.app").getReference("/Orders");
private final LiveData_FirebaseOrder liveData = new LiveData_FirebaseOrder(ORDERS_REF);
@NonNull
public LiveData<DataSnapshot> getDataSnapshotLiveData() {
return liveData;
}
}
And here is a screenshot of the Firebase Database that shows that there are some entries in the node Orders
that should be returned
Does anyone have an idea what I am making wrong? I tried to stick exactly to the instructions of the offical Firebase Blog.
Update: I found out that the query itself returns the correct datasnapshots but the recyclerview is not built and updated.