Always bind coroutine scopes to appropriate lifecycles and follow consistent patterns for asynchronous operations. Prefer suspending functions over class-based approaches when possible, and ensure proper job cancellation to prevent memory leaks.
Always bind coroutine scopes to appropriate lifecycles and follow consistent patterns for asynchronous operations. Prefer suspending functions over class-based approaches when possible, and ensure proper job cancellation to prevent memory leaks.
For internal Kotlin code without Java interoperability requirements:
// Preferred: suspending function approach
suspend fun requestLocalUrl(url: String): ByteArray? = withContext(Dispatchers.IO) {
loadFile(...)
}
// Instead of class-based approach with callback
class RequestTask(private val scope: CoroutineScope, private val onCompletion: ((ByteArray?) -> Unit)?) {
fun execute(url: String) {
scope.launch(Dispatchers.IO) { ... }
}
}
When a class-based approach is necessary:
class AsyncOperation(lifecycleOwner: LifecycleOwner) {
// Scope tied to lifecycle
private val scope = lifecycleOwner.lifecycleScope
fun execute(): Job = scope.launch(Dispatchers.IO) {
// Work here
}
// Or with SupervisorJob for managing multiple concurrent tasks
private val job = SupervisorJob()
private val scope = CoroutineScope(Dispatchers.IO + job)
fun cancel() {
job.cancel() // Cancels all child jobs
}
}
For any asynchronous work, maintain consistency by using coroutines with appropriate dispatchers rather than raw threads.
Enter the URL of a public GitHub repository