2013-03-16 73 views
12

我試圖瞭解如何在導航選項卡中使用片段時保留片段視圖狀態。在我的努力中,我遇到了兩個問題,我找不到任何適當的解決方案。Android導航選項卡:恢復片段視圖狀態

我有兩個選項卡,Tab1和Tab2。 Tab1的佈局由FragmentA定義,Tab2的佈局由FragmentB定義。 我已經按照這裏給出的方法:Adding navigation tabs

第一個問題:即使我的看法有標識,其狀態時的片段重新連接不完全恢復(製表開關旋轉後)。特別是:帶有ID的EditText確實保存了輸入的文本,但不保存其啓用狀態。即使他們有ID,我的按鈕也不會保存。我發現此問題的兩種可能的解決方法:

  1. 使用hide()/show()而不是attach()/detach()切換標籤時。
  2. in onPause()通過getView()將當前片段視圖狀態保存在片段的View實例變量中。在onCreateView(Bundle savedInstanceState)檢查此字段是否爲非空值,如果是,則返回此字段的值。這個解決方案看起來很亂,而且我被告知它可能會在我的應用程序中引入內存泄漏。

第二個問題:考慮以下用戶交互: 用戶開始對TAB1並做了一些變化,把TAB1的視圖狀態處於不同的狀態比其默認狀態(和我們想要的片段以節省此視圖狀態通過tabswitches和設備傾斜)。 用戶然後轉到Tab2。用戶然後傾斜她/他的設備(仍在Tab2)。 用戶然後交換到Tab1(在新的屏幕方向)。 現在,問題是:當用戶最初從Tab1切換到Tab2時,片段被分離並因此丟棄其視圖(即使片段實例仍然存在)。當用戶隨後傾斜設備時,活動 - 從而與其相關的FragmentA和FragmentB都被銷燬。由於此時FragmentA不再有視圖(請記住:它已被分離),因此在調用FragmentA.onSaveInstanceState(Bundle savedInstanceState)期間,我們無法保存其視圖元素的狀態(例如啓用/禁用哪些按鈕)。如何在這種情況下恢復片段視圖狀態?是唯一可行的解​​決方案將每個視圖元素的不同狀態標誌保存爲SharedPreferences?對於這樣的「日常工作」來說,這似乎太複雜了。

我一直都在SO和各種博客文章,但一直沒能找到解決這個(特定)問題。

回答

7

問題1:

Android不保存默認啓用您的視圖狀態。似乎只有被用戶操作直接影響的東西(沒有附加代碼)才被保存。對於普通視圖no information is saved以及對於其EditText是子類的TextView,entered text is saved(如果freezesText已設置)。

如果你想要保存任何東西,你將不得不自己做。 Here是一個帶有一些答案的問題,顯示如何實現自定義視圖狀態保存。如果你遵循這種方法,你可以堅持附加/分離。

問題2:

你是對在Fragment.onSaveInstanceState(包)你的觀點已經被銷燬後,可以被調用。但是,這不是你應該保存視圖狀態的地方。在分離片段時,Android會在視圖銷燬視圖之前調用View.onSaveInstanceState()。它會保存這個狀態並在再次附加片段時將其返回給您。這正是您在正常切換標籤時沒有旋轉的情況。分離時不調用Fragment.onSaveInstanceState(Bundle)。即使您旋轉設備,由於分離而保存的視圖狀態仍會保留。如果按照上面的指示實現View.onSaveInstanceState(),則即使在Tab1-Tab2-rotate-Tab1方案中,視圖狀態也會被正確保存和恢復。

附註: 文檔中的example code似乎在嘗試旋轉時會出現一些問題。 TabListener的生命週期與Activity的生命週期相同 - 每次旋轉時都會創建一個新的。這意味着它每次旋轉時都會丟失其片段的內部參照。添加的片段會自動重新創建,因此不需要TabListener嘗試創建新實例並在旋轉後添加它。相反,對於內部引用,它應該嘗試在片段管理器中找到具有適當標記的片段。旋轉後它仍然存在。

另一個問題是選定的選項卡沒有保存,但是這在該示例的底部註明。你可以將它保存在Activity.onSaveInstanceState(Bundle)中。

+0

非常感謝 - 很好的解釋。但是,事情還沒有完全清楚。我一直在穿過你提到的答案,但我沒有設法理解它的用法。什麼被視爲「CustomView」?我的片段視圖狀態僅包含內置視圖(如EditTexts,Buttons等)。因此我沒有擴展任何View類 - 我只是在xml佈局文件中構建了片段視圖。我怎樣才能連接在我的佈局的答案中提供的示例代碼,它不使用任何用戶定義的視圖(假設一個CustomView是android到用戶定義的控制是什麼ASP.net)? – 2013-03-16 20:13:51

+1

@jvmk要使用View.onSaveInstanceState(),您需要繼承一個View並覆蓋該方法。然後,您的佈局XML需要引用這些新視圖,而不是EditText/Button。 – antonyt 2013-03-16 21:53:51

+2

哇,真是瘋了。我認爲恢復內置視圖的視圖狀態將是一個足夠頻繁的任務,以支持它作爲標準功能。假設我應該編寫一個庫供將來使用。感謝您在這裏幫助我。這讓我生氣了2周,嘿。 – 2013-03-16 22:45:50

0
private ViewPager viewPager; 
viewPager = (ViewPager) findViewById(R.id.pager); 
mAdapter = new TabsPagerAdapter(getSupportFragmentManager()); 
viewPager.setAdapter(mAdapter); 
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { 

     @Override 
     public void onPageSelected(int position) { 
      // on changing the page 
      // make respected tab selected 
      actionBar.setSelectedNavigationItem(position); 
     } 

     @Override 
     public void onPageScrolled(int arg0, float arg1, int arg2) { 
     } 

     @Override 
     public void onPageScrollStateChanged(int arg0) { 
     } 
    }); 
} 

@Override 
public void onTabReselected(Tab tab, FragmentTransaction ft) { 
} 

@Override 
public void onTabSelected(Tab tab, FragmentTransaction ft) { 
    // on tab selected 
    // show respected fragment view 
    viewPager.setCurrentItem(tab.getPosition()); 
} 

@Override 
public void onTabUnselected(Tab tab, FragmentTransaction ft) { 
} 
+1

請考慮包括一些關於您的答案的信息,而不是簡單地發佈代碼。我們嘗試提供的不僅僅是「修復」,而是幫助人們學習。你應該解釋原始代碼中的錯誤,你做了什麼不同,以及爲什麼你的改變起作用。 – 2015-01-09 17:29:45

相關問題