How to create Android app using Android Architecture Components. The study.

Tomasz Milczarek
6 min readJan 30, 2018

--

The idea

Recently, along with Grzegorz Bielanski and Tomasz Myśliwiec, I came up with the idea of ​​creating an app supporting the collection of garbage put up in front of the house. The MVP (minimum valuable product) of the app was:

  • show different sectors (regions) of the city where garbage is collected
  • show list of future collection dates
  • notify user about these dates

The main screen presents three sectors of the town where garbage is collected:

Next, when you tap on sector you enter detail view presenting list of dates when garbage will be collected:

As one can see the app is a typical list/detail-view application with just one toggle component for notification subscriptions. As such it was a very good candidate for learning and testing new features and new Android APIs.

Since the two of us are Android developers, we’ve decided that our target platform will be… yes, Android. In addition, we both participate in the Android course organised by Udacity. So we thought that creating an application could be simply a good exercise and improvement of our practical development skills.

Grzegorz Bielanski wrote in more detail about the idea of the application in this article:

This post deals with just technical aspects of the app.

The technology

During the Udacity course students learn pure Android framework.
They learn how to use the basic components of Android (Activity, Service, ContentProvider, BroadcastReceiver), how to manage threads using the tools provided by the platform (AsyncTasks, AsyncLoaders, Services) and how to make a professional look & feel of the app (styles, themes etc.).

Therefore, to expand my knowledge I decided to use API not covered in the course but also belonging to Android platform — Android Architecture Components (AAC).

AAC were announced by Google in June 2017 (Google I/O). As official docs state AAC are collection of libraries that help you design robust, testable and maintainable apps. The following components can be distinguished: Room, ViewModel, LiveData and Lifecycle.

In our app we used Room to model and operate on our domain model, ViewModel to serve our presentation model and LiveData as a channel for transferring data between the two previous layers.

The architecture

AAC comes with imposed architecture which is known as MVVM (Model-View-ViewModel). Model stands for domain model, View is just a view layer and ViewModel acts as an adapter for data between model and view. The LiveData components are the way to communicate between these two layers.

The architecture of our application was based on Google’s official documentation:

and Codelabs session:

Basing on these assumptions we extracted the following packages structure:

  • /data/database — here come all the classes operating on local database
  • /data/network — classes used for fetching data from network
  • /data — repository class
  • /ui — flat folder for different view components (activities, fragments, views). In our simple app this package also contained ViewModel classes.

/data/database folder contained all domain model classes described by Room, e.g.:

@Entity(tableName = "sector_terms", indices = {@Index(value ={"sectorColor"})})
public class SectorTerm {

@PrimaryKey(autoGenerate = true)
private int id;
...}

SectorTerm class represents the base entity in our system which is due date for a given sector (region where garbage collection is performed).

Following the instructions I added DAO classes which operate on domain model:

@Dao
public interface SectorTermDao {

@Query
("SELECT * FROM sector_terms WHERE term >= :d AND sectCol == :sc")
LiveData<List<SectorTerm>> getFutureSectorTerms(Date d, int sc);
...}

As you can see DAO methods return LiveData objects. It’s important because this way Repository class will be able to observe data returned from DAO and react on changes:

public LiveData<List<SectorTerm>> getSectorTerms(SectorColor sc) {
Date today = SectorTermsDateUtils.getNormalizedUtcDateForToday();
return mSectorTermDao.getFutureSectorTerms(today, SectorColor.toInt(sc));
}

Repository class calls DAO and passes on data exposed again as LiveData.

So far I described just one path: data coming from local database.
Repository class is designed to handle both the local database and network data. The local database is supported by DAO (as mentioned above) and for the network we created dedicated service class:

public class SectorTermsNetworkDataSource {  ...  DatabaseReference mFirebaseDatabaseReference;
MutableLiveData<List<SectorTerm>> mDownloadedSectors;
...}

This service is kind of a common gate to other services: JobService, IntentService and FirebaseDatabase. Generally, it manages all the components that perform network operations.

The next layer we used is ViewModel. As documentation says:

A ViewModel provides the data for a specific UI component, such as a fragment or activity, and handles the communication with the business part of data handling, such as calling other components to load the data or forwarding user modifications. The ViewModel does not know about the View and is not affected by configuration changes such as recreating an activity due to rotation.

This component is dedicated to transfer data from domain model to presentation model. That’s why it contains two dependencies: Repository and another LiveData reference which will be exposing data to View layer:

public class DetailActivityViewModel extends ViewModel {
private final LiveData<List<SectorTerm>> mSectorTerms;
private final SectorTermRepository mRepository;
...}

In this case ViewModel is quite simple. It does not contain any logic,
we simply pass data from one layer to another. In other words the domain model == presentation model. If there was a need to prepare presentation model and implement some logic, ViewModel would be a good place to do so.

As defined by MVVM definition, the last (the outermost layer) is View. Views in our app are activities. We have three activities responsible for each sector. Each sector screen displays information about dates for scheduled collections:

In these activities, in onCreate() method we instantiate ViewModel references:

mViewModel = ViewModelProviders.of(currentSector(), factory).get(DetailActivityViewModel.class);

Next, we observe the LiveData sector list returned by mViewModel.getSectorTerms():

mViewModel.getSectorTerms().observe(this, new Observer<List<SectorTerm>>() {
@Override
public void onChanged(@Nullable List<SectorTerm> sectorTerms) {
// refresh view components
}
});

In this way we update view every time there are changes in the backend (local database or network).

When it comes to the look&feel of the app: we used material design recommendations. The app has simple, flat design. The only distinguishing feature is the use of animations between activity transitions.

There’s much more features and technical solutions to describe and discuss but the best way is to look at the source code and analyse it. The app is open-sourced and hosted on github:

It is also still under heavy development, there are many things to improve but we have already released it on Google Play and the first ratings are very promising :)

Link to the app:

If you have any questions please let me know via twitter:

or github account:

Thanks for reading!

--

--

Tomasz Milczarek

iOS Developer @ Millennium Bank. At work trying to follow agile/software craftsmanship practices.