有一个大的数据绑定视图,可能需要几秒钟才能膨胀.我想给用户显示一个启动屏幕,并膨胀主视图,延迟操作。Android抛出一个异常“未能调用观察者方法”。
MainActivity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.screen_splash)
Handler(Looper.getMainLooper()).postDelayed({
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(
this,
R.layout.activity_main
)
binding.lifecycleOwner = this // this line throws exception
}, 1000)
}activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:bind="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="vm"
type="com.example.ViewModel"/>
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/map_list"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" />
</RelativeLayout>例外:
2021-12-05 13:42:56.638 23701-23701/com.example E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example, PID: 23701
java.lang.RuntimeException: Failed to call observer method
at androidx.lifecycle.ClassesInfoCache$MethodReference.invokeCallback(ClassesInfoCache.java:226)
at androidx.lifecycle.ClassesInfoCache$CallbackInfo.invokeMethodsForEvent(ClassesInfoCache.java:194)
at androidx.lifecycle.ClassesInfoCache$CallbackInfo.invokeCallbacks(ClassesInfoCache.java:185)
at androidx.lifecycle.ReflectiveGenericLifecycleObserver.onStateChanged(ReflectiveGenericLifecycleObserver.java:37)
at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:354)
at androidx.lifecycle.LifecycleRegistry.addObserver(LifecycleRegistry.java:196)
at androidx.databinding.ViewDataBinding.setLifecycleOwner(ViewDataBinding.java:434)
at com.example.databinding.ActivityMainBindingImpl.setLifecycleOwner(ActivityMainBindingImpl.java:166)
at com.example.MainActivity.onCreate$lambda-3(MainActivity.kt:106)
at com.example.MainActivity.$r8$lambda$lffeScwTEbHi2B1isKEoQYU2po4(Unknown Source:0)
at com.example.MainActivity$$ExternalSyntheticLambda5.run(Unknown Source:2)
at android.os.Handler.handleCallback(Handler.java:888)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:213)
at android.app.ActivityThread.main(ActivityThread.java:8178)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1101)
Caused by: java.lang.NumberFormatException: s == null
at java.lang.Integer.parseInt(Integer.java:577)
at java.lang.Integer.valueOf(Integer.java:801)
at com.example.databinding.ControlPanelBindingImpl.executeBindings(ControlPanelBindingImpl.java:800)...发布于 2021-12-07 08:24:24
我不确定你的申请结构。在我们的例子中,我们有一个类似的需求,我们希望在绑定初始fragment之前向加载程序显示。所以我们在viewStub中创建了一个activity。然后,当该片段被附加时,我们将共享视图模型中的liveData设置为SHOW,这将通知活动来膨胀viewStub。这样,我们就可以膨胀视图存根,它隐藏了显示飞溅图像的整个屏幕。然后,一旦创建了片段中的视图,并且在onViewCreated中,我们再次将共享视图模型中的liveData设置为HIDE,其中隐藏了viewStub,并显示了片段。
发布于 2021-12-07 16:36:07
在您的主要活动中使用fragmentContainerView。显示要在此容器中显示的视图。在容器前面创建一个视图。在此视图中显示splash消息。在加载主视图时,使splash视图的可见性消失。因此,启动屏幕将使用活动生命周期,主视图将使用片段生命周期。这可能是你的解决方案。
发布于 2021-12-09 22:42:34
免责声明:答案中的更新2部分解决了该问题;如果其他部分能够帮助未来的访问者解决其他潜在问题,则将留下其他部分。
乍一看,您认为Caused by: java.lang.NumberFormatException: s == null与这个问题有关;尽管您在评论中告诉我们,它是同步工作的。
通过在代码中跟踪错误,异常java.lang.RuntimeException: Failed to call observer method将无助于了解错误。
但是,您的代码在简单布局中成功地与我一起工作;这个问题可能与您在访问binding.lifecycleOwner时试图同步加载大量布局有关;我想后一个片段在访问lifecycleOwner之前需要一段时间。所以,你可以提前发布一些延迟。
为此,我将使用协同机制,而不是发布延迟;因为代码将更具线性和可读性:
CoroutineScope(Main).launch {
delay(1000) // Original delay of yours
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(
this@MainActivity,
R.layout.activity_main
)
delay(1000) // try and error to manipulate this delay
binding.lifecycleOwner = this@MainActivity
}如果尚未使用,则coroutine依赖项为
def coroutine_version = "1.5.2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutine_version"更新
当主活动加载时,代码中发布的延迟无助于显示延迟期间的启动/启动屏幕;
处理程序(Looper.getMainLooper()).postDelayed({ val binding = DataBindingUtil.setContentView( this,R.layout.activity_main ) //除非1000秒超过binding.lifecycleOwner = This },1000)
您的代码所做的:
因此,发布的延迟只是累积到加载主布局的时间,这甚至使其更加滞后。此外,这并不是使用screen的推荐方法(这个中型员额会在这方面有所帮助)
相反,,我认为您打算做的是:
但是,问题是需要加载的东西是UI,它需要在主线程中,而不是在后台线程中这样做。因此,我们不使用两次不同的布局并调用setContentView()两次;您可以为主布局创建一个单一布局,并添加一些表示启动屏幕的视图,该视图将完全模糊主布局(位于其前面),直到加载布局(即延迟结束);然后删除这个启动视图:
演示:
splash_screen.xml (您想要的任何布局都必须与父级匹配,以使其模糊):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/splash_screen"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
android:gravity="center">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher" />
</LinearLayout>主要活动:
class MainActivity : AppCompatActivity() {
companion object {
const val TAG = "LOG_TAG"
}
lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(TAG, "Start Inflating layout")
binding = DataBindingUtil.setContentView(
this@MainActivity,
R.layout.activity_main
)
// Show only the first time app launches, not in configuration changes
if (savedInstanceState == null) {
CoroutineScope(IO).launch {
Log.d(TAG, "Start of delay")
delay(1000)
Log.d(TAG, "End of delay")
withContext(Main) {
hideSplash()
}
}
showSplash()
}
binding.lifecycleOwner = this@MainActivity
Log.d(TAG, "End Inflating layout")
}
private fun showSplash() {
supportActionBar?.hide()
// Inflate splash screen layout
val splashLayout =
layoutInflater.inflate(
R.layout.splash_screen,
binding.rootLayout,
false
) as LinearLayout
binding.rootLayout.addView(
splashLayout
)
}
private fun hideSplash() {
supportActionBar?.show()
binding.rootLayout.removeView(
findViewById(R.id.splash_screen)
)
}
}日志
2021-12-11 21:59:18.349 20681-20681/ D/LOG_TAG: Start Inflating layout
2021-12-11 21:59:18.452 20681-20707/ D/LOG_TAG: Start of delay
2021-12-11 21:59:18.476 20681-20681/ D/LOG_TAG: End Inflating layout
2021-12-11 21:59:20.457 20681-20707/ D/LOG_TAG: End of delay现在,延迟随着布局的膨胀而运行;加载时显示的启动屏幕;延迟结束时结束。

更新2
这绝对行不通:数据库=.行需要2.5秒才能完成,无法在"databinding.root“准备好之前添加视图。它在显示的代码中工作,因为您的主视图很小。
现在尝试将布局从setContentView()中的dataBinding中分离出来;但两者都需要位于主线程中。
setContentView(R.layout.screen_splash)
CoroutineScope(Main).launch {
// Inflate main screen layout asynchronously
binding = ActivityMainBinding.inflate(layoutInflater)
delay(2500) // 2.5 sec delay of loading the mainLayout before setContentView
setContentView(binding.root)
binding.lifecycleOwner = this@MainActivity
}https://stackoverflow.com/questions/70232199
复制相似问题