Android REST App with less than 100 lines of code

Android REST App with less than 100 lines of code

 

The Idea

This is one of my first blog posts (here the original one) I have ever written and my idea here is to show part of my experience as an Android Developer and try to make some people’s life easier. It would be great if you share your opinion 🙂

 

The Tech Stack

AndroidKotlinCoroutinesLiveDataNavigation ComponentKoinRetrofit… these are part of the technologies and libraries which I will use in my project. If you are not familiar with some of them, it’s not a problem, you can quickly check their documentations in the links above.

 

The Code

First I created an empty Android Studio project with Kotlin language and androidx.* artifacts, because we want to use all new stuff from Google.

 

After that I added all needed dependencies:

 

Lifecycle, ViewModel, LiveData:

// Lifecycle
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"

 

Navigation:

//Navigation
implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version"
implementation "androidx.navigation:navigation-ui-ktx:$navigation_version"

 

Koin:

// Koin for Android
implementation "org.koin:koin-android-viewmodel:$koin_version"

 

Retrofit, Moshi and OkHttpClient

// Retrofit 2 & Moshi
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version"
implementation "com.squareup.retrofit2:retrofit-mock:$retrofit_version"
implementation "com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:$retrofit_adapter_version"
implementation "com.squareup.moshi:moshi:$moshi_version"
implementation "com.squareup.moshi:moshi-kotlin:$moshi_version"
implementation "com.squareup.moshi:moshi-adapters:$moshi_version"
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version"
// OkHttp 3
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version"

After we are done with the build.gradle file it’s time to start with the real development. First we have to make our work easier and use Dependency Injection, for that reason we will use Koin (not Dagger :)). If you have never used Koin or Kotlin, now is the time to change your mind and try it.

 

Koin Modules

First I will create a module for the WebService (Retrofit) which will make our REST calls

val webServiceModule = module {
//Create OkHttpClient
single { createOkHttpClient() }
//Create WebServiceApi
single { createWebServiceApi(okHttpClient = get()) }
}

Then ViewModel module

val viewModelModule = module {
//Create an instance of MyRepository
single { MyRepository(get()) }
//Create an instance of MyVieModel
viewModel
{ MyViewModel(get()) }
}

And after we are ready with the Modules, we can create the Component which with Koin and Kotlin looks like this:

val appComponent: List = listOf(webServiceModule, viewModelModule)

just a list with all modules, nice a? 🙂

In the end we just have to startKoin in our Application class

override fun onCreate() {
super.onCreate()
startKoin {
androidLogger()
androidContext(this@App)
modules(appComponent)
}
}

Done, with 10 lines of code we already can inject our WebService, Repository and ViewModel.

Now we are ready to start building our application with its separate layers. And because I really like MVVM design pattern our building blocks will be View (Fragments in our case), ViewModel and Model (our Repository where the whole business logic will be placed).

 

Model (WebService, Repository)

My WebService is really simple with one GET request to get a User by ID and it looks like this:

interface WebServiceApi {
@GET("/users/{user_id}")
suspend fun getUser(@Path("user_id") userId: Long): Response
}

How you can see Retrofit already supports suspend functions and we can use our REST calls with Kotlin Coroutines which is super nice.

So, the class which will use our WebService is our Repository and this is how it looks with DI, LiveData, Suspend functions and less code:

class MyRepository(private val webServiceApi: WebServiceApi) {

fun getUserById(id: Long): LiveData> {
return liveData(Dispatchers.IO) {
emit(Resource.Loading())
val response = webServiceApi.getUser(id)
if (response.isSuccessful) {
emit(Resource.Success(response.body()))
} else {
emit(Resource.Error("Get User failed!"))
}
}
}
}

Another cool stuff which we use here is livedata{} building block where we call getUser(id) asynchronously, and then use emit() to emit the result. And one small note here, we create a simple helper sealed class Resource which handles networking calls results, also you can check the class here:

sealed class Resource(
val data: T? = null,
val message: String? = null,
val status: Status
) {
class Success(data: T) : Resource(data, status = Status.SUCCESS)
class Loading(data: T? = null) : Resource(data, status = Status.LOADING)
class Error(message: String, data: T? = null) : Resource(data, message, Status.ERROR)
}

enum class Status {
SUCCESS,
ERROR,
LOADING
}

Now we already have our app engine which will make REST call, process the result and return back LiveData response to which we can subscribe for changes.

 

ViewModel

Our ViewModel which will be used from our View (Fragment) is huge, but I will put the code here:

class MyViewModel(private val myRepository: MyRepository) : ViewModel() {

fun
getUserById(id: Long) = myRepository.getUserById(id)

}

Just a joke, it’s a single line 🙂

 

View

The place where the data from the Web Server will be shown is our View and this is how the Fragment looks like:

class MyFragment : Fragment() {

// Lazy Inject ViewModel
val viewModel: MyViewModel by sharedViewModel()

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.my_fragment, container, false)
}

override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewLifecycleOwner.lifecycleScope.launchWhenStarted {
viewModel
.getUserById(userId).observe(viewLifecycleOwner, Observer {
when
(it.status) {
Status.SUCCESS -> showResult()
Status.ERROR -> showError()
Status.LOADING -> showLoading()
}
})
}
}

}

The great stuff here is:

  • by sharedViewModel() –inject the ViewModel
  • viewLifecycleOwner –use it when you observe for LiveData, because this is one of the common mistakes and you can read more here
  • lifecycleScope.launchWhenStarted –be sure your code will be execute after the Fragment is started

Pretty much that’s all about the code, now you just need to run your application and see how everything works asynchronously and well.

 

Conclusion

When I start my career as an Android Developer to create a simple application like this with so less code was impossible, but now these days everything helps you and gives you more time which you can spend on your project architecture and app idea instead of tapping code. The future is bright 🙂

Hope you enjoy and don’t forget to clap here in the original post 😉

Share:

Recent Posts

Android REST App with less than 100 lines of code

26 August, 2019 | by bytesandminds

How to create and get startup ideas!

22 August, 2019 | by bytesandminds

Bytes&Minds goes Startup School.

16 July, 2019 | by bytesandminds