2013-10-27 62 views
13

我最近開始使用碎片已經創建了一個演示應用程序看起來像這樣:如何保存和重用相同的碎片實例?

Demo App

點擊片段1之間的每一個按鍵開關,片段2和片段3

我是什麼試圖完成每個片段只有1個實例並重用。 (請注意,所有片段都是動態創建和添加的)。目前我通過創建片段的HashMap並放置每個實例並從中抓取它來完成此操作。

所以我的問題是: 有沒有更好的方式來做到這一點: 通過使用FragmentManager的putFragment(...)方法? putFragment (Bundle bundle, String key, Fragment fragment)我無法弄清楚如何在我的情況下使用它。如果有人能給我一個如何使用這種方法的例子。

是它昂貴守住我的活動的每個片段的參考?這是否保留所有的片段活着?我正在使用軟參考來解決這個問題,但我不確定這是否是正確的方法。請指出我採取任何其他方式來做到這一點,或讓我知道這是否是最好的方式來完成這一點。

在此先感謝。

這裏是我的代碼:

UPDATE: 我試圖從後面堆重用片段,試圖只有在後面堆棧不存在,它添加。下面的代碼給我的非法狀態異常後,我從片段導航離去的一個 - >回來給它 - >然後嘗試按後退按鈕:

10-28 13:21:40.255: ERROR/MessageQueue-JNI(3548): java.lang.IllegalStateException: Fragment already added: FragmentOne{423db570 #0 id=0x7f050006 fragOne} 

public class MainActivity extends Activity implements View.OnClickListener { 

private Button btnOne; 
private Button btnTwo; 
private Button btnThree; 

/* Called when the activity is first created. 
    */ 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    initialize(); 
    if(findViewById(R.id.fl) != null){ 
     if(savedInstanceState != null) 
      return; 
    } 

    FragmentManager.enableDebugLogging(true); 
    updateView("fragOne"); 
} 

private void initialize(){ 
    btnOne = (Button) findViewById(R.id.button1); 
    btnTwo = (Button) findViewById(R.id.button2); 
    btnThree = (Button) findViewById(R.id.button3); 
    btnOne.setOnClickListener(this); 
    btnTwo.setOnClickListener(this); 
    btnThree.setOnClickListener(this); 
    fragHolder = new HashMap<String, SoftReference<Fragment>>(); 
} 

private void updateView(String tag){ 
    FragmentTransaction ft = getFragmentManager().beginTransaction(); 
    Fragment frag = getFragmentManager().findFragmentByTag(tag); 

    boolean addToStack = true; 
    if(frag == null){ 
     if(tag.equals("fragOne")) 
      frag = new FragmentOne();  
     else if(tag.equals("fragTwo")) 
      frag = new FragmentTwo(); 
     else if(tag.equals("fragThree")) 
      frag = new FragmentThree(); 
    }else{ 
     //Don't add to back stack 
     addToStack = false; 
    } 
    ft.replace(R.id.fl, frag, tag); 
    if(addToStack) 
     ft.addToBackStack(null); 
    ft.commit(); 
} 

    @Override 
    public void onClick(View v) { 
     switch(v.getId()){ 
      case R.id.button1: 
       updateView("fragOne"); 
       break; 
      case R.id.button2: 
       updateView("fragTwo"); 
       break; 
      case R.id.button3: 
       updateView("fragThree"); 
       break; 
     } 
    } 
} 
+0

你看過FragmentTransactions嗎?他們可能對你有幫助。 –

回答

2

爲了證明FragmentTransaction,下面的示例可能會有所幫助您。

首先,你想要做你的活動,你有正確的onCreate()所有的初始化的東西,但我們會做一些修改。

public class MainActivity extends Activity implements View.OnClickListener { 

private Button btnOne; 
private Button btnTwo; 
private Button btnThree; 

/* Called when the activity is first created.*/ 
@Override 
public void onCreate(Bundle savedInstanceState) 
{ 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    initialize(); 
    if(findViewById(R.id.fl) != null) 
    { 
     if(savedInstanceState != null) 
     { 
      FragmentTransaction trans = getFragmentManager().beginTransaction(); 

      //This is where we add our first fragment 
      trans.add(R.id.fl, new FragmentOne()); 
      trans.commit(); 
     } 
    } 
} 

private void initialize() 
{ 
    btnOne = (Button) findViewById(R.id.button1); 
    btnTwo = (Button) findViewById(R.id.button2); 
    btnThree = (Button) findViewById(R.id.button3); 
    btnOne.setOnClickListener(this); 
    btnTwo.setOnClickListener(this); 
    btnThree.setOnClickListener(this); 
} 

public void onClick(View view) 
{ 
    //Here is where we'll actually transfer the fragments 

    FragmentTransaction trans = getFragmentManager().beginTransaction(); 
    switch(v.getId()){ 
     case R.id.button1: 
      trans.replace(R.id.fl, new FragmentOne()); 
      trans.addToBackStack(null); 
      trans.commit(); 
      break; 
     case R.id.button2: 
      trans.replace(R.id.fl, new FragmentTwo()); 
      trans.addToBackStack(null); 
      trans.commit(); 
      break; 
     case R.id.button3: 
      trans.replace(R.id.fl, new FragmentThree()); 
      trans.addToBackStack(null); 
      trans.commit(); 
      break; 
    } 
} 

這將允許您輕鬆地從一個片段轉換到下一個片段。

+0

感謝您的回答。我最初嘗試這種方法,但是這增加了每一筆交易到堆棧中使其保持在大小每筆交易增加。正如我所提到的,內存在我的實際應用程序中是一個問題。所以我想限制後端堆棧中的條目數量。我想一個更好的問題是:如果有可能使用返回堆棧作爲一個FIFO隊列 - 10交易後>添加11時丟棄第一。 – Naveed

+1

你可以調用'disallowAddToBackStack()'來跟蹤一個靜態的整數或者什麼東西,當你在背面堆棧上有太多東西的時候。 –

+0

謝謝,這也解決了我得到的非法狀態異常。如果你已經在上面,但仍然需要不添加相同的片段,但這很簡單。 – Naveed

1

的FragmentManager做它自己的內存管理。它會根據其邏輯殺死/重新創建或保留實例。你可以確保你的片段狀態保存使用onSaveInstanceState()

或者你可以強制系統在你的片段上使用setRetainInstance(true)保持你的實例活着。

這是你如何創建事務。

FragmentTransaction fragmentTransaction = context.getSupportFragmentManager().beginTransaction(); 
    fragmentTransaction.replace(R.id.layout, new MyFragment(), f.getClass().getName()); 
    fragmentTransaction.commit(); 
+1

感謝您的回答。我之前正在嘗試這種方法,我注意到的唯一區別是,如果您在片段1中鍵入某些內容,然後將其替換爲片段2,則在導航回時會創建片段1的新實例會導致您將該更改放棄爲重複使用同一個實例(在這種情況下,文本仍然存在) – Naveed