使用 setExitTransition 到 Fragment 时出现 NullPointerException

NullPointerException when using setExitTransition to Fragment

我正在尝试为片段的进入和退出设置动画。 setEnterTransition 工作正常,但如果我使用 setExitTransition,它会抛出 nullPointerException。如果我使用 setReturnTransition,它不会显示任何动画。

这是我的。

private void showFragment() {
    Fragment fragment = JoinGroupFragment.newInstance();
    FragmentTransaction ft = getFragmentManager().beginTransaction()
            .add(R.id.fragment_container, fragment, JOIN_GROUP_FRAGMENT_TAG);


    if (Build.VERSION.SDK_INT >= 21) {
        Log.i(TAG, "set enter transition");
        fragment.setEnterTransition(new Slide(Gravity.TOP));
//      fragment.setExitTransition(new Slide(Gravity.BOTTOM));
    }

    ft.commit();
}

private void dismissFragment() {
    Fragment joinGroupFragment = getFragmentManager().findFragmentByTag(JOIN_GROUP_FRAGMENT_TAG);
    if (joinGroupFragment != null) {
        FragmentTransaction ft = getFragmentManager().beginTransaction();
//      ft.hide(joinGroupFragment);
        ft.remove(joinGroupFragment);
        ft.commit();
    }
}

现在,如果我使用 setExitTransition,我会遇到以下错误。

java.lang.NullPointerException: Attempt to read from field 'int android.app.Fragment.mContainerId' on a null object reference at android.app.BackStackRecord.onPreDraw(BackStackRecord.java:1131) at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:944) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1970) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5885) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767) at android.view.Choreographer.doCallbacks(Choreographer.java:580) at android.view.Choreographer.doFrame(Choreographer.java:550) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5254) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

我环顾四周,发现有一个与此相关的错误。 https://code.google.com/p/android/issues/detail?id=82832

已发布解决方法。我尝试了同样的事情,但使用 FragmentManager 而不是 supportFragmentManager,但我仍然面临同样的问题。

我尝试过的解决方法

// This is in onCreate().
getFragmentManager().beginTransaction().add(R.id.fragment_container, new Fragment())
                    .addToBackStack("dummy")
                    .commit();

private void showFragment() {
    Fragment fragment = JoinGroupFragment.newInstance();
    FragmentTransaction ft = getFragmentManager().beginTransaction()
            .replace(R.id.fragment_container, fragment, JOIN_GROUP_FRAGMENT_TAG);

    ft.addToBackStack(null);
    // ft.addToBackStack("dummy");
    // ft.addToBackStack("my_backstack); // none of these work
    ft.commit();


    if (Build.VERSION.SDK_INT >= 21) {
        Log.i(TAG, "set enter transition");
        fragment.setEnterTransition(new Slide(Gravity.TOP));
        fragment.setExitTransition(new Slide(Gravity.BOTTOM));
    }

    ft.commit();
}

private void dismissFragment() {
    Fragment joinGroupFragment = getFragmentManager().findFragmentByTag(JOIN_GROUP_FRAGMENT_TAG);
    if (joinGroupFragment != null) {
        FragmentTransaction ft = getFragmentManager().beginTransaction();
//      ft.hide(joinGroupFragment);
        ft.remove(joinGroupFragment);
        ft.commit();
    }
}

我知道后台堆栈中没有任何用于转换的片段,但添加虚拟片段也无济于事。有什么解决方法吗?

更新

我使用了相同的片段,而不是虚拟片段。

getFragmentManager().beginTransaction().add(R.id.fragment_container, JoinGroupFragment.newInstance())
                        .addToBackStack("dummy")
                        .commit();

private void showFragment() {
    Fragment fragment = JoinGroupFragment.newInstance();
    FragmentTransaction ft = getFragmentManager().beginTransaction()
            .replace(R.id.fragment_container, fragment, JOIN_GROUP_FRAGMENT_TAG);

    ft.addToBackStack("dummy");
    ft.commit();


    if (Build.VERSION.SDK_INT >= 21) {
        Log.i(TAG, "set enter transition");
        fragment.setEnterTransition(new Slide(Gravity.TOP));
        fragment.setExitTransition(new Slide(Gravity.BOTTOM));
    }

    ft.commit();
}

private void dismissFragment() {
    Fragment joinGroupFragment = getFragmentManager().findFragmentByTag(JOIN_GROUP_FRAGMENT_TAG);
    if (joinGroupFragment != null) {
        FragmentTransaction ft = getFragmentManager().beginTransaction();
//      ft.hide(joinGroupFragment);
        ft.remove(joinGroupFragment);
        ft.commit();
    }
}

如果我这样做,当我第一次调用 showFragment() 时,之前添加的(在 onCreate() 中)片段显示退出过渡,新片段显示进入过渡,但是当我调用 dismissFragment(),它仍然会抛出相同的错误。我一直在使用 getBackStackEntryCount() 记录 backstack 计数,删除片段时它显示 2,但仍然是错误。

但我不明白第一个片段是如何显示退出过渡的。


这个我也试过了

getFragmentManager().beginTransaction().add(R.id.fragment_container, new Fragment())
                        .addToBackStack("dummy")
                        .commit();

private void showFragment() {
    Fragment fragment = JoinGroupFragment.newInstance();
    FragmentTransaction ft = getFragmentManager().beginTransaction()
            .replace(R.id.fragment_container, fragment, JOIN_GROUP_FRAGMENT_TAG);

    ft.addToBackStack("dummy");
    ft.commit();


    if (Build.VERSION.SDK_INT >= 21) {
        Log.i(TAG, "set enter transition");
        fragment.setEnterTransition(new Slide(Gravity.TOP));
        fragment.setExitTransition(new Slide(Gravity.BOTTOM));
    }

    ft.commit();
}

private void dismissFragment() {
    Fragment joinGroupFragment = getFragmentManager().findFragmentByTag(JOIN_GROUP_FRAGMENT_TAG);
    if (joinGroupFragment != null) {
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.replace(R.id.fragment_container, new Fragment());
        ft.remove(joinGroupFragment);
        ft.commit();
    }
}

这很好用并显示了退出过渡。但是 BackStackEntryCount 继续增加,尽管 remove 调用增加了使用的内存。

原来我还不了解FragmentManager的backstack。我想做的事情可以在没有 backstack 的情况下完成。很简单。

对于过渡,我需要用其他片段替换片段,否则它不是过渡。

private void showFragment() {
    Fragment fragment = JoinGroupFragment.newInstance();
    FragmentTransaction ft = getFragmentManager().beginTransaction()
            .replace(R.id.fragment_container, fragment, JOIN_GROUP_FRAGMENT_TAG);

    ft.commit();


    if (Build.VERSION.SDK_INT >= 21) {
        fragment.setEnterTransition(new Slide(Gravity.TOP));
        fragment.setExitTransition(new Slide(Gravity.BOTTOM));
    }

    ft.commit();
}

private void dismissFragment() {
    Fragment joinGroupFragment = getFragmentManager().findFragmentByTag(JOIN_GROUP_FRAGMENT_TAG);
    if (joinGroupFragment != null) {
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.replace(R.id.fragment_container, new Fragment());
        ft.commit();
    }
}

效果很好。我也会用 backstack 尝试它,稍后 post。