片段在Android 12启动画面结束前被初始化



我有一个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
}
}
}

最新更新