How to create Asynchronous Call using Retrofit and Observables in Kotlin? - android

I want to make API calls using Retrofit2 library, returns generic type observable.
I am getting an error: android.os.NetworkOnMainThreadException, while making calls.

Looks really easy to solve, two cases to consider. :1)If you are not using RXJava or 2) if you are using it
1) If you are NOT using RXJava
You should use the method enqueue when you make the call. The error you get is because you are calling the response on the same Thread(the MainThread)
Here is an example took from the web that uses Enqueue with Kotlin that possibly you can adapt to your case
override fun loadPokemonList(pokemonListListener: PokemonListListener) {
call = pokemonService.getPokedex();
call.enqueue(object : Callback<PokeDex> {
override fun onResponse(call: Call<PokeDex>?, response: Response<PokeDex>?) {
if (response != null && response.isSuccessful) {
pokemonListListener.onSuccess(response.body())
} else {
pokemonListListener.onFailure(appContext.getString(R.string.error_fetching_data))
}
}
override fun onFailure(call: Call<PokeDex>?, t: Throwable?) {
pokemonListListener.onFailure(appContext.getString(R.string.error_fetching_data))
}
})
}
2) If you are using RXJava(usually version 2, be aware you will find several tutorials for the first version online)
But please consider that most of the developers today solve this asynchronous call using RXJava2 that is the second case I was mentioning at the beginning of he post. It will take you several hours to understand the basics of it but once you will do, you will have a great skill to bring with you and manage this kind of calls( even multiple ones) will be really simple. In fact RXJava allows you really easy to direct the operation in a concurrent Thread and observe the result on the Main Thread. Here a good tutorial that explains how to do that
with the easy and well known pattern (see the notations)
Observable<List<TrendsResponse>>
.subscribeOn(Schedulers.io())//Run the call on another Thread
.observeOn(AndroidSchedulers.mainThread())//observe on the Main Thread
.subscribe();
Differently by what people new to RXJava think:
on default RXJava does not call a concurrent Thread, is up to you to do that with the subcribeOn that does all the "dirty" work and then to observe the result on the Main Thread with ObserveOn.
For principiants is easy to grasp that comparing both of them to the two famous methods of AsyncTask: doInBackground and onPostExecute
EDIT: Please look also this post if you or future users have problems.

With Retrofit/RxJava, the network call will be default be performed on the thread that subscribes to the Observable returned from the stub. On Android, we are normally executing on the "main" thread, and it is not permitted to access the network on this thread, hence the error.
The solution is to tell RxJava to subscribe to the Observable on a different thread:
getDataFromAPI(/*...*/)
.subscribeOn(Schedulers.io())
.observerOn(AndroidSchedulers.mainThread())
.subscribe({ /* result available in `it` */ })
Schedulers.io() is a reference to a scheduler that uses a set of threads specifically intended to be used for IO operations.
The .observeOn allows you to handle the result safely back on the main thread.

Related

How to make a flow run on a different thread than the one used for collection?

I have a flow that does CPU intensive work as shown below:
fun doWork():Flow<MyResult> =
flow{
for(i in 1..100){
//calculate()
}
emit(MyResult())
}
I collect from it inside a Fragment as shown below:
viewLifecycleOwner.lifecycleScope.launchWhenCreated {
launch {
viewModel.doWork().collect {
val result = it ?: return#collect
// Preview result
}
}
}
But, since I am collecting using the main thread, the flow body runs on the main thread which is not the best thing to do.
How can I make the flow execute on a different thread?
In case you intend to do heavy calculations inside a flow it is recommended to move it to the default dispatcher like so,
flow{
//CPU intensive work
}.flowOn(your chosen dispatcher)
Libraries like the Room database and retrofit for networking handle the correct threading under the hood for you, so you do not have to worry about using .flowOn
Using withContext() inside a flow will not work for you.
This link is also very useful if you want to know more about asynchronous Flow.

Get Value from Object to Activity/Fragment in Kotlin [duplicate]

I'm writting my first app in Kotlin, so I'm pretty new to this. One of the functions it performs is to read something from an API, and then update the screen based on the result.
I have tried lots of things with the coroutines, but nothing seems to work.
For example, I have something like this:
private fun readAPI() {
runBlocking {
fun rAPI() = async {
val api = "..."
result = URL(api).readText()
}
println(tag, "Result: " + rAPI().await())
}
}
And lots of different approaches. Nothing seems to work. In the above case I'm getting an exception "android.os.NetworkOnMainThreadException".
The only thig that has worked so far, is something using OkHttp3 as described here: https://rstopup.com/como-hacer-una-solicitud-a-la-api-de-kotlin.html (it's in Spanish, but you'll get the idea), and this works, it brings the API response, I parse it, fill in my sqlite3 database and so on. But, since I don't know when the API ends, I can't update the screen controls. And if I try to do it serially, I get an exception that only the thread which started the activity is the one that can update the activity or something like that.
I've seen, and follow LOTS of tutorials that talks about suspend functions, launch, etc., and they try to mimick an API call with delay(), those tutorials work perfectly, until I try to do a real API call.
So, can you point me to a full example on how to call an API with Kotlin, and then update some screen elements?
EDIT
I'm editing changing the fun by val:
runBlocking {
val rAPI = async {
val api = "..."
URL(api).readText()
}
Log.w(tag, rAPI.await())
}
I got the "android.os.NetworkOnMainThreadException" exception.
Since you want to use coroutine-async ways, you must tell main thread to waiting for you. you need to use suspend function or block to do this.
GlobalScope.launch {
suspend {
Log.d("coroutineScope", "#runs on ${Thread.currentThread().name}")
delay(10000)
withContext(Dispatchers.Main) {
Log.d("coroutineScope", "#runs on ${Thread.currentThread().name}")
}
}.invoke()
}
result log
09:36:09.500 D/: #runs on DefaultDispatcher-worker-1
// 10 seconds later
09:36:19.678 D/: #runs on main
I think this should do the trick.
However I suggest you to understand how to use OkHttp/Volley by passing callbacks(with onSuccess and onFail or something) into that.
Or Retrofit2 with RxJavato handle many of these issues.
EDIT
For the Module with the Main dispatcher had failed to initialize error, replace the withContext() line with this
withContext(Handler(Looper.getMainLooper()).asCoroutineDispatcher())
EDIT
Now don't use RxJava, use liveData/LiveEvent to implement the observer pattern
In Kotlin you can convert callbacks to coroutines as described in this codelab https://codelabs.developers.google.com/codelabs/kotlin-coroutines/#6

When to use Kotlin Coroutines to optimize code performance

Currently, I am experimenting a bit with kotlin coroutines and I asked myself a question: Is there any significant performance gain when using coroutines? Let's look at some (theoretical) examples:
Example one
val myUnsortedList = listOf(1, 2, 5, 6, 3, 10, 100)
fun doStuffWithSorted(list: List<Int>) { ... }
// Without coroutine
val sortedList = myUnsortedList.sorted()
doStuffWithSorted(sortedList)
coroutineScope {
launch {
val sortedList = myUnsortedList.sorted()
doStuffWithSorted(sortedList)
}
}
Example two
fun doSomeHeavyOperations() { // doing heavy Operations but non blocking }
fun main() { doSomeHeavyOperations() }
//////////////// VERSUS //////////////////////
suspend fun doSomeHeavyOperations() { // doing heavy Operations but non blocking }
suspend fun main() {
coroutineScope {
launch {
doSomeHeavyOperations()
}
}
}
There are many more examples and maybe one of you could give some, where using coroutines is recommended. So my final question is (including the question above): When should it be considered to optimize the code performance with coroutines, and when is the expense bigger than the gained performance?
Coroutines are primarily a tool for computations that involve a lot of waiting, think about network calls executed in sync. in those cases the calling thread does nothing but wait for the server's response.
to remove this waiting issue we use async programming, AKA callbacks. so you start a network call and specify a callback which will be invoked once the result is ready. but the callback model has its own issues, the callback hell, as in below code.
fun someAPICalls(){
getToken(){ token ->
login(token) { userID ->
getUser(userID){ user ->
// Save user in DB
// This nesting can be even deeper
}
}
}
}
As you can see this code is not something that can be considered manageable. with kotlin's suspending functions, all this reduces to
fun someAPICalls() = viewModelScope.launch{
val token = getToken() // suspending function calls (Retrofit, Room)
val userId = login(token)
val user = getUser(userId)
}
As you can see, this is very close to how sequential code is written.
Even though there are other options(RX etc) available to solve the callbacks issue, they do introduce their own semantics which you need to learn. on the other hand writing coroutines code is not that different from its sequntial counterpart, you only have to learn a few basic constructs(Dispatchers, Builders etc), and this is something that makes coroutines the best choice in this scenario.
Apart from this there are some other scenarios where coroutines can be used effectively, one such use case is the practice of thread offloading used in UI frameworks such as Android. when you want to execute a long running CPU bound operation, you don't do it on UI thread, instead you offload the operation to a background thread. this can also be acomplished very cleanly using one of the couroutines builder such as lifecycleScope.launch(Dispatchers.Default) {}
Where coroutines should be avoided?
Coroutine is an abstraction above thread, its something that requires a thread to execute in same way as a thread requires a CPU core to execute. because of this there is certain overhead introduced by the coroutine managment, so if you need to perform a long running CPU bound operation which may require use of multiple threads, you are better off using threads (Java ExecutorService etc.).

Editing data in repository pattern using RxJava

I'm refactoring the implementation of my repositories using RxJava so i want to know some ways to edit, for example, a user.
My getUser(email: String), with email as id, is returning an observable and in the repository implementation i either get the data from database or server, all good by now.
What i want to achieve is editing a user. For that i would have and update(user: User) function, and the naive way to use it would be
userRepository.getUser(email)
.subscribeOn(Schedulers.io())
.subscribe { user ->
user.name = "antoher name"
userRepository.update(user)
.subscribeOn(Schedulers.io())
.subscribe {
//handle response
}
}
Is there a way to avoid this type of call of an observer inside an observer? It is not very readable for me and i guess there's a better way but i'm not getting it.
NOTE: I'm using clean architecture, so i think an update for every field, making me get user in data module is not correct as i would have subscribe to an observer in data, and that difficult the dispose when activity destroys
For me is not the same question as When do you use map vs flatMap in RxJava? because, despite of flatMap being the thing that answer the question, it is not the same question, so anyone who has the same problem/question but don't know that flatmap is the answer, will never reach to use flatmap.
One strength of using RxJava is that you can chain as many async operations (method that would return Observable or Single, repository methods in your case) as you want without falling into callback hells. You see in your code that there are nested subscribe blocks. What if you had to chain more async network operations? You fall into callback hells and the code will become harder to follow and maintain.
Removing nested callbacks and making code more functional, compositional, and readable is one thing RxJava is really good at. In the intro part of ReactiveX website , they mention about this in the intro part of ReactiveX website (http://reactivex.io/intro.html).
Callbacks solve the problem of premature blocking on Future.get() by
not allowing anything to block. They are naturally efficient because
they execute when the response is ready.
But as with Futures, while callbacks are easy to use with a single
level of asynchronous execution, with nested composition they become
unwieldy.
Flatmap operator is to the rescue here. You can look into the definition of flatMap operator in the link below.
http://reactivex.io/documentation/operators/flatmap.html
Below is the code I would use in your case.
userRepository.getUser(email)
.subscribeOn(Schedulers.io())
.map { user -> user.name = "another name"; return user; }
.flatMap { user -> userRepository.update(user) }
.doOnSuccess { /* handle response here */ } // doOnNext if you are using observable
.subscribe({ /* or handle response here */ }, { /* must handle error here */})
Flatmap operator flattens Single of update response which will be returned by your repository's update method and pass just the response downstream. Above code is not only easier to read but also makes your code reusable because update logic is now part of the chain.
Distinguishing between map and flatMap is really important in exploiting the full benefit of RxJava so it will be really beneficial to get used to it!

Starting an asynchronous operation using RxJava without subscribing to an observable?

Let's say your DAO has this method that updates user records in the DB:
#Update
fun update(user: User): Single<Int>
Recently I started learning RxJava and so far I have seen lots examples like following:
// Example 1
disposable.add(dao.updateUser(user)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
Log.d(TAG, "response received")
}
In the above example, I understand that as soon as the subscription starts, updateUser() will be executed on a worker thread and the subscriber will be notified and run in the main thread once the execution completes.
But what if you are not interested in the result of updateUser(), and all you want is just to execute updateUser() on a worker thread?
So far I have tried doing:
// Example 2
dao.updateUser(user)
or
// Example 3
dao.updateUser(user).subscribeOn(Schedulers.io())
But they didn't work. It seems the update requests are never executed, nothing was logged and records didn't change. I am guessing that's because there isn't any subscriber attached to it.
For now I am forcing it to work by attaching a random subscriber that doesn't really do anything like the one in Example 1. One of the problems with the approach is that I might need to make this request a lot and that might create a lot of dummy subscribers, not to mention that the code looks really bad.
Could you help me find a better way of handling this?
But You already wrote answer for Your question.
You can just call:
dao.updateUser(user).subscribe()
If You want manipulate / jump between thread you are doing something like in Example 1.

Categories

Resources