内部 exception/crash 快速点击 Android 的概览按钮两次
Internal exception/crash when quickly tapping Android's overview button twice
我在 MainActivity 中包含一个名为 CustomArFragment 的片段(ArFragment from Sceneform 1.15 的子类)。在某个时间点,我通过替换为新实例来重置片段。我通过在 MainActivity 中调用以下方法来执行此操作:
fun reset() {
val oldFragment = (supportFragmentManager.findFragmentById(R.id.custom_ar_fragment)) as? CustomArFragment ?: return
val newArFragment = CustomArFragment()
val transaction = supportFragmentManager.beginTransaction()
transaction.remove(oldFragment)
transaction.add(R.id.custom_ar_fragment, newArFragment)
transaction.commit()
}
现在,正如我所说,起初替换似乎工作正常,新片段在替换后像往常一样 运行。但是,如果我在调用 reset()
后的任何时间点快速连续按两次 android overview button 我会收到以下错误,这似乎与某些内部我无法追踪的电话:
java.lang.NullPointerException: throw with null exception
at com.google.ar.sceneform.utilities.Preconditions.checkNotNull(SourceFile:3)
at com.google.ar.sceneform.SceneView.onLayout(SourceFile:41)
at com.google.ar.sceneform.ArSceneView.onLayout(SourceFile:79)
at android.view.View.layout(View.java:20729)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20729)
at android.view.ViewGroup.layout(ViewGroup.java:6198)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20729)
at android.view.ViewGroup.layout(ViewGroup.java:6198)
at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1915)
at android.view.View.layout(View.java:20729)
at android.view.ViewGroup.layout(ViewGroup.java:6198)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20729)
at android.view.ViewGroup.layout(ViewGroup.java:6198)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)
at android.view.View.layout(View.java:20729)
at android.view.ViewGroup.layout(ViewGroup.java:6198)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20729)
at android.view.ViewGroup.layout(ViewGroup.java:6198)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)
at android.view.View.layout(View.java:20729)
at android.view.ViewGroup.layout(ViewGroup.java:6198)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at com.android.internal.policy.DecorView.onLayout(DecorView.java:757)
at android.view.View.layout(View.java:20729)
at android.view.ViewGroup.layout(ViewGroup.java:6198)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2859)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2386)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1524)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7398)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1092)
at android.view.Choreographer.doCallbacks(Choreographer.java:888)
at android.view.Choreographer.doFrame(Choreographer.java:819)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1078)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6815)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
现在,我不确定这是与 Sceneform 相关的错误还是我替换片段的方式有问题。
我想澄清一下,除非我在替换完成后双击应用程序概览按钮,否则替换工作正常,并且我没有在 CustomArFragment 的生命周期方法中做任何可能干扰替换的事情.因此,如果我按下概览按钮,然后等待一两秒钟,然后再次按下它以打开应用程序备份,一切都会按预期运行而不会崩溃。
非常感谢您的帮助,我 运行 不知道是什么原因造成的!
崩溃似乎与某些 ARCore/Sceneform 资源在删除旧片段后保留 运行 一段时间有关,但仍引用已删除的片段(前一段时间我解决了这个问题,所以我不记得确切的原因,但我认为是这个)。
无论如何,为了避免崩溃,我发现唯一可行的方法是将删除的片段添加到后台堆栈。这样sceneform/ARCore就不会遇到空指针了。
val oldFragment = (supportFragmentManager.findFragmentById(R.id.custom_ar_fragment)) as? CustomArFragment ?: return
oldFragment.arSceneView.pause()
val newArFragment = CustomArFragment()
val transaction = supportFragmentManager.beginTransaction().remove(oldFragment).add(R.id.sceneform_fragment, newArFragment).addToBackStack(null)
transaction.commit()
supportFragmentManager.executePendingTransactions()
当然,将旧片段保存到后台堆栈并不理想,因为我从来没有打算 return 给它们。但是,由于我假设片段的重置次数会很低,所以它对我来说已经足够好了。但是,如果您找到更好的重置 ArFragment
的解决方案,请告诉我。
我在 MainActivity 中包含一个名为 CustomArFragment 的片段(ArFragment from Sceneform 1.15 的子类)。在某个时间点,我通过替换为新实例来重置片段。我通过在 MainActivity 中调用以下方法来执行此操作:
fun reset() {
val oldFragment = (supportFragmentManager.findFragmentById(R.id.custom_ar_fragment)) as? CustomArFragment ?: return
val newArFragment = CustomArFragment()
val transaction = supportFragmentManager.beginTransaction()
transaction.remove(oldFragment)
transaction.add(R.id.custom_ar_fragment, newArFragment)
transaction.commit()
}
现在,正如我所说,起初替换似乎工作正常,新片段在替换后像往常一样 运行。但是,如果我在调用 reset()
后的任何时间点快速连续按两次 android overview button 我会收到以下错误,这似乎与某些内部我无法追踪的电话:
java.lang.NullPointerException: throw with null exception
at com.google.ar.sceneform.utilities.Preconditions.checkNotNull(SourceFile:3)
at com.google.ar.sceneform.SceneView.onLayout(SourceFile:41)
at com.google.ar.sceneform.ArSceneView.onLayout(SourceFile:79)
at android.view.View.layout(View.java:20729)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20729)
at android.view.ViewGroup.layout(ViewGroup.java:6198)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20729)
at android.view.ViewGroup.layout(ViewGroup.java:6198)
at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1915)
at android.view.View.layout(View.java:20729)
at android.view.ViewGroup.layout(ViewGroup.java:6198)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20729)
at android.view.ViewGroup.layout(ViewGroup.java:6198)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)
at android.view.View.layout(View.java:20729)
at android.view.ViewGroup.layout(ViewGroup.java:6198)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20729)
at android.view.ViewGroup.layout(ViewGroup.java:6198)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)
at android.view.View.layout(View.java:20729)
at android.view.ViewGroup.layout(ViewGroup.java:6198)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at com.android.internal.policy.DecorView.onLayout(DecorView.java:757)
at android.view.View.layout(View.java:20729)
at android.view.ViewGroup.layout(ViewGroup.java:6198)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2859)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2386)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1524)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7398)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1092)
at android.view.Choreographer.doCallbacks(Choreographer.java:888)
at android.view.Choreographer.doFrame(Choreographer.java:819)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1078)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6815)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
现在,我不确定这是与 Sceneform 相关的错误还是我替换片段的方式有问题。
我想澄清一下,除非我在替换完成后双击应用程序概览按钮,否则替换工作正常,并且我没有在 CustomArFragment 的生命周期方法中做任何可能干扰替换的事情.因此,如果我按下概览按钮,然后等待一两秒钟,然后再次按下它以打开应用程序备份,一切都会按预期运行而不会崩溃。
非常感谢您的帮助,我 运行 不知道是什么原因造成的!
崩溃似乎与某些 ARCore/Sceneform 资源在删除旧片段后保留 运行 一段时间有关,但仍引用已删除的片段(前一段时间我解决了这个问题,所以我不记得确切的原因,但我认为是这个)。
无论如何,为了避免崩溃,我发现唯一可行的方法是将删除的片段添加到后台堆栈。这样sceneform/ARCore就不会遇到空指针了。
val oldFragment = (supportFragmentManager.findFragmentById(R.id.custom_ar_fragment)) as? CustomArFragment ?: return
oldFragment.arSceneView.pause()
val newArFragment = CustomArFragment()
val transaction = supportFragmentManager.beginTransaction().remove(oldFragment).add(R.id.sceneform_fragment, newArFragment).addToBackStack(null)
transaction.commit()
supportFragmentManager.executePendingTransactions()
当然,将旧片段保存到后台堆栈并不理想,因为我从来没有打算 return 给它们。但是,由于我假设片段的重置次数会很低,所以它对我来说已经足够好了。但是,如果您找到更好的重置 ArFragment
的解决方案,请告诉我。