正确分段堆栈

时间:2016-11-17 01:31:37

标签: java android android-fragments

我在应用程序中实现正确的反向包装时遇到了一些麻烦。我以为我知道我在做什么,但事实证明它只是因为侥幸而起作用,而我宁愿把它当作正确的做事方式。

这是在Android Studio中使用Google提供的模板。

首先,我的设置看起来像这样;我的content_main.xml设置如下:

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
....>
<FrameLayout
    ....
    android:id="@+id/mainFrame"></FrameLayout>
</RelativeLayout>

在我的主要活动中,我有一个函数可以通过输入这样的id来切换片段:

(我知道生病可能会因为使用android.app.Fragment而不是支持库而有些松懈,我愿意转换,如果它有助于我的事业,但后来我遇到了不同的问题,更多关于如果答案结果是&#34;切换到支持库&#34;)

private void drawFragmentFromId(int id)
{
    android.app.Fragment currentFragment = fm.findFragmentById(R.id.mainFrame);
    if (id == R.id.nav_overview)
    {
        //fm is a global fragment manager, is that bad practice?
        if(currentFragment.getTag() == "F_SETTINGS")
            fm.beginTransaction().replace(currentFragment.getId(), oFrag, "F_OVERVIEW").commit();
        else
            fm.beginTransaction().replace(currentFragment.getId(), oFrag, "F_OVERVIEW").addToBackStack(currentFragment.getTag()).commit();
    }
....
}

我有if(currentFragment.getTag() == "F_SETTINGS")子句,因为理想情况下,我不想将设置片段添加到backstack。也就是说,如果用户转到概述片段,然后是设置片段,然后是片段“foo”,然后点击后退按钮,理想情况下,我不希望应用程序返回到设置片段,但完全跳过它。如果我在这里做错了,或者这是一种很好的做法,请告诉我。

在我的onBackPressed中,我让super.onBackPressed()处理过去片段的绘制。

出于某种原因,这会让应用程序崩溃,告诉我我正在尝试绘制已经绘制过的片段。确切地说:

java.lang.IllegalStateException: Fragment already added: OverviewFragment{7ee61cf #0 id=0x7f0d0072 F_OVERVIEW}

如果我尝试例如转到概述片段,然后设置,然后再次查看概述,然后点击后退按钮,应用程序似乎会崩溃。但是,如果我将设置片段添加到backstack,这个过程似乎完全正常。

如果我转到概述片段,那么设置然后是另一个片段,称之为“foo”,然后应用程序做了一些非常奇怪的事情,它根据需要跳过设置片段,但是它没有& #39; t用概述片段替换foo片段,它只是将概述片段放在最上面。

我猜测问题在于应用程序的默认onBackPressed()。它可能不知道要用新的片段代替什么片段,但老实说,我不知道如何纠正这个。

非常感谢任何帮助。谢谢你阅读本文。

修改: 整个logcat stacktrace:

11-16 15:22:26.948 24151-24151/com.projects.mocks.mocks E/AndroidRuntime: FATAL EXCEPTION: main
                                                                      Process: com.projects.mocks.mocks, PID: 24151
                                                                      java.lang.IllegalStateException: Fragment already added: OverviewFragment{134836e #0 id=0x7f0d0072 F_OVERVIEW}
                                                                          at android.app.FragmentManagerImpl.addFragment(FragmentManager.java:1219)
                                                                          at android.app.BackStackRecord.popFromBackStack(BackStackRecord.java:1630)
                                                                          at android.app.FragmentManagerImpl.popBackStackState(FragmentManager.java:1587)
                                                                          at android.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:578)
                                                                          at android.app.Activity.onBackPressed(Activity.java:2503)
                                                                          at android.support.v4.app.FragmentActivity.onBackPressed(FragmentActivity.java:180)
                                                                          at com.projects.mocks.mocks.MainActivity.onBackPressed(MainActivity.java:143)
                                                                          at android.app.Activity.onKeyUp(Activity.java:2477)
                                                                          at android.view.KeyEvent.dispatch(KeyEvent.java:2664)
                                                                          at android.app.Activity.dispatchKeyEvent(Activity.java:2730)
                                                                          at android.support.v7.app.AppCompatActivity.dispatchKeyEvent(AppCompatActivity.java:543)
                                                                          at android.support.v7.view.WindowCallbackWrapper.dispatchKeyEvent(WindowCallbackWrapper.java:53)
                                                                          at android.support.v7.app.AppCompatDelegateImplBase$AppCompatWindowCallbackBase.dispatchKeyEvent(AppCompatDelegateImplBase.java:315)
                                                                          at android.support.v7.view.WindowCallbackWrapper.dispatchKeyEvent(WindowCallbackWrapper.java:53)
                                                                          at com.android.internal.policy.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:2310)
                                                                          at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:4127)
                                                                          at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4089)
                                                                          at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3642)
                                                                          at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3695)
                                                                          at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3661)
                                                                          at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3787)
                                                                          at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3669)
                                                                          at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3844)
                                                                          at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3642)
                                                                          at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3695)
                                                                          at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3661)
                                                                          at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3669)
                                                                          at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3642)
                                                                          at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3695)
                                                                          at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3661)
                                                                          at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3820)
                                                                          at android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent(ViewRootImpl.java:3981)
                                                                          at android.view.inputmethod.InputMethodManager$PendingEvent.run(InputMethodManager.java:2253)
                                                                          at android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback(InputMethodManager.java:1874)
                                                                          at android.view.inputmethod.InputMethodManager.finishedInputEvent(InputMethodManager.java:1865)
                                                                          at android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished(InputMethodManager.java:2230)
                                                                          at android.view.InputEventSender.dispatchInputEventFinished(InputEventSender.java:141)
                                                                          at android.os.MessageQueue.nativePollOnce(Native Method)
                                                                          at android.os.MessageQueue.next(MessageQueue.java:323)
                                                                          at android.os.Looper.loop(Looper.java:135)
                                                                          at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                                          at java.lang.reflect.Method.invoke(Native Method)
                                                                          at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                                          at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

1 个答案:

答案 0 :(得分:0)

看起来我已经想出了我想要的效果。而且我将发布这个作为其他任何可能面临同样问题的人的答案。

似乎我的代码是正确的,我只是遗漏了一小段代码,使整个过程按预期工作。

上面代码的问题是我正在尝试实现这个效果: 用户单击[A],然后单击[C],然后单击任何其他片段,调用它,[B]。 我不是在后台堆栈中添加[C],所以你会认为onBackPressed()在执行逆转时会跳过[C],但是后台堆栈的工作方式是需要一种“状态快照” '并将重新加载那个确切的状态。由于我没有在后台堆栈中添加[C],根据我的理解,它所知道的只是重新添加[A],但[B]永远不会被删除。

解决方案是执行以下操作:

private void drawFragmentFromId(int id)
{
    android.app.Fragment currentFragment = fm.findFragmentById(R.id.mainFrame);
    if (id == R.id.nav_overview)
    {
        //fm is a global fragment manager, is that bad practice?
        if(currentFragment.getTag() == "F_SETTINGS"){
//-------------------------------------------------------------------------------
            fm.popBackStack(); //it was this guy here. that's all I was missing.
//-------------------------------------------------------------------------------
            fm.beginTransaction().replace(currentFragment.getId(), oFrag, "F_OVERVIEW").commit();
        }
        else
            fm.beginTransaction().replace(currentFragment.getId(), oFrag, "F_OVERVIEW").addToBackStack(currentFragment.getTag()).commit();
    }
....
}

It was this answer that pointed me in the right direction.(再向下一点,这是一个冗长的答案)