Android Navigation Instrumentation 测试抛出方法 addObserver 必须在主线程上调用

Android Navigation Instrumentation test throws Method addObserver must be called on the main thread

我有两个片段,一个是我图表中的主片段。单击按钮后,用户将导航到第二个片段。它通过将用户导航到第二个片段并显示文本来按预期工作。所以图表很好。

现在我想写一个仪器测试。

@RunWith(AndroidJUnit4::class)
class TransitionTest {

    @Test
    fun testNavigationToSecondFragment() {
        
        val navController = TestNavHostController(
            ApplicationProvider.getApplicationContext())

        navController.setGraph(R.navigation.my_graph) <--throws exception

        // the rest of my test continues here
    }
}

但是,上面显示的设置图形的行抛出以下异常:

IllegalStateException: Method addObserver must be called on the main thread.

我的环境:

fragment_version = 1.2.5 nav_version = 2.3.1 espresso = 3.3.0

有谁知道发生了什么以及如何解决它?

我将 setGraph 函数包装在 runOnUiThread 中,测试通过。找到真正原因和更好的解决方案后,我会更新答案。

runOnUiThread {
    navController.setGraph(R.navigation.my_graph)
}

升级包后,我也开始遇到这个问题:

implementation 'androidx.activity:activity:1.2.0-alpha06'

 implementation 'androidx.activity:activity:1.2.0-beta01'

在我的代码中,我在后台线程中打开了一个片段,这似乎与新包有关。该片段在生命周期中添加了一个观察者:

我认为你在 UI 线程上包装对 运行 的调用是唯一可行的解​​决方案,因为在你的情况下也可以在内部添加观察者。

我遇到了同样的问题,所以我将尝试解释其根本原因。 从 androidx.lifecycle:lifecycle-*:2.3.0-alpha06 开始。 LifecycleRegistry 中有一个行为变化。 LifecycleRegistry now verifies that its methods are called on the main thread. Now remains another question unsolved whether the instrumentation tests are running in the MainThread? Apparently no otherwise it would have passed. It is using Instrumentation Thread where most of the tests run. As per documentation, you can use @UiThreadTest or runOnUiThread as in the top .

还有一种方法可以解决这个问题

InstrumentationRegistry.getInstrumentation().runOnMainSync {
            navController.setGraph(R.navigation.my_graph)
        }

由于 @UiThreadTest 仅适用于 @Test@Before@After,因此如果您有一些通用测试功能,它们可能无法按预期工作

当我的 com.google.gms:google-services 库与 appcompat 版本冲突时,我遇到了这个问题。当我将我的 appcompat 版本更改为以下

时,问题得到解决
implementation 'androidx.appcompat:appcompat:1.3.0'