You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Wear Tile刷新抛出CancellationException崩溃如何排查

问题根因

这个偶现崩溃的本质是协程取消异常未被拦截导致的:

  1. 你当前使用自定义的独立CoroutineScope(serviceScope)执行Tile刷新逻辑,这个作用域和Tile请求生命周期、TileService生命周期完全解绑
  2. 当系统发起Tile刷新请求后,如果协程执行完成前请求被终止(常见场景:用户滑走Tile离开可视区域、TileService被系统回收、新的刷新请求覆盖旧请求、请求耗时超过系统10秒默认超时窗口),系统会取消对应请求任务
  3. kotlinx-coroutines-guava的future构建器会在协程被取消时,向返回的ListenableFuture传递CancellationException,而Wear Tiles库的TileProviderWrapper在主线程读取Future结果时没有捕获该类取消异常,异常直接抛到主线程触发崩溃,和你提供的堆栈调用链完全匹配。
排查方向
  • 场景复现验证:手动连续多次滑动到目标Tile再快速滑走,同时在Logcat过滤onTileRemove/onDestroy生命周期日志和JobCancellationException日志,确认崩溃是否和Tile离开可视区域、Service销毁的时间点重合
  • 协程状态校验:在协程块开始、网络请求前后打印coroutineContext[Job]?.isActive状态,确认崩溃发生时当前协程Job是否已经被取消,同时排查代码中是否存在手动调用serviceScope.cancel()的逻辑
  • 网络耗时排查:抓取网络请求日志,统计listUsersDevices接口的耗时分布,确认是否存在弱网下请求耗时超过10秒,触发系统超时取消请求的情况
  • 刷新逻辑校验:全局搜索requestUpdate调用点,确认是否存在短时间内多次触发Tile刷新,导致旧请求未完成就被新请求覆盖取消的问题
修复方案
  • 替换协程作用域:删除自定义的独立serviceScope,改用和TileService生命周期绑定的lifecycleScope,确保作用域随Service销毁自动取消,不会出现脱离生命周期的协程任务。注意需要引入Wear版本的lifecycle依赖:androidx.lifecycle:lifecycle-runtime-ktx
  • 增加异常拦截:在协程块内捕获CancellationException和其他业务/网络异常,异常发生时返回缓存的旧Tile或者默认占位Tile,避免异常穿透到框架层
  • 参考修复代码:
class WeatherTileService : TileService() {
    // 删除自定义的serviceScope
    override fun onTileRequest(requestParams: TileRequest) = lifecycleScope.future {
        Log.d("Tile", "Refreshing weather data")
        return@future try {
            val api = AmbientWeatherClient.getInstance()
            val devices = api.listUsersDevices(APP_KEY, API_KEY)
            // 原有Tile构建逻辑
            Tile.Builder()
                .setResourcesVersion(RESOURCES_VERSION)
                .setFreshnessIntervalMillis(5 * 60 * 1000)
                .setTimeline(/* 原有timeline构建逻辑 */)
                .build()
        } catch (e: CancellationException) {
            // 请求被系统取消是正常场景,直接返回缓存的Tile即可
            Log.d("Tile", "Tile request cancelled, use cached tile")
            getCachedTile()
        } catch (e: Exception) {
            // 捕获网络异常、数据解析异常等所有非取消异常
            Log.e("Tile", "Refresh tile failed", e)
            getDefaultErrorTile()
        }
    }

    // 实现本地缓存Tile、默认错误Tile的构建逻辑
    private fun getCachedTile(): Tile { /* 实现略 */ }
    private fun getDefaultErrorTile(): Tile { /* 实现略 */ }
}
  • 优化网络配置:给OkHttp配置合理的超时时间,将连接、读、写超时都设置在8秒以内,避免请求耗时过长触发系统超时取消
  • 增加本地缓存:每次刷新成功后将Tile数据持久化到本地,请求取消或失败时优先返回缓存内容,既避免崩溃,也能提升Tile加载速度

内容的提问来源于stack exchange,提问作者GDefender

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 22:06:25