This is part of our Udemy premium course: Android Firebase MVVM Jetpack – Many Offline First CRUD Apps. In the course we are covering step by step how to create full android applications based on Firebase Realtime Database and Android Jetpack.
This tutorial will cover the first app we create in that course. The app is an offline-first CRUD app with Search and Pagination capability. In the app the user can add a scientist with his details to the database, fetch them, update them, delete them. The user can also search against already existing Scientists. The data when being read is paginated, making the app efficient. Pagination is taking place at the Firebase level.
The app has several screens/pages:
No.
Page/Screen
Type
Role
1.
Splash Screen
Activity
Use it to display your brand
2.
Dashboard Screen
Activity
Use it as the center or your app .
3.
CRUD Screen
Activity
Used for posting new data, updating and deleting data
4.
Listing Sceen
Activity
Used for hosting our Fragments
5.
LatestFragment
Fragment
Used for showing the last seven added items. This data is read primarily for our local cache.
6.
ListingsFragment
Fragment
Used for showing all items in our Firebase realtime database. However the data is paginated, with each page containing seven items or any number you want.
7.
SearchFragment
DialogFragment
Is our search dialog. First search is performed locally, then if no match is found we connect to Firebase and search there.
8.
Detail Page
Activity
For showing details of a single scientist
Let’s now take a look at organization of this project:
Here’s the app demo:
Android MVVM Firebase CRUD Cache
/App.java
MAIN ROLE: Load our custom fonts and initialize our LRU caching library.
This App.java is our custom application class. It will derive from android.app.Application. We will load our custom fonts right here using a third party library called Calligraphy.
ViewPump.init(ViewPump.builder()
.addInterceptor(new CalligraphyInterceptor(
new CalligraphyConfig.Builder()
.setDefaultFontPath("fonts/Verdana.ttf")
.setFontAttrId(R.attr.fontPath)
.build()))
.build());
We will also initialize our Hard Disk Caching here:
public class Scientist implements Serializable {
private String mId,name,description,galaxy,star,dob,dod,key;
...
This class will represent a single Scientit. It is our model class is therefore basically a java bean. It will define the properties of our scientist like name, description, galaxy, star , date of birth and death of death.
The key property will be autogenerated by Firebase realtime database.
We will make this class implement serializable interface. This will allow us to easily pass it across activities.
/data/model/process/RequestCall.java
MAIN ROLE: Represent a network request against our Firebase realtime database
We want to request this operation using a class to make our code cleaner and manageable. We are interested in three poperties of this operation:
State – The state of operation e.g PROGRESS, ERROR or SUCCESS
Message – The associate message of the operation
An optional downloaded list of scientists.
public class RequestCall {
private int status;
private String message;
private List<Scientist> scientists;
...
/data/repository/ScientistsRepository.java
This is where we will perform our business logic. We are interested in performing CRUD operations agains Firebase Realtime database so we will write logic for doing those right here:
For example to select data we start by defining our method:
public MutableLiveData<RequestCall> select() {
RequestCall r = new RequestCall();
List<Scientist> scientists=new ArrayList<>();
We’ve also instantiate a RequestCall object to represent our network request as well as a List of scientists that will hold our downloaded data.
You can see we’ve then set the RequestCall object to our MutableLiveData object. By the way our method will be returning this mutableLievData object.
Then:
DB.child("Scientists").addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists() && dataSnapshot.getChildrenCount() > 0) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
//Now get Scientist Objects and populate our arraylist.
Scientist scientist = ds.getValue(Scientist.class);
Objects.requireNonNull(scientist).setKey(ds.getKey());
scientists.add(scientist);
}
r.setStatus(Constants.OPERATION_COMPLETE_SUCCESS);
r.setMessage("DOWNLOAD COMPLETE");
r.setScientists(scientists);
} else {
r.setStatus(Constants.OPERATION_COMPLETE_SUCCESS);
r.setMessage("NO DATA FOUND");
}
downloadMutableLiveData.postValue(r);
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.d("FIREBASE CRUD", databaseError.getMessage());
r.setStatus(Constants.OPERATION_COMPLETE_FAILURE);
r.setMessage(databaseError.getMessage());
downloadMutableLiveData.postValue(r);
}
});
return downloadMutableLiveData;
}
DB in this case is our Firebase realtime database reference. You can see we’ve specified the node where our data will be held using the child() method. Then we’ve added a value event listener and overidden two methods:
onDataChange() – SUCCESS
onFailure() – FAILURE
As we said we are returning a MutableLiveData object regardless of the success or failure. After all our RequestCall object which is the generic parameter of our RequestCall accomodates success, failure as well as progress. Thus observers will check for whether the current state is progress, failure or success and react accordingly.
Please take the whole course here or download code here.
Oclemy
This is part of our Udemy premium course: Android Firebase MVVM Jetpack – Many Offline First CRUD Apps. In the course we are covering step by step how to create full android applications based on Firebase Realtime Database and Android Jetpack.
This tutorial will cover the first app we create in that course. The app is an offline-first CRUD app with Search and Pagination capability. In the app the user can add a scientist with his details to the database, fetch them, update them, delete them. The user can also search against already existing Scientists. The data when being read is paginated, making the app efficient. Pagination is taking place at the Firebase level.
The app has several screens/pages:
Let’s now take a look at organization of this project:
Here’s the app demo:
Android MVVM Firebase CRUD Cache
/App.java
MAIN ROLE: Load our custom fonts and initialize our LRU caching library.
This App.java is our custom application class. It will derive from
android.app.Application
. We will load our custom fonts right here using a third party library called Calligraphy.We will also initialize our Hard Disk Caching here:
/data/model/entity/Scientist.java
MAIN ROLE: Is our data object class.
This class will represent a single Scientit. It is our model class is therefore basically a java bean. It will define the properties of our scientist like name, description, galaxy, star , date of birth and death of death.
The key property will be autogenerated by Firebase realtime database.
We will make this class implement serializable interface. This will allow us to easily pass it across activities.
/data/model/process/RequestCall.java
MAIN ROLE: Represent a network request against our Firebase realtime database
We want to request this operation using a class to make our code cleaner and manageable.
We are interested in three poperties of this operation:
/data/repository/ScientistsRepository.java
This is where we will perform our business logic. We are interested in performing CRUD operations agains Firebase Realtime database so we will write logic for doing those right here:
For example to select data we start by defining our method:
We’ve also instantiate a RequestCall object to represent our network request as well as a List of scientists that will hold our downloaded data.
Then we set the properties of our RequestCall:
You can see we’ve then set the RequestCall object to our MutableLiveData object. By the way our method will be returning this mutableLievData object.
Then:
DB
in this case is our Firebase realtime database reference. You can see we’ve specified the node where our data will be held using thechild()
method. Then we’ve added a value event listener and overidden two methods:As we said we are returning a MutableLiveData object regardless of the success or failure. After all our RequestCall object which is the generic parameter of our RequestCall accomodates success, failure as well as progress. Thus observers will check for whether the current state is progress, failure or success and react accordingly.
Please take the whole course here or download code here.