我有一个FragmentContainerView在我的MainActivity使用导航图。
<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" />
我希望我的片段等待,直到我从API得到一些数据之前,我隐藏我的闪屏。我用的是安卓12启动屏幕。这就是我如何试图完成它(从文档):
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
}
}
}
)
只有在我得到数据后,启动屏幕才会消失。但问题是,我的片段回调,如onViewCreated
被调用,甚至在我的数据准备好之前。这会导致问题,因为我依赖于我在启动屏幕期间获取的数据来完成一些任务。
我怎么能确保,我的片段不会被初始化之前我的启动屏幕消失??
启动画面只有在我获得数据后才会消失。但问题是,我的片段回调,如onViewCreated被调用,甚至在我的数据准备好之前。
活动和片段生命周期回调只由系统在适当的时间触发。它们不能由开发者触发;这是无法控制的。所以,你不能阻止onCreateView
,onViewCreated
,…从发生。也就是说,你不能从初始化停止活动/片段;否则你可能会有anr。
更多细节
activity/fragments的初始化不应该在后台任务完成之前被捕获;这实际上会导致anr。
当您使用addOnPreDrawListener
捕获活动的根布局的绘图时;这并不意味着活动的初始化(即onCreate()
)被捕获,因为两者都是异步工作的,onCreate()
,onStart()
, &onResume()
将正常返回。
对于fragment的回调也是如此,其中fragment的初始化(即onCreateView()
,onViewCreated
…)与活动的onCreate()
相耦合。
现在,由于起始目的片段的初始化依赖于API数据;那么这个特定的片段不应该是起始目标。
所以,为了解决这个问题,你需要创建一个启动屏幕片段作为不依赖于API数据的开始目的地。
根据传入的API数据,您可以通过navController
:
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
}
}
}