我的 MainActivity 中有一个 FragmentContainerView,它使用导航图。
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav" />
我希望我的 fragment 等到我从 API 获取一些数据后再隐藏启动屏幕。我正在使用 Android 12 Splash Screen 。这就是我试图实现它的方式(来自 documentation ):
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
installSplashScreen()
setContentView(R.layout.activity_main)
//Set up an OnPreDrawListener to the root view.
val content: View = findViewById(android.R.id.content)
content.viewTreeObserver.addOnPreDrawListener(
object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
// Check if the initial data is ready.
return if (mainActivityViewModel.isDataReady()) {
// The content is ready; start drawing.
Timber.tag("Splash").d("data ready")
content.viewTreeObserver.removeOnPreDrawListener(this)
true
} else {
Timber.tag("Splash").d("data not ready")
// The content is not ready; suspend.
false
}
}
}
)
只有在我获取数据后,启动屏幕才会消失。但问题是,即使在我的数据准备好之前,我的 Fragments 回调(例如 onViewCreated
)也会被调用。这会导致问题,因为我依赖在启动屏幕期间获取的数据来执行某些任务。
我如何确保在我的启动屏幕消失之前我的 fragment 不会被初始化?
最佳答案
The Splash screen is going away only after I get the data. But the issue is that my Fragments callbacks like onViewCreated gets invoked even before my data is ready.
Activity和 fragment生命周期回调仅由系统在适当的时间触发。它们不能由开发人员触发;对此无法控制。因此,您无法阻止 onCreateView
、onViewCreated
等发生。即,您无法从初始化中停止 Activity/fragment ;否则您可能会出现 ANR。
更详细
在某些后台任务完成之前,不应捕获 Activity/fragment 的初始化;这确实会导致 ANR。
当您使用addOnPreDrawListener
获取 Activity 根布局的绘制时;这并不意味着 Activity 的初始化(即 onCreate()
)被捕获,因为两者都是异步工作的,并且 onCreate()
、onStart()
, & onResume()
会正常返回。
对于 fragment 的回调也是如此,其中 fragment 的初始化(即 onCreateView()
、onViewCreated
...)与 Activity 的 onCreate() 耦合
.
现在,由于起始目标 fragment 的初始化依赖于API数据;那么这个特定的 fragment 不应该是起始目的地。
因此,要解决此问题,您需要创建一些启动屏幕 fragment 作为不依赖于 API 数据的起始目标。
根据 API 传入数据,您可以通过 navController
决定导航到原始 fragment :
return if (mainActivityViewModel.isDataReady()) {
// Do the transaction to the original fragment through the navController
// The content is ready; start drawing.
Timber.tag("Splash").d("data ready")
content.viewTreeObserver.removeOnPreDrawListener(this)
true
} else {
// Not transaction is needed, keep the splash screen fragment
Timber.tag("Splash").d("data not ready")
// The content is not ready; suspend.
false
}
}
}
关于android - 在 Android 12 启动画面结束之前 fragment 被初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72578802/