【问题标题】:How to save and reuse same instance of fragments?如何保存和重用相同的片段实例?
【发布时间】:2013-10-27 03:26:44
【问题描述】:

我最近开始使用片段创建了一个演示应用程序,如下所示:

点击每个按钮在片段 1、片段 2 和片段 3 之间切换。

我想要完成的是每个片段只有 1 个实例并重用它。 (请注意,所有片段都是动态创建和添加的)。目前我正在通过创建片段的 HashMap 并放置每个实例并从那里抓取它来做到这一点。

所以我的问题是: 有没有更好的方法来做到这一点: 通过使用 FragmentManager 的 putFragment(...) 方法? putFragment (Bundle bundle, String key, Fragment fragment) 我不知道如何在我的情况下使用它。如果有人可以给我一个如何使用这种方法的例子。

在我的活动中保留每个片段的引用是否昂贵?这会让所有碎片保持活力吗?我正在使用软引用来解决这个问题,但我不确定这是否是正确的方法。请指出我这样做的任何替代方式,或者让我知道这是否是实现这一目标的最佳方式。

提前致谢。

这是我的代码:

更新: 我正在尝试重用后台堆栈中的片段,仅在后台堆栈中不存在时才尝试添加它们。在我离开片段一 -> 回到它 -> 然后尝试按下返回按钮后,下面的代码给了我非法状态异常:

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;
        }
    }
}

【问题讨论】:

  • 你研究过 FragmentTransactions 吗?它们可能对您有帮助。

标签: java android android-fragments


【解决方案1】:

为了演示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;
    }
}

这将使您可以轻松地从一个片段过渡到下一个片段。

【讨论】:

  • 感谢您的回答。我最初尝试过这种方法,但是这会将每个事务添加到后台堆栈,导致每个事务的大小不断增加。正如我提到的,内存是我实际应用程序中的一个问题。所以我想限制后堆栈中的条目数。我想一个更好的问题是:如果可以将 backstack 用作 FIFO 队列 -> 在 10 个事务之后,在添加第 11 个时丢弃第一个。
  • 您可以调用 disallowAddToBackStack() 并在后台堆栈中有太多东西时跟踪静态整数或其他东西。
  • 感谢这也解决了我得到的非法状态异常。如果您已经在上面,仍然需要努力不添加相同的片段,但这很简单。
【解决方案2】:

FragmentManager 进行它自己的内存管理。它将根据其逻辑杀死/重新创建或保留您的实例。您可以使用onSaveInstanceState()

确保您的片段状态已保存

或者您可以在 Fragment 上使用 setRetainInstance(true) 强制系统保持您的实例处于活动状态。

这就是您创建交易的方式。

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

【讨论】:

  • 感谢您的回答。我之前尝试过这种方法,我注意到的唯一区别是,如果您在片段 1 中键入内容,然后将其替换为片段 2,则在返回时创建片段 1 的新实例将导致您丢失该更改,因为重复使用同一个实例(在这种情况下,文本仍然存在)
猜你喜欢
  • 2018-11-05
  • 2014-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多