tools:
借助 XML,当实际数据不可用时,我们可以选择使用占位符进行设计。Jetpack Compose 中有类似的东西吗?
我知道我可以通过专用预览功能将示例数据传递到我的可组合项。但例如,当图像源是一个 URL(通过 Coil、Glide.. 加载)时,即使我传递了示例 URL,它也无法在预览中加载。一个实用的解决方案可以节省开发时间。
我正在尝试使用 FragmentScenario 测试片段。这个片段有自己的菜单。操作栏上有一个添加图标,单击此菜单项会启动一个子片段,用户可以从中添加新项目。所以我试图测试这种行为。但是,您可能知道,FragmentScenario 在 EmptyFragmentActivity 中启动片段,而不启动真正的宿主活动。由于操作栏不是片段布局的一部分,而是属于宿主活动,因此在测试期间操作栏和菜单甚至不可见。那么如何测试与菜单的交互呢?
我从官方文档中找到了这条信息:
如果您需要调用片段本身的方法,例如响应选项菜单中的选择,您可以通过实现 FragmentAction 安全地执行此操作:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEventFragment() {
val scenario = launchFragmentInContainer<MyFragment>()
scenario.onFragment(fragment ->
fragment.onOptionsItemSelected(clickedItem) {
//Update fragment's state based on selected item.
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是,如何将正确的项目传递给 onOptionsItemSelected 回调?我试图将 addMenuItem 定义为成员变量并在 onCreateOptionsMenu 内部对其进行初始化,但它返回 null。在测试期间似乎没有调用 onCreateOptionsMenu。所以我不知道如何测试用户与菜单的交互。
我在 suspendCancellableCoroutine 中包装了一个回调,将其转换为挂起函数:
suspend fun TextToSpeech.speakAndWait(text: String) : Boolean {
val uniqueUtteranceId = getUniqueUtteranceId(text)
speak(text, TextToSpeech.QUEUE_FLUSH, null, uniqueUtteranceId)
return suspendCancellableCoroutine { continuation ->
this.setOnUtteranceProgressListener(object : JeLisUtteranceProgressListener() {
override fun onDone(utteranceId: String?) {
if(utteranceId == uniqueUtteranceId) {
Timber.d("word is read, resuming with the next word")
continuation.resume(true)
}
}
})
}
}
Run Code Online (Sandbox Code Playgroud)
我使用片段的生命周期作用域协程范围调用此函数,并且我假设在片段被销毁时它被取消。然而,LeakCanary 报告说,由于这个监听器,我的片段正在泄漏,并且我通过日志验证了即使在协程被取消之后,回调仍然被调用。
所以看来用 suspendCancellableCoroutine 而不是 suspendCoroutine 包装不足以取消回调。我想我应该主动检查该作业是否处于活动状态,但是如何呢?我尝试coroutineContext.ensureActive()
检查coroutineContext.isActive
回调内部,但 IDE 给出错误,指出“只能在协程体内调用暂停函数”。我还能做些什么来确保作业被取消时它不会恢复?
我需要在自定义视图中使用协程。看完这个演讲,我相信我最好的选择是使用lifecycleScope作为协程范围,这样当lifecycleowner被销毁时它会自动取消。
但是我似乎无法访问自定义视图中的生命周期范围。根据文档,我们可以从生命周期对象 aslifecycle.coroutineScope
或从生命周期所有者as访问它lifecycleOwner.lifecycleScope
。但是自定义视图不是生命周期所有者。那么我可以以某种方式访问片段的生命周期范围吗?或者如果我不能,我应该使用哪个协程上下文?
android android-custom-view kotlin-coroutines coroutinescope