Внутреннее исключение / cra sh при быстром нажатии кнопки обзора Android дважды - PullRequest
3 голосов
/ 18 июня 2020

У меня есть фрагмент CustomArFragment (подкласс ArFragment из Sceneform 1.15 ), содержащийся в MainActivity. В какой-то момент я сбрасываю Фрагмент, заменяя его новым экземпляром. Я делаю это, вызывая следующий метод в 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 кнопку обзора дважды в быстрой последовательности , я получаю следующую ошибку, которая, похоже, связана с какой-то внутренней вызовы, которые мне не удалось отследить:

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, которые могут помешать работе замена. Итак, если я нажму кнопку обзора, а затем подожду секунду или две, прежде чем снова нажать ее, чтобы открыть резервную копию приложения, все будет работать, как задумано, без сбоев.

Помощь приветствуется, у меня закончились идеи из-за чего это может быть!

1 Ответ

0 голосов
/ 14 августа 2020

Cra sh, похоже, связано с тем фактом, что некоторые ресурсы ARCore / Sceneform продолжают работать в течение некоторого времени после удаления старого фрагмента, но все еще ссылаются на удаленный фрагмент (это было какое-то время go Я решил это проблема, поэтому я не помню точную причину, но я думаю, что это было так).

В любом случае, чтобы избежать cra sh, единственное, что я обнаружил, что работает, - это добавить удаленный фрагмент в Backstack. Таким образом, 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()

Конечно, не идеально сохранять старые фрагменты в backstack, поскольку я никогда не собираюсь возвращаться к ним. Однако, поскольку я предполагаю, что количество сбросов фрагмента будет низким, он работает для меня достаточно хорошо. Но если вы найдете лучшее решение для сброса ArFragment, дайте мне знать.

...