--

Wednesday 24 October 2018

Chapter 1 : Modern Android Architecture ‘Android Jetpack’ – Managing & Tracking Android Lifecycle (Room, LiveData and ViewModel)


        While managing lifecycle, we have to manage the data, orientations or memory leaks all based on lifecycle and we have to do it on our own which is cumbersome sometimes. So, we need these new set of libraries which can do most of our work very easily without going into deep. The Support Library components aren’t the only familiar features in the list of Jetpack components. All of the Architecture Components (Lifecycle, LiveData, Room and ViewModel) are now part of Jetpack, too.

It helps us to solve two critical points:

  • Manage our UI components lifecycle
  • Persist data over configuration changes

In this chapter, We are going to develop an app, which basically
  1. Takes some input from the user(LiveData)
  2. Save into the local database(Room) 
  3. Show it on the screen(ViewModel)
Let’s get started!!

Note : Use Android Studio 3.0 or later version.

Adding Dependencies (Pre AndroidX)


Room is basically a Database object mapping library use to access the database. Lifecycle, this has some good set of classes like ViewModel and LiveData which we will use to manage the lifecycle of our app. Add these libraries to build.gradle (Module: app) file, at the end of the dependencies block.

dependencies {
// Room components
implementation 'android.arch.persistence.room:runtime:2.0.0'
annotationProcessor 'android.arch.persistence.room:compiler:2.0.0'

// Lifecycle components
implementation 'android.arch.lifecycle:extensions:2.0.0'
annotationProcessor 'android.arch.lifecycle:compiler:2.0.0'
}

Refer here for AndroidX Dependencies.


Room (Local database)

We can query your data without having to deal with cursors or loaders. We can define our database by adding annotations in your Model class. So get rid of third-party ORMs like Sugar, In fact, when the official Android libraries give you an equal, or if not, better solution. The library helps you create a cache of your app's data on a device that's running your app. If user does not have internet connection, Just chill ! No problem! This cache allows users to view a consistent copy of key information within your app.

3 key concepts of Room


@Entity - We just have to annotate “@Entity” to a class and the name of the class becomes table name and, data members becomes the name of the columns. “@Entity” class represent an entity in a table.



Here, we have class StudentModel, and name of table is also same. We had made a column itemName, personName, and addedDate.

@Dao (Data Access Object) - An Interface where we put all our SQL queries. No need to write whole quires now, we just need to make a method and annotate with specific annotations like “@Insert”, “@Delete”, “@Query(SELECT FROM *)”



Here, we have an interface StudentModelDao. To insert the data we annotated “@Insert” to insert method. Room doesn’t gives us annotations which can help us in selecting everything so we have “@Query” to do some custom queries.

@Database - We need to create an abstract class (Room class) which extends RoomDatabase. It is a database layer over the SQLite database; this helps us in all the work which we use to do in SQLiteOpenHelper class. We need only a single instance for the whole app.



Here, we have a Room class AppRoomDatabase in which we declare all our entities and version of the database. getDatabase() method will return the room database instance. If we want to access the database lets deep dive into ViewModel and LiveData.


ViewModel (Data-handling business logic)

ViewModel is the new class provided by lifecycle. It can be termed as the bridge between model and UI but quite intelligent one in the sense that it can be automatically retained in the case of orientation change .

Generally what happens during orientation change?
        For instance we are in one activity and the activity loads some list and add it to the RecyclerView. Now when the orientation change has not been handled then new instance of activity will be created and the loading of list takes place and is then again added to RecyclerView.

How does 
ViewModel solve this problem?
        If you have used 
ViewModel along with LiveData class to store data then during orientation change new instance of activity will be created but the data won't be downloaded again. ViewModel will provide the most recent available data.

Note: Don’t think that 
ViewModel will hold data forever or for every case. If you close or activity is destroyed the ViewModel will also be destroyed or cleared.



StudentListViewModel class must extend the ViewModel class. If the ViewModel needs the application context, then it must extend the AndroidViewModel class. 
In our ViewModel, we first get an instance of our database using AppRoomDatabase.getDatabase(this.getApplication())

We need to load the list of student items from the database. For that, we should use the query we defined in the DAO class, getAllStudItems(). Next, call the abstract method we created for DAO and then call the query method. 


appDatabase.itemAndStudentModel().getAllStudItems();

The ViewModel will contain all the data needed for our Activity. In our example, we are using something called LiveData.

LiveData

LiveData is an observable data holder. It can only be observed in the context of a lifecycle, more precisely in the context of an Activity or Fragment lifecycle. By passing the reference of an Activity or Fragment, it can understand whether your UI onScreen, offScreen or Destroyed. After passing the UI object to LiveData, whenever the data in the live data changes. It notifies the lifecycle owner with updates and then the UI redraw itself with updates.

MutableLiveData extends LiveData internally and also the two methods of LiveData available,
1. setValue() : Set the value and dispatch the value to all the active observers. It cannot be done in background thread it must be done in the main thread only.
2. postValue() : Post a task to main thread to override value set by setvalue. As setvalue cannot be called from background thread so post value must be used to set value from background thread.


How LiveData solved developer`s major Headaches ?

  • No more manual life-cycling handle - Observers just observe relevant data and don’t stop or resume observation. LiveData manages all of this under control.
  • Proper configuration changes - If an observer is recreated due to a configuration change, like device rotation, it immediately receives the latest available data.
  • Ensures your UI matches the data state -Instead of updating the UI every-time when the data changes, your observer can update the UI every time there’s a change. It receives the latest data upon becoming active again.
  • No memory leaks - Observers are bound to Lifecycle objects and clean up after themselves when their associated life cycle destroyed.
  • No crashes due to stopped activities - It means if an activity is in the back stack, then it doesn’t receive any LiveData stream.
  • Sharing resources - You can extend LiveData object using the singleton pattern to wrap system services so that they can be shared in your app.
  • We wrap our list of student items inside LiveData so that the Activity can observe changes in the data and update the UI.


Framing RecyclerView Adapter

Now since we will be displaying a list of student items, we need a RecyclerView. So first, let’s create an adapter for the same.

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.RecyclerViewHolder> {
private List<StudentModel> studentModelList;
private View.OnLongClickListener longClickListener;

public RecyclerViewAdapter(List<StudentModel> studentModelList, View.OnLongClickListener longClickListener) {
this.studentModelList = studentModelList;
this.longClickListener = longClickListener;
}

@Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new RecyclerViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycler_item, parent, false));
}

@Override
public void onBindViewHolder(final RecyclerViewHolder holder, int position) {
StudentModel borrowModel = studentModelList.get(position);
holder.itemTextView.setText(borrowModel.getItemName());
holder.nameTextView.setText(borrowModel.getPersonName());
holder.dateTextView.setText(borrowModel.getAddedDate().toLocaleString().substring(0, 11));
holder.itemView.setTag(borrowModel);
holder.itemView.setOnLongClickListener(longClickListener);
}

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

public void addItems(List<StudentModel> borrowModelList) {
this.studentModelList = borrowModelList;
notifyDataSetChanged();
}

static class RecyclerViewHolder extends RecyclerView.ViewHolder {
private TextView itemTextView;
private TextView nameTextView;
private TextView dateTextView;
RecyclerViewHolder(View view) {
super(view);
itemTextView = view.findViewById(R.id.itemTextView);
nameTextView = view.findViewById(R.id.nameTextView);
dateTextView = view.findViewById(R.id.dateTextView);
}
}
}


Creating the Android LifecycleObserver & LifecycleOwner


The basic idea here is that there is a class named LifecycleOwner which emits various lifecycle events (such as ON_CREATE, ON_PAUSE, etc) which you as an Android Developer are already familiar with. Now you can implement an interface name LifecycleObserver which listens to these events and respond accordingly.

public class AppLifeCycleObserver implements LifecycleObserver {
private String LOG_TAG = "AppLifeCycleObserver";
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
Log.i(LOG_TAG, "onResume");
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause() {
Log.i(LOG_TAG, "onPause");
}
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void onCreate() {
Log.i(LOG_TAG, "onCreate");
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onStart() {
Log.i(LOG_TAG, "onStart");
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onStop() {
Log.i(LOG_TAG, "onStop");
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onDestroy() {
Log.i(LOG_TAG, "onDestroy");
}
}


Adding the Observer


Observers are added to lifecycle owners via calls to the addObserver() method of owner’s Lifecycle object, a reference to which is obtained via a call to the getLifecycle() method. Edit the HomeActivity.java class file and add code to the onCreate() method to add the observer:



Creating a Lifecycle Owner

By creating a custom lifecycle owner class and demonstrate how to trigger events and modify the lifecycle state from within that class. The class is going to need a LifecycleRegistry instance initialized with a reference to itself, and a getLifecycle() method configured to return the LifecycleRegistry instance. Declare a variable to store the LifecycleRegistry reference, a constructor to initialize the LifecycleRegistry instance and add the getLifecycle() method:




Next, the class will need to notify the registry of lifecycle state changes. By triggering lifecycle events using the handleLifecycleEvent() method. For this example, we will add some methods that simply trigger lifecycle events when called. Finally change within the AppLifecycleOwner class is to add the AppLifeCycleObserver class as an observer.

In HomeActivity.java, create an instance of the AppLifecycleOwner class and to call the startLifecycleOwner() and stopLifecycleOwner() methods.



We must remove observer in onDestory() method of calling activity to avoid memory leaks.

@Override
protected void onDestroy() {
super.onDestroy();
getLifecycle().removeObserver(new AppLifeCycleObserver());
}


I have uploaded the latest source code in 
GitHub for your reference. Kindly raise your queries in the command section.

References :

https://developer.android.com/jetpack/arch/lifecycle
https://medium.com/mindorks/android-architecture-components-room-viewmodel-and-livedata-50611793e4a9
https://blog.iamsuleiman.com/android-architecture-components-tutorial-room-livedata-viewmodel/
https://codinginfinite.com/android-livedata-example/


Happy coding!!!
Cheers!!!

Sunday 7 October 2018

Chapter 0 : Modern Android Architecture ‘Android Jetpack’ - Lifecycle


       Jetpack is “the next generation of components to accelerate app development”. It’s a set of libraries, tools and architectural guidelines to help making building great Android apps quick and easy. It provides common infrastructure code so you can focus on what makes your app unique.



Activity/Fragment - Depend only on a view model.
View model - Provides the data for fragment or activity, and contains data-handling business logic to communicate with the model.
Repository - Depends on a persistent data model and a remote backend data source and handle data operations.
Room - An object-mapping library that provides local data persistence with minimal boilerplate code.
Retrofit library - To access our backend through REST API.

Lifecycle-manageable components such as activities and fragments perform actions in response to a change in another Android component. The lifecycle methods of activities and fragments leads to a poor organization of the code and to the proliferation of errors in most of the cases.
The lifecycle-aware component helps to move the code of dependent components out of the lifecycle methods of activity & fragments and into the components themselves.

Dependencies


AndroidX

dependencies {
def lifecycle_version = "2.0.0"
// Lifecycles only (no ViewModel or LiveData)
implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" // use kapt for Kotlin
// alternately - if using Java8, use the following instead of lifecycle-compiler
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
}


Pre-AndroidX

dependencies {
def lifecycle_version = "1.1.1"
// Lifecycles only (no ViewModel or LiveData)
implementation "android.arch.lifecycle:runtime:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version" // use kapt for Kotlin
// alternately - if using Java8, use the following instead of compiler
implementation "android.arch.lifecycle:common-java8:$lifecycle_version"
}


Refer here for updated Dependencies.

The android.arch.lifecycle package can automatically adjust their behavior based on the current lifecycle state of an activity or fragment that has three main classes that we’ll deal with:
  • LifeCycle
  • LifeCycleOwner
  • LifeCycleObserver

Lifecycle


Lifecycle class holds the information about the component (like an activity or a fragment) lifecycle state where allows other objects to observe this state.

The lifecycle events (i.e. Lifecycle.Event.ON_CREATE, Lifecycle.Event.ON_RESUME, Lifecycle.Event.ON_PAUSE and etc) & lifecycle states (INITIALIZED, CREATED, RESUMED and etc) are used to track the lifecycle status for its associated component.




A single state can span multiple lifecycle owner events, so for an activity it’s considered in the CREATED state once it’s created and just before it’s paused, and in the same time the duration between the activity’s onStart() and just before onPause() it’s considered also in the STARTED state.
Since multiple states can interleave for a given point of time, if we want to check for a specific state, we always use the isAtLeast method:

if (lifeCycle.currentState.isAtLeast(Lifecycle.State.STARTED)) { //...}

LifecycleOwner and Lifecycle Observers


If we're trying to manage the lifecycle of activity or Fragment, we must implement LifecycleOwner interface to the activity. The lifecycle of a whole application process is managed by ProcessLifecycleOwner. Fragments and Activities in Support Library 26.1.0 and later already implement the LifecycleOwner interface.

If we have a custom class that we would like to make a LifecycleOwner, we can use the LifecycleRegistry class, but we need to forward events into that class.

LifecycleOwners such as Activity & Fragments are objects with lifecycle like Activity and Fragments. LifecycleObserver (e.g. LiveData) observes LifecycleOwners and are notified of lifecycle changes.

class SampleObserver implements LifecycleObserver{

@OnLifecycleEvent(ON_CREATE)
void startUp(LifecycleOwner source) {
}

@OnLifecycleEvent(ON_ANY)
void onAny(LifecycleOwner source, Event event) {
}

@OnLifecycleEvent(ON_STOP)
void cleanUp(LifecycleOwner source) {
}
}


The best way to handle lifecycle-aware components (activities and fragments) as lean as possible. They should not try to acquire their own data; instead, use a ViewModel to do that, and observe a LiveData object to reflect the changes back to the views.
So, Android Lifecycle-aware components are tracked and managed by Room, LiveData and ViewModel in the next episode.