diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-08-22 00:54:33 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-08-22 00:54:33 +0000 |
| commit | 44b0aa44e065822818e8473bb8e49b0ca45c43c8 (patch) | |
| tree | f678dc1e43b7432daa009c777c6acbc7201c1f04 /app/src/main/java/org | |
| parent | 6373c34525fdac3a298ab5e0299080383b72aaf6 (diff) | |
Add a cancellable OkHttp Call.await() extension
execute() blocks the calling thread and ignores the coroutine it runs
in -- if that coroutine is cancelled (a screen torn down mid-save, a
WorkManager-stopped fetch), the network call keeps running to
completion regardless, tying up a thread/socket for nothing. enqueue()
plus invokeOnCancellation actually aborts the in-flight HTTP call.
Diffstat (limited to 'app/src/main/java/org')
| -rw-r--r-- | app/src/main/java/org/terst/feedreader/data/Net.kt | 27 |
1 files changed, 27 insertions, 0 deletions
diff --git a/app/src/main/java/org/terst/feedreader/data/Net.kt b/app/src/main/java/org/terst/feedreader/data/Net.kt index d3720a0..4d0c956 100644 --- a/app/src/main/java/org/terst/feedreader/data/Net.kt +++ b/app/src/main/java/org/terst/feedreader/data/Net.kt @@ -1,8 +1,35 @@ package org.terst.feedreader.data +import kotlinx.coroutines.suspendCancellableCoroutine +import okhttp3.Call +import okhttp3.Callback import okhttp3.OkHttpClient +import okhttp3.Response +import java.io.IOException +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException /** Shared OkHttp client -- one connection pool for the whole app. */ object Net { val client: OkHttpClient by lazy { OkHttpClient() } } + +// A plain call.execute() blocks the calling thread and knows nothing about the coroutine +// it's running inside -- if that coroutine gets cancelled (a screen torn down mid-save, a +// WorkManager-stopped fetch), the network call keeps right on running to completion +// regardless, tying up a thread/socket for work nothing is waiting on anymore. enqueue() +// registers real cancellation: cont.invokeOnCancellation { cancel() } actually aborts the +// in-flight HTTP call (closes the socket) instead of just abandoning the coroutine. +suspend fun Call.await(): Response = suspendCancellableCoroutine { cont -> + cont.invokeOnCancellation { cancel() } + enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + cont.resume(response) + } + + override fun onFailure(call: Call, e: IOException) { + if (cont.isCancelled) return + cont.resumeWithException(e) + } + }) +} |
