hey, i am currently playing around with jetpack co...
# android
c
hey, i am currently playing around with jetpack compose on android. since my experience with android is very beginner level (tbh i am a jvm backend developer trying to write my first android app 😄)  i am wondering how to avoid 
android.os.NetworkOnMainThreadException
i already figured out this is because i just call an http client (which is blocking) in the main activity (main/ui thread) as you can see on the screenshot. what do i need to do to make my http call with my client of choice work? stackoverflow was saying something about AsyncTasks but the answers has been very old and looked pretty different from my jetpack compose code 😄 I found solutions like: https://stackoverflow.com/a/13136668/10562333 that would just deactivate the restriction but that feels wrong to me. From what I understood so far I would need to do the call in a background thread instead of the main thread. Can I do this by wrapping my call in a coroutine and if so how? What would be the state of the art way to tackle this problem? (bearbeitet)
f
Erm, AsyncTask is quite old solution
You could use Retrofit, KTOR + Kotlin Coroutines or RxJava
for example
google KTOR client with coroutines it would be my bet
c
i would need a solution that is client independent since i want to use some 3rd party library that is doing http requests later on (which is not build on top of a non-blocking client or coroutines). can i wrap that call in a coroutine on my own, save the response in some kind of state and just render it on change? (this is how i would do things in the web)
f
yup, use coroutines with coroutineScope.launch/async(Dispatchers.IO){ }
also use ViewModel or other patter that you would like to use
https://ktor.io/docs/client.html <-- you can use it in Android, Multiplatform and Native
imho best solution
i used it in Linux, Android and iOS app
c
just to make sure i understood it correctly, i need to implement the following flow: • fetch data from somewhere, wrapped by a coroutine • store the response in some kind of state object • rerender if state has changed do you know where i can find a minimal example that tackles this specific use-case?
f
I didn't do Compose that much 😉 but there are plenty of exmaples over internet
Copy code
class API(){
    private val client = HttpClient() {
        install(JsonFeature) {
            serializer = KotlinxSerializer()
        }
        install(HttpTimeout) {
            requestTimeoutMillis = 30000
        }
}
    fun checkIfInternetAvailable() = GlobalScope.async {
        try {
            val response = client.get<HttpResponse> {
                url("<https://www.google.com>")
                timeout {
                    // timeout config
                    requestTimeoutMillis = 2000
                }
            }
            response.status.value in 200..299
        } catch (e: Exception) {
            false
        }
    }
}
Here is simple check if internet is available by checking out any url (in this case google) using ktor. This is how simple is to use ktor to make calls
z
1. I wouldn't ping the home page of google. At least perform a HEAD request to
<https://www.gstatic.com/generate_204>
. 2. You don't really need to do this. You can also perform an API call to your API and depending on the callback there decide if you want to show a "no internet" dialog 3. What if the user can't connect to Google (Google is blocked in some countries) but can connect to your API. Why would you want to refuse the user access? @felislynx
f
Dude this is example of how to use ktor
z
It’s usually a smell for your composables to be making network requests themselves. Typically network calls should be managed by a higher-level layer in your architectural stack, as @felislynx suggested (e.g. ViewModel, Presenter, Repository, etc.). Those components should have their own coroutine scopes that they can use to launch requests as required, and have some mechanism for processing responses (e.g. using a
MutableStateFlow
or
LiveData
. Typically you don’t store or expose the network response directly, but some higher-level data derived from it. Eventually, that’s what your composable consumes, e.g. via
collectAsState
or
observeAsState
, and those
*asState
functions will make sure your composable updates when the data from your higher layers change.
👍 1