Skip to content

Instantly share code, notes, and snippets.

@pksokolowski
Created November 21, 2019 02:24
Show Gist options
  • Save pksokolowski/84b0514fd3bf3ce5c661f076f93520aa to your computer and use it in GitHub Desktop.
Save pksokolowski/84b0514fd3bf3ce5c661f076f93520aa to your computer and use it in GitHub Desktop.
A helper reducing repeated code with network calls made using coroutines. Along with a usage sample.
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import javax.inject.Inject
/**
* A component handling ongoing background/long running tasks.
* It is not app-wide in and out of itself, so various components
* might have their own instances of it and their own counters consequently.
*/
class OngoingTasksTracker @Inject constructor() {
private val isAnyTaskInProgress = MutableLiveData<Boolean>()
fun areThereOngoingTasks() = isAnyTaskInProgress as LiveData<Boolean>
private var ongoingTasks = 0
fun startOne() {
if (++ongoingTasks > 0) isAnyTaskInProgress.value = true
}
fun endOne() {
if (--ongoingTasks == 0) isAnyTaskInProgress.value = false
}
}
import com.github.pksokolowski.posty.di.PerApp
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject
@PerApp
class RequestRunner @Inject constructor(private val ongoingTasksTracker: OngoingTasksTracker) {
fun <R> run(
body: (suspend () -> R),
onException: (e: Exception) -> Unit,
onSuccess: (r: R) -> Unit
) {
ongoingTasksTracker.startOne()
GlobalScope.launch {
try {
val result = body.invoke()
withContext(Dispatchers.Main) {
ongoingTasksTracker.endOne()
onSuccess.invoke(result)
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
ongoingTasksTracker.endOne()
onException.invoke(e)
}
}
}
}
fun areThereAnyOngoingRequests() = ongoingTasksTracker.areThereOngoingTasks()
}
class MainViewModel @Inject constructor(
private val service: JsonPlaceholderService,
private val requestRunner: RequestRunner
) : ViewModel() {
private val posts = MutableLiveData<List<Post>>().apply { value = listOf() }
fun getPosts() = posts as LiveData<List<Post>>
fun isDownloadInProgress() = requestRunner.areThereAnyOngoingRequests()
private val status = MutableLiveData<Status>()
fun getStatus() = status as LiveData<Status>
fun refreshPosts() = requestRunner.run(
{ service.getPosts() },
{
status.value = ERROR(R.string.status_offline)
},
{
posts.value = it
status.value = OK
}
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment