Android kotlin flow retrofit

Android Architecture: MVVM with Coroutines + Retrofit + Hilt + Kotlin Flow + Room

Nov 2, 2020 · 5 min read

W hen you are starting a new Android App the first thing you want is to have the best architecture for your App. Ideally, you would want your architecture to be built with the best development trends in Android.

The quest for the perfect architecture starts by researching and learning top architecture trends. As the MVVM being the officially recommended architecture, it is an ideal choice to make.

There are many articles on buildi n g MVVM architecture using LiveData, ViewModel, Room, Retrofit, Coroutines, Dagger, RxJava, repository pattern, and the single source of truth strategy, etc. But, when it comes to putting all pieces together, things get tricky.

The official Android Architecture blueprint provides excellent MVVM architecture samples. But, the samples don’t use any networking library(e.g. Retrofit) library and instead mocks the Remote Data sources.

Also, I came across this article on why you should not be using LivData in repositories ‘No more LiveData in your repository’. And the architecture blueprint samples use the LiveData in repositories.

Motivation

Ideally, you would want to build something very scalable yet very concise, easy to understand, and simple to implement. Thanks to the introduction of the new official members, Kotlin Coroutines, Kotlin Flow, and Android Hilt.

We will build an MVVM architecture using all these concepts. Let’s get started.

The best way to learn is to implement it. So, we will be building a sample app that uses the TMDB API to show a list of trending movies. The detail screen shows details about the selected movie.

You can find the complete source code of this sample project on GitHub.

devnarendra08/DemoTMDB

You can’t perform that action at this time. You signed in with another tab or window. You signed out in another tab or…

Let’s get started!

Model

We don’t need to create the Factory for our ListingViewModel. Hilt handles all the pain. Refer.

The listing screen observes the viewModel.movieList LiveData exposed by the ViewModel and feeds the data to the MovieAdapter to display.

Every response is wrapped inside the Result class, which holds the 3 different statuses of the response(SUCCESS, ERROR, LOADING).
The data property holds the success value in case of successful response and error and message properties in case of failure.

ViewModel

The Hilt will inject movieRepository dependency in the constructor.

Kotlin Coroutines makes it super easy to do the IO work. fetchMovies() launches a Coroutine in the viewModelScope provided by the ViewModel KTX library.
You don’t need to worry about canceling the operations when ViewModel goes away. The viewModelScope will manage everything for you. You can read more about Coroutines scopes and Structured concurrency here.

movieRepository.fetchTrendingMovies() returns the Flow object. The collect will be invoked when any value is emitted to the Flow. We will learn more about Flow in the next section.

Repository
The repository will be responsible to provide the data either from the Remote or Local data sources.

flow<> builder constructs the Flow object. The Flow exposes the data as a stream like RxJava. The flowOn(Dispatchers.IO) specifies the Coroutine context for the execution. The emit() will invoke the collect() in our ViewModel. Here we will emit 3 different values.

emit(fetchTrendingMoviesCached()) emits the cached values from the Room database data.
emit(Result.loading()) emits the loading state.
emit(result) emits the result from the API response.

Читайте также:  Ватсап для андроида установка

We will cache the data when the response is successful.

Note: The approach that we have used in this sample app is less complex and gives you control over the Loading status. But, If you really want a more clean Single Source of the Truth strategy for your data, you can easily do that by returning Flow from your Room Dao. The Room library already has nice support for this.

Remote Data Source
The remote data source will be responsible for fetching the data from the REST APIs.

The MovieRemoteDataSource uses the Retrofit library to fetch the data from the TMDB REST APIs. Hilt injects the required dependency in the constructor.

getResponse is the Higher-Order Kotlin function which accepts the Retrofit Service function as the method parameter and returns the Retrofit response wrapped inside Result class. This makes our code concise.

Retrofit already has Coroutine suspend function support. We just need to add the suspend keyword in our service interface.

Local Data Source: Room Dao
The local data source will be responsible for storing and fetching the data from the Room Database.

Hilt: Dependency Injection
The Hilt is built on top of the Dagger and it is very less boilerplate and it is part of the Jetpack libraries and easily integrates with other Jetpack libraries.

The only dependencies we need to construct is the Retrofit and the Room database. Which is pretty straight forward.

You can read more about using Hilt in your App from here.

That’s it. We are done!
You can find the complete source code of the sample project on GitHub.

devnarendra08/DemoTMDB

You can’t perform that action at this time. You signed in with another tab or window. You signed out in another tab or…

I haven’t implemented pagination in the listing screen to keep the sample app very small and simple to understand.

We returned everything as Flow from our Repository. But, if you just need one shot operation, then the same can be achieved by simply using the suspend function. You can learn more from here.
In our case, Flow helps us to emit the statuses along with the success and error response.

Disclaimer
We must first understand the core concept of any new approach or library before randomly putting everything together.

Summary

  • We learned how to put all new Android concepts together and make it work seamlessly.
  • We learned how we can use Kotlin Flow/suspend function to make your app concise and readable.
  • We learned how Hilt Dependency Injection makes your code less boilerplate and testable.
  • We learned how to use Retrofit with Coroutines and wrap the response with success, failure, and loading states.

Please let me know your valuable inputs in the comments.

I would appreciate Claps if you find this article useful. Your Claps will keep me motivated to continue doing the good work.

Источник

Pagination in Android with Paging 3, Retrofit and kotlin Flow

Haven’t you asked how does Facebook, Instagram, Twitter, Forbes, etc… let you “scroll infinitely” without reach a “end” of information in their apps? Wouldn’t you like to implement something like that?

This “endless scrolling” feature is commonly called “Pagination” and it’s nothing new. In a brief resume, pagination help you to load chunks of data associated with a “page” index.

Let’s assume you have 200 items to display in your RecyclerView. What you would do normally is just execute your request, get the response items and submit your list to your adapter. We already know that RecyclerView by it’s own is optimized for “recycle our views”. But do we really need to get those 200 items immediately? What if our user never reach the top 100, or top 50? The rest of the non displayed items are still keep on memory.

What pagination does (in conjunction with our API) is that it let us establish a page number, and how many items per page can we load. In that way, we can request for the next page of items only when we reach the bottom of our RecyclerView.

Читайте также:  Android apps that backup apps

Non library approach

Before paging 3, you could have implemented Pagination by adding some listeners to your RecyclerView and those listeners would be triggered when you reach the bottom of your list. There are some good samples about it, here is a video with a vey detailed explanation (it’s on Indi, but it is understandable anyways).

A real PRODUCTION ready example is on the Plaid app. Look at their InfinteScrollListener class.

Android Jetpack Paging 3 and Flow

Today you gonna learn how to implement Pagination by using paging 3 from the android jetpack libraries. For my surprise the codelab of Paging 3 was one of the most easiest I have ever done. Florina Muntenescu did a great job with each step of the codelab, go check it out and give it a try. If you want to go straight to the sample code, check this pull request and see step by step how I implement paging 3 to this project.

Источник

MVVM with Kotlin Coroutines and Retrofit [Example]

Coroutines are a neat new feature of the Kotlin language that allow us to write asynchronous code in a more idiomatic way. — This also means you can write asynchronous code the same way you would normally write synchronous code in your project.

Already, I have explained about MVVM in detail in my another post. Please check that for better understanding of MVVM. in this post, I am focusing on coroutines and retrofit working together.

The flow diagram for the coroutines with retrofit in viewModel.

Coroutines are helpful in two main problems,

  1. A long-running task that can block the main thread
  2. Main safety allows you to ensure that any suspend function can be called from the main thread

According to the Kotlin docs it is stated that coroutines are a lightweight alternative to threads.

“Coroutines provide a way to avoid blocking a thread and replace it with a cheaper and more controllable operation”

Before we begin I would like to briefly address the concept and the commonly used functions in Coroutine.

Coroutines build upon regular functions by adding two new operations. In addition to invoke (or call) and return, coroutines add suspend and resume.

  • suspend — pause the execution of the current coroutine, saving all local variables
  • resume — continue a suspended coroutine from the place it was paused

Suspend Function

A suspending function is just a regular Kotlin function with an additional suspend modifier which indicates that the function can suspend the execution of a coroutine.

You can only call suspend functions from other suspend functions, or by using a coroutine builder like launch to start a new coroutine.

We use call back functions when we get response from our Async task. Suspend and resume work together to replace callbacks.

To understand suspend functions, we should also know about provided dispatchers by Kotlin.

To specify where the coroutines should run, Kotlin provides three dispatchers that you can use:

  • Dispatchers.Main — Use this dispatcher to run a coroutine on the main Android thread. This should be used only for interacting with the UI and performing quick work. Examples include calling suspend functions, running Android UI framework operations, and updating LiveData objects.
  • Dispatchers.IO — This dispatcher is optimized to perform disk or network I/O outside of the main thread. Examples include using the Room component, reading from or writing to files, and running any network operations.
  • Dispatchers.Default — This dispatcher is optimized to perform CPU-intensive work outside of the main thread. Example use cases include sorting a list and parsing JSON.

Lets, see this with an example -> We are calling our api through coroutines. So, we use Dispatchers.IO.

When we call getAllMovies() suspend method, then it suspends our coroutine. The coroutine on the main thread will be resumed with the result as soon as the withContext block is complete.

Note: Using suspend doesn’t tell Kotlin to run a function on a background thread. It’s normal for suspend functions to operate on the main thread.

Launch and Async

launch and async are the most commonly used Coroutine builder.

launch – Launches new coroutine without blocking current thread and returns a reference to the coroutine as a Job . The coroutine is canceled when the resulting job is cancelled .

Читайте также:  Airpods для андроида подойдут

async – Creates new coroutine and returns its future result as an implementation of Deferred . The running coroutine is canceled when the resulting object is cancelled .

Take a look at this piece of code as an example.

From the example, the difference between launch and async is that async can return the future result which has a type of Deferred , and we can call await() function to the Deferred variable to get the result of the Coroutine while launch only executes the code in the block without returning the result.

Coroutine Scope

Coroutine Scope defines a scope for coroutines. Every coroutine builder (like launch, async, etc) is an extension on CoroutineScope. When the scope dies, the Coroutines inside will be out of the picture too. Fortunately, the Android lifecycle-viewmodel-ktx provides a really easy way to get a Coroutine Scope in the ViewModel. I will show you how to do so later.

Coroutines in your Android Project

To begin add the following library to your build.gradle file dependencies:

Note : You’ll also need to be on kotlin version 1.3 or better.

Making it work with Retrofit?

Retrofit is a type-safe HTTP client for Android and Java.

Starting from Retrofit 2.6.0 you no longer require the Call Adapter as Retrofit now includes built-in support for Kotlin suspend modifier on functions.

In order to begin, let’s add the retrofit dependencies into our app level build.gradle file:

Declaring our interface.

For this example I am using https://howtodoandroid.com/movielist.json api to get list of movies.

Observe the below snippet for our interface:

You may notice that instead of Call , we now have a function with the suspend modifier defined in our interface function.

According to Retrofit documentation this function will, behind the scenes behave as a normal Call.enqueue operation.

Also we wrap our response in a Response object to get metadata about our request response e.g. information like response code.

We no longer have to await() anymore as this is handled automatically! As with all networking on Android its done on the background. And this is a very clean way of doing so!

Building Retrofit Service

Our Retrofit instance will look like the following code snippet:

ViewModel with Coroutines

A CoroutineScope keeps track of all coroutines it creates. Therefore, if you cancel a scope, you cancel all coroutines it created. This is particularly important if you’re running coroutines in a ViewModel.

If your ViewModel is getting destroyed, all the asynchronous work that it might be doing must be stopped. Otherwise, you’ll waste resources and potentially leaking memory. If you consider that certain asynchronous work should persist after ViewModel destruction, it is because it should be done in a lower layer of your app’s architecture.

Add a CoroutineScope to your ViewModel by creating a new scope with a SupervisorJob that you cancel in onCleared() method. The coroutines created with that scope will live as long as the ViewModel is being used.

Coroutines and LiveData

LiveData is an observable value holder for UI and we are expected to be able to access the value from the main thread. With the release of livedata-2.1.0-alpha1, google provided the interoperability between LiveData and Coroutines.

Exception Handling in Kotlin Coroutines

If you consider the above example, you can see we are wrapping our code inside a try-catch exception. But, when we are working with coroutines we can handle an exception using a global coroutine exception handler called CoroutineExceptionHandler.

To use it, first, we create an exception handler in our ViewModel,

and then we attach the handler to the ViewModelScope.

So, our code looks like,

Kotlin Coroutines With Retrofit Example

Now, lets see the example of list movies using kotlin coroutines and retrofit.

Required Dependencies

Here are the things you need to add to your build.gradle

First, setup the retrofit service.

Next step is to setup the repository.

Setup the ViewModel,

Finally, in our MainActivity setup the viewmodel and call the getAllMovies() method of the viewModel.

Thanks for reading. checkout this example in GITHUB.

Источник

Оцените статью