2016-11-17 71 views
2

我遇到一些麻煩,在我的應用程序中執行正確的堆疊。我以爲我知道我在做什麼,但事實證明它只是因爲僥倖,而我寧願將它解決爲做事的正確方法。片段正確堆疊

這是使用谷歌在Android Studio中提供的模板介意你。

首先,我的設置看起來像這樣;我content_main.xml設置是這樣的:

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

在我的主要活動,我有通過採取一個id這樣的切換片段的功能:

(我知道生病可能得到採用了android有些呆滯。 app.Fragment而不是支持庫,我願意切換它,如果它能幫助我的事業,但是然後遇到不同的問題,更多的是如果答案證明是「切換到支持庫」)

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")因爲理想情況下,我不想將設置片段添加到後臺堆棧中。也就是說,如果用戶轉到概述片段,然後設置片段,然後片段'foo',然後點擊後退按鈕,理想情況下,我不希望應用程序返回到設置片段,但跳過它完全。讓我知道如果我在這裏做錯了什麼,或者是否有良好的做法。

並在我的onBackPressed我讓super.onBackPressed()處理過去的片段的繪圖。

出於某種原因,這使得應用程序有時會崩潰,告訴我,我正在嘗試繪製已經繪製的片段。確切的說:

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

的應用程序似乎崩潰,如果我嘗試,例如,去概述片段,然後設置,然後再概述,然後打的後退按鈕。然而,如果我將設置片段添加到backstack,這個過程似乎工作得很好。

如果我轉到概述片段,然後設置然後另一個片段,稱之爲'foo',然後應用程序做一些非常奇怪的事情,它會跳過設置片段,如果需要,但它不會取代foo片段與概述片段,它只是將概覽片段放在頂部。

我猜測問題出在應用的默認onBackPressed()。它可能不知道用什麼片段替換新片,但老實說,我不知道如何糾正這個問題。

任何幫助將不勝感激。並感謝您閱讀本文。

編輯: 整個logcat的堆棧跟蹤:

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) 
+0

請張貼從logcat的 – Karakuri

+0

編輯問題一個完整的堆棧跟蹤。 –

回答

0

看的像我想通了,我想要的效果。而且我會把這個帖子作爲對可能面臨同樣問題的其他任何人的回答。

看來我的代碼是正確的,我只是錯過了一小段代碼,使整個事情按預期工作。

我上面的代碼的問題是,我試圖達到這樣的效果: 用戶點擊[A],然後點擊[C]然後點擊任何其他片段,調用它,[B]。 我並沒有將[C]添加到backstack中,所以你會認爲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.(還有更遠,這是一個冗長的答案)