同步测试线程、UI线程和CursorLoader线程

Posted

技术标签:

【中文标题】同步测试线程、UI线程和CursorLoader线程【英文标题】:Synchronize testing thread, UI thread, and CursorLoader thread 【发布时间】:2015-08-29 19:29:04 【问题描述】:

我的理解是,android 插桩 JUnit 测试在它们自己的线程上运行,除非使用 @UiThread 注释或调用 Instrumentation.runOnMainSync()Activity.runOnUiThread()。现在我正在尝试使用CursorLoader 来访问我的应用程序的数据库并填充ListView。我还有一个测试可以验证 ListView 是否正确填充。

我的问题是我需要同步三个线程:测试线程应该等到CursorLoader 线程完成并通知UI 线程填充ListView。为了创建CursorLoader,我在LoaderManager 支持下注册了LoaderCallbacks,并在onCreateLoader() 中创建实例。然后onLoadFinished()改变ListView的适配器的光标。

现在我需要确保我的测试等到onLoadFinish() 被调用后,才能尝试访问ListView 的子视图。我目前的想法是在测试可以调用的LoaderCallbacks 实现中添加一个waitForData() 方法。但是,我不确定如何实现此方法。我可以简单地使用wait(),然后在onLoadFinished() 中使用notifyAll() 吗?还是我需要使用更复杂的东西,比如Semaphore

【问题讨论】:

【参考方案1】:

您在如何做这件事上走在正确的轨道上。一般的方法确实只是阻塞主测试线程,直到工作线程完成。这是一个使用ConcurrentUnit的示例:

final Waiter waiter = new Waiter();

LoaderManager.LoaderCallbacks callbacks = new LoaderManager.LoaderCallbacks() 
  public void onLoadFinished(Loader<D> loader, D data) 
    waiter.assertEquals(someValue, "foo");
    waiter.resume();
  

  //...
;


// register callbacks...

waiter.await(5000); // wait 5 seconds for resume

【讨论】:

感谢您回答我的问题。对不起,我没有早点回复。我有一个问题:SessionStatus 是什么? @Code-Apprentice 如果我记得的话,这只是 android API 的一部分。唯一与测试相关的位是使用Waiter,它允许您的测试等到您准备好恢复,这可能是在收到一些回调之后。 谷歌搜索“android SessionStatus”不会对 Android API 文档产生影响,因此我得出结论,这是特定于该示例来自何处的自定义类。我也不确定如何将它融入我现有的应用程序和测试框架。 SessionListener 是否与应用程序代码本身或测试一起使用? Waiter 在哪里声明?我在哪里打电话waiter.await()?你能提供一个更完整的例子吗? @Code-Apprentice 我不记得这个例子是从哪里来的,但是因为它会分散注意力,所以这里有一个更新的例子。它未经测试,但基本要点仍然存在。在您的单元测试中,创建一个 Waiter。调用 Waiter.await 来阻止测试。然后,当您准备好取消阻止测试时,从您的回调中调用 Waiter.resume。这是适用于测试任何异步代码的基本模式,无论 API 是什么样的。 感谢您最新评论中的回答和描述。有机会我会去看看。【参考方案2】:

Espresso 处理这种类型的同步。我还没有使用它来弄清楚细节,但它看起来很有希望。

【讨论】:

以上是关于同步测试线程、UI线程和CursorLoader线程的主要内容,如果未能解决你的问题,请参考以下文章

访问 List 项时 UI 和 Worker 线程同步

使用 CursorLoader 查询 SQLite DB 并填充 AutoCompleteTextView

qt 线程与ui线程同步

为啥不等待 Task.Run() 同步回 UI 线程/原始上下文?

同步线程 - 没有 UI

理解SynchronizationContext,如何在Winform里面跨线程访问UI控件