This article assume you have prior Android development experience with Android Studio, since this topic is pretty huge already.
What is this guide?
I will explain what these tech are, why you should use them and where are the good resources to learn them.
Do you need this guide? Plenty of online tutorials I read while learning are half baked, not production ready code and fail to highlight some best practices. I will try to provide guidance to address these issues.
There shall be very little or no code here, since I would need to create a dozen of tutorials to show everything in action (I might create some later targeting specific topics). But I will show you where the good sample code are.
Kotlin
Why use Kotlin?
- Modern, fun and productive language
- Clean and concise code (less code)
- Null safety (Kotlin's type system is aimed to eliminate NullPointerException from our code)
- Nice interoperability with Java
- Officially supported language in Android Studio
You can watch Introduction to Kotlin - Google I/O '17 to have a better understanding of Kotlin's appeal.
Learning Kotlin the fast way
Before we begin, we do need learn a little bit about Kotlin. The official Kotlin reference is the best place to start. Since it could be tiring to go through everything at one go, I selectively pickup:
The above should be enough to get you going, while I google on the go if I see some syntax which I didn't understand.
Architecture Components
Why use Architecture Components?
- Lifecycle-aware components to reduce leaks and crashes.
- LiveData - UI code subscribe/listen to data changes and render UI accordingly (like Reactive programming in RxJava/React/Vue.js, with additional benifit of lifecyle-aware - stop update when pause or destroyed, auto cleanup)
- ViewModel - Data logic/state which survice screen rotation
- Room - ORM which return LiveData (notify when data changed) or RxJava
Learning Architecture Components the correct way
I make the mistake of going into tutorials directly as I am lazy to go through the documentation and thought that I could learn faster from sample code. Boy I was wrong as many tutorials focus on some very genric sample which fail to show production use case and highlight the benefit of using architecture components.
I would recommend reading Guide to App Architecture to have a basic understanding of the components and their relationship.
Room
is the DataSource from SQLite. An additional layer ofRepository
is created if there are multiple DataSource (SQLite, Network, MemoryCache, etc). To avoid over engineering in the beginning, I would recommend useRoom
withoutRepository
to keep things simple.ViewModel
is the data logic, which intereact withRoom
to retreive or update date .ViewModel
supply LiveData (e.g. generated byRoom
) toActivity/Fragment
.Activity/Fragment
callViewModel
to update and retrieve data.ViewModel
also store the state ofActivity/Fragment
.ViewModel
shall never hold any UI widgets to avoid leaks and crashes.Activity/Fragment
subscribe toLiveData
supplied byViewModel
to listen to data changes and render the UI.Activity/Fragment
should only have UI logic, with state/data logic handled byViewModel
(Activity/Fragment
callViewModel
methods).
Read ViewModels and LiveData: Patterns + AntiPatterns for a better understanding of each components, what to do and not to do.
Start Coding
Use Get Started with Kotlin on Android to create a Basic Activity project with Kotlin. Refer Adding Components to your Project to setup Architecture Components for Android Android.
NOTE: include kotlin-kapt plugin and replace annotationProcessor
with kapt
Sequence of learning
Sample Code
Focus on MVVM architecture since we are using ViewModel
- Two main source of sample codes are android-architecture-components and android-architecture.
- I would recommend starting with BasicRxJavaKotlinSample since it's relatively simple to understand. (NOTE: download the entire project by clicking on
Clone or download
and open in Android Studio for easier reading.) - Once you have a basic understanding on how to use the components, download dev-todo-mvvm-live-kotlin. This example is more complete (also more complex) which provide hint on directory structure and architecture design, but it doesn't use LiveData for records from database.
NOTE: dev-todo-mvvm-live-kotlin make use of DataBinding where you can see both LiveData/SingleLiveEvent and Observable in ViewModel
. DataBinding with LiveData shall be available in Android Studio 3.1 (currently in Beta, or you can use android-gradle 3.1).
FAQ / Tips
Why use Room (vs DBFlow) as ORM?
I have considered using DBFlow (speed, more established, good kotlin support). The main reason I choose Room is LiveData (play well with Architecture Component as a lifecycle-aware component, ability to subscribe to data changes).
Room is pretty nice to use as it's something similar to Retrofit, where you can declare SQL statement and it will be generated with as function which return objects. Besides, it can return LiveData, RxJava or DataBinding Observarable.
@Daopublic interface UserDao { @Query("SELECT * FROM user") List<User> getAll(); @Query("SELECT * FROM user WHERE id IN :userId") User getById(int userId);}
LiveData is more than Database Object
LiveData is like a subset of RxJava, where you can subscribe to it and listen to changes. The most common use case is using Room to return LiveData.
LiveData also can be use as Event Bus, where I can create editEvent
in ViewModel
. Activity/Fragment
can listen to editEvent
to launch an activity, where the event is triggered in RecyclerViewAdapter
though viewItem.holder.itemView.setOnClickListener
.
NOTE: Since LiveData+ViewModel is lifecycle aware, I believe it is not possible to use it as Event Bus between activity (only one activity is active at anytime), though you can share data between fragments.
NOTE: Though RxJava could accomplished the same thing, but LiveData should be more lightweight with the benifit of being lifecycle-aware. Read about when to use RxJava in Architecture Components.
NOTE: use SingleLiveEvent which inherit from MutableLiveData
. This avoids a common problem with events: on configuration change (like rotation) an update can be emitted if the observer is active. This LiveData only calls the observable if there's an explicit call to setValue() or call().
// In ViewModelval editEvent = SingleLiveEvent<Long>()// Listener in Activity/FragmentviewModel.editEvent.observe(this@MainActivity, Observer<Long> { id -> startActivityForResult(UserActivity.newIntent(this@MainActivity, id), REQUEST_USER_ACTIVITY)})// Trigger event in RecyclerViewAdapterval item = items.get(position)holder.itemView.setOnClickListener { viewModel.editEvent.value = item.id}
Another example would be to create a snackbarMessageEvent
. Activity/Fragment
will subscribe to this event to display snackbar if event is fired. Both UI or ViewModel code can display SnackBar by snackbarMessageEvent.value = "Edit successful"
.
Concern for Over-engineering
When implementing Architecture Components and looking into sample code of dev-todo-mvvm-live-kotlin, I realize it has a tendency to fall into the trap of over-engineering.
If you are building a simple app, it is possible to cut down a few layer of encapsulation (Activity + ViewModel + Room). If you are building a relatively large app, perhaps the encapsulation and seperation of code will bring more structure and maintainability, hopefully not at too much expense of productivity (Imagine we need at least 5 classes/files for a single activity: Activity + Fragment + Adapter + ViewModel + Respository + Room + Retrofit).