设置requestedOrientation导致Android测试崩溃问题求助
问题:Jetpack Compose应用横竖屏切换测试崩溃
我正在测试一款基于Kotlin和Jetpack Compose开发的Android应用,验证横竖屏切换等配置变更场景,但设置屏幕方向为横屏/竖屏时出现崩溃。以下是简化的测试代码、应用代码及崩溃日志:
测试代码
package com.example.sandbox import android.content.pm.ActivityInfo import androidx.compose.ui.test.ComposeTimeoutException import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.test.core.app.ActivityScenario import org.junit.Rule import org.junit.Test class MainActivityTest { @get:Rule val rule = createAndroidComposeRule<MainActivity>() private lateinit var scenario: ActivityScenario<MainActivity> @Test fun sandboxTest() { scenario = ActivityScenario.launch(MainActivity::class.java) rule.waitForIdle() rule.activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE } }
应用代码
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { SandBoxTheme { Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> Greeting( name = "Android", modifier = Modifier.padding(innerPadding) ) } } } } } @Composable fun Greeting(name: String, modifier: Modifier = Modifier) { Text( text = "Hello $name!" ) }
崩溃日志
java.lang.NullPointerException: Cannot run onActivity since Activity has been destroyed already at androidx.test.internal.util.Checks.checkNotNull(Checks.java:50) at androidx.test.core.app.ActivityScenario.lambda$onActivity$2$androidx-test-core-app-ActivityScenario(ActivityScenario.java:792) at androidx.test.core.app.ActivityScenario$$ExternalSyntheticLambda2.run(D8$$SyntheticClass:0) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:487) at java.util.concurrent.FutureTask.run(FutureTask.java:264) at android.app.Instrumentation$SyncRunnable.run(Instrumentation.java:2497) at android.os.Handler.handleCallback(Handler.java:984) at android.os.Handler.dispatchMessage(Handler.java:104) at android.os.Looper.loopOnce(Looper.java:238) at android.os.Looper.loop(Looper.java:357) at android.app.ActivityThread.main(ActivityThread.java:8149) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:957)
问题原因与修复方案
崩溃原因
同时使用createAndroidComposeRule和ActivityScenario.launch()会导致重复启动Activity:
createAndroidComposeRule会自动初始化并启动指定的Activity实例- 手动调用
ActivityScenario.launch()会再次启动新的Activity,原由Rule管理的Activity会被销毁 - 后续调用
rule.activity时,访问的是已被销毁的实例,触发NullPointerException
修复方案(推荐:保留Compose Rule)
移除手动的ActivityScenario相关代码,直接通过createAndroidComposeRule管理Activity:
package com.example.sandbox import android.content.pm.ActivityInfo import androidx.compose.ui.test.junit4.createAndroidComposeRule import org.junit.Rule import org.junit.Test class MainActivityTest { @get:Rule val rule = createAndroidComposeRule<MainActivity>() @Test fun sandboxTest() { rule.waitForIdle() // 通过Rule获取当前活跃的Activity设置方向 rule.activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE // 可选:等待配置变更完成后执行后续操作 rule.waitForIdle() } }
替代方案(单独使用ActivityScenario)
如果需要更灵活的生命周期控制,可单独使用ActivityScenario,通过onActivity方法操作Activity:
package com.example.sandbox import android.content.pm.ActivityInfo import androidx.test.core.app.ActivityScenario import org.junit.Test class MainActivityTest { @Test fun sandboxTest() { val scenario = ActivityScenario.launch(MainActivity::class.java) scenario.onActivity { activity -> activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE } // 等待配置变更完成 scenario.waitForActivity() } }
注意:此方式下无需使用createAndroidComposeRule,若需Compose UI测试,需结合对应API实现。
内容的提问来源于stack exchange,提问作者Saral
相关产品推荐
相关产品推荐

