Modern Android development with Kotlin, Part 1

Mladen Rakonjac
ProAndroidDev
Published in
12 min readAug 31, 2017

--

It is really hard to find one project that covers all the things that are new in Android Development, so I decided to write one. In this article we will use the following:

https://twitter.com/brijeshmasrani/status/901291501870751745

0. Android Studio 3, beta 1
1. Kotlin language
2. Build Variants
3. ConstraintLayout
4. Data binding library
5. MVVM architecture + repository pattern ( with mappers) + Android Manager Wrappers ( Part 2 )
6. RxJava2 and how it helps us in architecture ( Part 3)
7. Dagger 2.11, what is Dependency Injection, why you should use it. (Part 4)
8. Retrofit (with Rx Java2)
9. Room (with Rx Java2)

What our app will be?
Our app will be the simplest app that covers all mentioned things: it will have only one feature that fetches all GitHub repositories from user googlesamples, saves those data in local database and shows it to user.

I will try to explain as many lines of code as I can. You can follow looking on commits of code that I published on github.

Let’s make our hands dirty:

0. Android studio

To install Android Studio 3 beta 1 you have to go to this page.

Note: If you want to install it along with some previous version, on Mac you should rename old version in Application folder to for example “Android Studio Old”. You can find more info, including Windows and Linux here.

Android Studio has support for Kotlin. Go to Create Android Project. You will see new thing there: Checkbox with label include Kotlin support. It is checked by default. Press next twice and select Empty Activity, then finish.
Congrats! You have made first Android app in Kotlin :)

1. Kotlin

You can see MainActivity.kt:

The .kt extension means that file is Kotlin file.

MainActivity : AppCompatActivity() means that we are extending AppCompatActivity.

Further, all methods have to have a fun word and in Kotlin you don’t have to use ; but you can if you like. You have to use override word and not an annotation.

So, what is the meaning of ? in savedInstanceState: Bundle? ? It means that savedInstanceState parameter can be Bundle type or null. Kotlin is null safety language. If you have:

var a : String

you will get a compilation error, cause a must be initialized and it cannot be null. That means you have to write:

var a : String = "Init value"

Also, you will get a compilation error if you do:

a = null

To make a nullable, you have to write:

var a : String?

Why is this important feature of Kotlin language? It helps us to avoid NPE. Android developers are so tired of NPE. Even creator of null, sir Tony Hoare, apologized for inventing it . Let’s say that we have nullable nameTextView. The following code will give us NPE if it is null:

nameTextView.setEnabled(true)

But Kotlin, actually, is good and it will not allow us to even do such a thing. It will force us to use ? or !! operator. If we use ? operator:

nameTextView?.setEnabled(true)

the line will be proceeded only if nameTextView is not a null. In another case, if we use !! operator:

nameTextView!!.setEnabled(true)

it will give us NPE if nameTextView is a null. It is just for adventurers :) .

This was a little introduction for Kotlin. As we move on, I will stop to describe other Kotlin specific code.

2. Build Variants

Often in development, you have different environments. The most usual are testing and production environment. Those environments can differ in server url, icon, name, target api and so on. Usually, in every project at the start I have following:

  • finalProduction , that goes to Google Play Store
  • demoProduction, that is version with production server url with new features that are still not on Google Play Store. Our clients can have this version installed next to the one from Google Play so they can test it and give us feedback.
  • demoTesting, same as demoProduction with testing server url
  • mock, useful for me as a developer and for designers. Sometimes we have the design ready and our API is still not ready. Waiting for API to be ready to start development is not a solution. This build variant is provided with fake data, so design team can test it and give us feedback. It is really helpful to not procrastinate. Once when API is ready, we are moving our development to demoTesting environment.

In this application, we will have all of them. They will differ in applicationId and name. There is a new api in gradle 3.0.0 flavorDimension that allows you to mix different product flavors, so you can mix demo and minApi23 flavors. In our app, we will use just “default” flavorDimension. Go to build.gradle for App and insert this code inside android{}

Go to strings.xml and delete app_name string, so we will not have conflicts. Then press Sync Now. If you go to Build Variants that are on the left of the screen, you can see 4 different build variants where each of them has two build types: Debug and Release. Switch to demoProduction build variant and run it. Then switch to another one and run it. You should see two applications with different names.

3. ConstraintLayout

If you open activity_main.xml class, you should see that layout is ConstrainLayout. If you ever code iOS application, you know about AutoLayout. ConstraintLayout is really similar to it. They are even using the same Cassowary algorithm.

Constraints help us to describe what are relations of views. For each view you should have 4 constraints, one for each side. In this case, our view is constrained to parent for each side.

If you move Hello World text view little bit up in Design tab, in Text tab new line will appear:

app:layout_constraintVertical_bias="0.28"

Design tab and Text tab are synced. Our move in Design tab affects xml in Text tab and vice verse. The Vertical bias describes the vertical tendency of the view to his constraints. If you want view to be centered vertically, you should use:

app:layout_constraintVertical_bias="0.28"

Let’s make our activity to show just one repository. It will have name of repository, number of stars, owner and it will show if repository has issues or not.

To get such a layout, xml has to look like this:

Don’t be confused with tools:text. It just helps us to have good preview of the layout.

We can notice that our layout is flat. There are no nested layouts. You should use nested layouts as less as you can cause it can affect performance. More info about it you can find here. Also, ConstraintLayout works with different screen sizes really good:

and I have a feeling that I can achieve wanted result really fast.
That was a small introduction in ConstraintLayout. You can find Google code lab here and there is a documentation about CL on github.

4. Data binding library

When I heard about data binding library, first thing that I asked myself was “Butterknife works really good for me. Plus, I am using a plugin that helps me to get views from xml. Why should I change it?”. Once I learned more about data binding I had the same feeling like I had when I used ButterKnife for the first time.

What ButterKnife helps us?

ButterKnife helps us to get rid of boring findViewById. So, if you have 5 views, without Butterknife you have 5 + 5 lines to bind your views. With ButterKnife you have 5 lines. And that’s it.

What is ButterKnife bad for?

ButterKnife still does not solve the problem of code maintains. When I used ButterKnife, I often found myself getting a runtime exception, cause I deleted view in xml and I didn’t delete binding code in activity/fragment class. Also, if you want to add view in xml, you have to do binding again. It is really boring. You are losing your time to maintain bindings.

What about Data Binding library?

There are a lot of benefits! With Data binding library you can bind your views with just one line of code! Let me show you how it works. Let’s add Data Binding library to our project:

// at the top of file 
apply plugin: 'kotlin-kapt'


android {
//other things that we already used
dataBinding.enabled = true
}
dependencies {
//other dependencies that we used
kapt "com.android.databinding:compiler:3.0.0-beta1"
}

Note that version of Data Binding compiler is same as gradle version in your project build.gradle file:

classpath 'com.android.tools.build:gradle:3.0.0-beta1'

Press Sync Now. Go to activity_main.xml class and wrap Constraint Layout with layout tag:

Note that you have to move all of xmlns to layout tag. Then press Build icon or use shortcut Cmd + F9. We need to build project so Data Binding library can generate class ActivityMainBinding that we will use in our MainActivity class.

If you don’t do Build of the project you will not see ActivityMainBinding class cause it is generated at compile time. We still did not finish binding, we just said that we have non-null variable that is ActivityMainBinding type. Also, as you can notice I didn’t put ? on the end of ActivityMainBinding and I did not initialize it. How is it possible? lateinit modifier allows us to have non-null variables waiting for initialization. Similar to ButterKnife, binding initialization should be done in onCreate method, once when our layout is ready. Further, you should not declare binding in onCreate method, cause you will probably use it outside of onCreate method scope. Our binding should not be null, so that is why we use lateinit. Using lateinit modifier we don’t have to null check binding variable each time when we access it.

Let’s initialize our binding variable. You should replace:

setContentView(R.layout.activity_main)

with:

binding = DataBindingUtil.setContentView(this, R.layout.activity_main)

That’s it! You successfully bind your views. Now you can access it and apply some changes. For example, let’s change repository name to “Modern Android Medium Article” :

binding.repositoryName.text = "Modern Android Medium Article"

As you can see we can access to all views (those that have id, of course) from activity_main.xml through the binding variable. That is why Data Binding is better than ButterKnife.

Getters and setters in Kotlin

Probably, you already noticed that we don’t have .setText() method like we do in Java. I would like to stop here to explain how getters and setters work in Kotlin comparing to Java.

First, you should know why we are using setters and getters. We are using it to hide variables of the class and to allow access only through methods so we can hide details of the class from the clients of the class and forbid same clients to change our class directly. Let’s say that we have Square class in Java:

Using setA() method we are forbidding clients of the class to set a negative value to a cause side of the square must not be negative. Using this approach we have to make a private, so it cannot be set directly. That also means the client of our class cannot get the a directly , so we have to provide a getter. That getter returns a. If you have 10 variables with similar requirements you have to provide 10 getters. Writing such lines is the boring thing where we usually not use our mind.

Kotling makes our developer’s life easier. If you are calling

var side: Int = square.a

it does not mean that you are accessing a directly. It is same as:

int side = square.getA();

in Java cause Kotlin autogenerates default getters and setters. In Kotlin, only if you have special setter or getter you should specify it. Otherwise, Kotlin autogenerates it for you:

var a = 1
set(value) { field = Math.abs(value) }

field ? What is this now? To make it clear, let’s look at this code:

var a = 1
set(value) { a = Math.abs(value) }

This means that you are calling the set method inside the set method cause there is no direct access to the property in Kotlin world. This will make infinite recursion. When you call a = something it automatically calls set method.
I hope now it is clear why you must use field keyword and how setters and getters work.

Let’s go back to our code. I would like to present you one more great feature of Kotlin language, apply :

apply allows you to call multiple methods on one instance.

We still did not finish with Data Binding, there are more great things. Let’s make ui model class for Repository ( This is UI Model class for Github Repository, holds data that should be displayed, do not misplace it with Repository Pattern). To make Kotlin class you should go to New -> Kotlin File/Class :

class Repository(var repositoryName: String?,var repositoryOwner: String?,var numberOfStars: Int? ,var hasIssues: Boolean = false)

In Kotlin, the primary constructor is a part of a class header. If you don’t want to provide the second constructor, that’s it! Your job of class making is finished here. There are no constructor parameters to fields assigns, there are no getters and setters. Whole class in just one line!

Go back to MainActivity.kt class, and make an instance of Repository class:

var repository = Repository("Medium Android Repository Article",
"Mladen Rakonjac", 1000, true)

As you can notice, there is no new keyword for object construction.

Now let’s go to activity_main.xml and add data tag:

<data>
<variable
name="repository"
type="me.mladenrakonjac.modernandroidapp.uimodels.Repository"
/>
</data>

We can access this repository variable that is Repository type in our layout. For example we can do following in TextView with repository_name id:

android:text="@{repository.repositoryName}"

repository_name text view will show text that is got from repositoryName property of repository variable. The only thing that is left is to bind repository variable from xml to repository from MainActivity.kt.
Press Build to make Data Binding library to generate needed classes and go back to Main Activity and add this two lines:

binding.repository = repository
binding.executePendingBindings()

If you run the app, you will see that textview will show “Medium Android Repository Article”. Nice feature, huh? :)

But what if we do following:

Handler().postDelayed({repository.repositoryName="New Name"}, 2000)

Will the new text be shown after 2000 millis ? No, it will not. You have to set repository again. Something like this will work:

Handler().postDelayed({repository.repositoryName="New Name"
binding.repository = repository
binding.executePendingBindings()}, 2000)

But, it will be boring if have to do this every time when we change some property. There is a better solution called Property Observer.
Let’s first describe what is Observer pattern cause we will need it in rxJava section too:

Probably, you have already heard for http://androidweekly.net/ . It is a weekly newsletter about Android Development. If you want to receive it , you have to subscribe onto it giving your email address. After some time, if you decide it, you can stop it going to unsubscribe option on their site.

This is one example of Observer/Observable pattern. In this case Android Weekly is Observable, it emits newsletters each week. Readers are Observers cause they subscribe on it, waits for new emits and once when they receive it, they read it and if some of them decide that she does not like it, she/he can stop listening to it.

Property Observer in our case is xml layout, that will listen for changes in Repository instance. So, Repository is Observable. For example, once when repository name property is changed in the instance of Repository class, xml should be updated without calling:

binding.repository = repository
binding.executePendingBindings()

How to make it using Data Binding library? Data Binding library provide us with BaseObservable class that Repository class should implement:

BR is a class that is auto generated once when Bindable annotation is used. As you can see, once when the new value is set we are notifying it. Now you can run the app and you will see that repository name will be changed after 2 seconds without calling executePendingBindings() again.

That was all for this part. In next part, I will write about MVVM pattern and Repository pattern and I will write about Android Wrapper Managers. You can find all code here. This article cover code up to the following commit.

You can find Part 2 here:

Thanks for reading and follow me for more articles like this. :)

P.S. Thanks to:

--

--