From 44b0aa44e065822818e8473bb8e49b0ca45c43c8 Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Sat, 22 Aug 2026 00:54:33 +0000 Subject: 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. --- app/src/main/java/org/terst/feedreader/data/Net.kt | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'app/src/main/java/org/terst/feedreader') 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) + } + }) +} -- cgit v1.2.3