网页加载完成后取消协程超时任务仍打日志,如何解决?
解决协程取消后仍输出超时日志的问题
问题原因
原代码在onPageFinished里通过launch调用cancelAndJoin(),会导致取消动作存在延迟。如果页面加载完成时,delay(5000)已经执行完毕,协程会跳过ensureActive()检查(此时协程仍处于活跃状态),直接输出超时日志,之后才完成取消操作,从而出现不符合预期的日志输出。
修复方案
1. 简化协程取消逻辑
在onPageFinished中直接调用cancel()(无需用launch包裹,也不需要cancelAndJoin()),因为cancel()是同步操作,会立即标记协程为取消状态,打断正在执行的delay:
override fun onPageFinished(view: WebView?, url: String?) { super.onPageFinished(view, url) logUtil.i(TAG, "Finished loading $url") // 直接取消协程,无需在新协程中执行 loadTimer?.cancel() }
2. 移除冗余的ensureActive()
delay()本身是可取消的挂起函数,当协程被取消时,delay()会立即抛出CancellationException终止协程,不会执行后续的日志代码。因此ensureActive()是多余的,可以移除:
override fun onStart() { super.onStart() loadTimer = launch { delay(TimeUnit.SECONDS.toMillis(5)) // 仅当协程未被取消(即超时)时才执行日志 logUtil.w(TAG, "Loading took longer than expected") } webView.loadUrl(url) }
3. 完善生命周期清理
为避免页面销毁后协程仍运行,建议在onDestroy中也取消协程:
override fun onDestroy() { super.onDestroy() loadTimer?.cancel() }
修复后逻辑
- 若页面在5秒内加载完成,
cancel()会立即打断delay(),协程终止,不会输出超时日志。 - 若页面加载超过5秒,
delay()执行完毕后输出超时日志。 - 页面销毁时主动取消协程,避免内存泄漏和无效日志。
内容的提问来源于stack exchange,提问作者tyczj
相关产品推荐
相关产品推荐

