2013-10-27 97 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