Anko 的 uiThread 偶尔不会被触发
Anko's uiThread sporadically not fired
我目前正在使用 Anko 的 doAsync 来处理异步任务。
具体来说,我正在使用它来解析对 ArrayList 数据对象的响应 json,如下所示:
// Asynchronously parse server response
doAsync {
val itemlist = parseResponse(response)
uiThread {
Otto.INSTANCE.post(UpdateRedeemedVoucherViewsEvent(itemlist))
}
}
大多数时候,就像在 Google 像素 (Android 8.0.0) 上一样,它工作得很好。我的对象得到解析,Otto 总线事件 将发布到 ui 线程.
但在极少数情况下,此过程会失败。
到目前为止,我注意到 ui 线程调用不会在 Galaxy S5 Mini (Android 5.1.1) 上触发。虽然我的数据解析没有任何错误或异常,但 uiThread 括号中的代码片段不会被执行。
到目前为止,我无法确定此行为的任何原因。没有 logcat 日志,什么都没有。没有关于何时会出现此错误的方案。
有没有人遇到过与 kotlin 相同或相似的问题 and/or Anko?
更新:我自己找到了解决方案,请参阅下面我的回答以获得解释。
我遇到了同样的问题,这是因为后台发生了未捕获的异常。
用 try/catch 包围您的后台任务,您应该能够看到发生了什么。
doAsync {
try {
val itemlist = parseResponse(response)
} catch(t: Throwable) {
//TODO log your exception
]
uiThread {
Otto.INSTANCE.post(UpdateRedeemedVoucherViewsEvent(itemlist))
}
}
谢谢你们的帮助。
我自己弄明白了,所以我发布这个答案以防万一其他人遇到这个问题。
TL;DR: context 丢失,所以 uiThread 不会被执行
解决方法:
我偶然发现了这个 post,其中提到了 uiThread 方法的一个重要特征:
Basically you have an async function that will execute it’s code in another thread, and will give the chance of returning main thread using uiThread. async is an extension function implemented for Context, and will use a weak reference of it, so it won’t prevent GC from releasing its memory.
经过进一步调查,我在解析完成后发现了以下日志,并且 uiThread 应该被调用的位置:
I/art: Background partial concurrent mark sweep GC freed 30879(16MB) AllocSpace objects, 16(2MB) LOS objects, 40% free, 16MB/27MB, paused 2.123ms total 196.372ms
所以看起来确实有一些 GC 操作,可能会也可能不会释放 context。
为了防止这种情况,我正在使用 Ankos runOnUiThread,它可以在给定的上下文引用中被调用:
// Asynchronously parse server response
doAsync {
val itemlist = parseResponse(response)
context.runOnUiThread {
Otto.INSTANCE.post(UpdateRedeemedVoucherViewsEvent(itemlist))
}
}
据我所知,这似乎已经成功了。
我目前正在使用 Anko 的 doAsync 来处理异步任务。 具体来说,我正在使用它来解析对 ArrayList 数据对象的响应 json,如下所示:
// Asynchronously parse server response
doAsync {
val itemlist = parseResponse(response)
uiThread {
Otto.INSTANCE.post(UpdateRedeemedVoucherViewsEvent(itemlist))
}
}
大多数时候,就像在 Google 像素 (Android 8.0.0) 上一样,它工作得很好。我的对象得到解析,Otto 总线事件 将发布到 ui 线程.
但在极少数情况下,此过程会失败。 到目前为止,我注意到 ui 线程调用不会在 Galaxy S5 Mini (Android 5.1.1) 上触发。虽然我的数据解析没有任何错误或异常,但 uiThread 括号中的代码片段不会被执行。
到目前为止,我无法确定此行为的任何原因。没有 logcat 日志,什么都没有。没有关于何时会出现此错误的方案。
有没有人遇到过与 kotlin 相同或相似的问题 and/or Anko?
更新:我自己找到了解决方案,请参阅下面我的回答以获得解释。
我遇到了同样的问题,这是因为后台发生了未捕获的异常。
用 try/catch 包围您的后台任务,您应该能够看到发生了什么。
doAsync {
try {
val itemlist = parseResponse(response)
} catch(t: Throwable) {
//TODO log your exception
]
uiThread {
Otto.INSTANCE.post(UpdateRedeemedVoucherViewsEvent(itemlist))
}
}
谢谢你们的帮助。 我自己弄明白了,所以我发布这个答案以防万一其他人遇到这个问题。
TL;DR: context 丢失,所以 uiThread 不会被执行
解决方法: 我偶然发现了这个 post,其中提到了 uiThread 方法的一个重要特征:
Basically you have an async function that will execute it’s code in another thread, and will give the chance of returning main thread using uiThread. async is an extension function implemented for Context, and will use a weak reference of it, so it won’t prevent GC from releasing its memory.
经过进一步调查,我在解析完成后发现了以下日志,并且 uiThread 应该被调用的位置:
I/art: Background partial concurrent mark sweep GC freed 30879(16MB) AllocSpace objects, 16(2MB) LOS objects, 40% free, 16MB/27MB, paused 2.123ms total 196.372ms
所以看起来确实有一些 GC 操作,可能会也可能不会释放 context。
为了防止这种情况,我正在使用 Ankos runOnUiThread,它可以在给定的上下文引用中被调用:
// Asynchronously parse server response
doAsync {
val itemlist = parseResponse(response)
context.runOnUiThread {
Otto.INSTANCE.post(UpdateRedeemedVoucherViewsEvent(itemlist))
}
}
据我所知,这似乎已经成功了。