如何正确地删除保留的实例片段 [英] How to properly remove retained instance Fragment

查看:117
本文介绍了如何正确地删除保留的实例片段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前,我想保留一个昂贵的数据结构,在配置更改。我选择不使用捆绑来处理它,因为昂贵的数据结构不parcelable。

因此​​,我使用了非UI片段(称之为 RetainInstanceFragment ),其 setRetainInstance(真)来保存数据结构。

 公共类RetainInstanceFragment扩展片段{
    @覆盖
    公共无效的onCreate(捆绑savedInstanceState){
        super.onCreate(savedInstanceState);        //创建昂贵的数据结构
        expensiveDataStructure = CreateExpensiveDataStructure();        //告诉框架,尽量保持这个片段各地
        //配置更改时。
        setRetainInstance(真);
    }    公共ExpensiveDataStructure expensiveDataStructure = NULL;
}

这是UI片段(称之为 UIFragment )将获得 RetainInstanceFragment 昂贵的数据结构。每当有上配置更改 UIFragment UIFragment 将始终尝试让缓存 RetainInstanceFragment FragmentManager ,才决定创建一个新的 RetainInstanceFragment

例子code是如下。

 公共类UIFragment扩展SherlockListFragment
    @覆盖
    公共无效onActivityCreated(捆绑savedInstanceState){
        super.onActivityCreated(savedInstanceState);        FragmentManager FM = getFragmentManager();        //检查是否我们保留了工人的片段。
        retainInstanceFragment =(RetainInstanceFragment)fm.findFragmentByTag(数据);        //如果不保留(或第一次运行),我们需要创建它。
        如果(retainInstanceFragment == NULL){
            retainInstanceFragment =新RetainInstanceFragment();
            fm.beginTransaction()加(watchlistArrayFragment,数据)提交()。
        }其他{
            //我们可以重新使用retainInstanceFragment.expensiveDataStructure甚至
            //配置更改后。
        }
    }
}

不过,有一个问题。每当我毁掉我的老 UIFragment ,并用新的替换 UIFragment 我希望老 RetainInstanceFragment 也将被销毁。这是我如何毁灭和创造新的 UIFragment

 公共类MyFragmentActivity扩展SlidingFragmentActivity
    当在滑动菜单是不同的菜单项//被触发
    //选择。
    公共无效selectActiveContent(国家国家){
        片段片段=新UIFragment(国家);
        。getSupportFragmentManager()调用BeginTransaction()取代(R.id.content,片段).commitAllowingStateLoss()。
    }

但是老 RetainInstanceFragment 永远不会被破坏。

我的猜测是,也许我忘了要执行清理 UIFragment 。因此,我添加以下code

UIFragment

  @覆盖
公共无效onDetach(){
    super.onDetach();
    //为了区分这是否是一个配置的变化,或者我们是
    //删除不掉了片段?
    如果(this.isRemoving()){
        FragmentManager FM = getFragmentManager();
        。fm.beginTransaction()删除(retainInstanceFragment).commit();
    }
}

但是,它不工作的所有时间。我执行几个滑动菜单点击。

  1。 selectActiveContent() - >创建新UIFragment和新RetainInstanceFragment
2. selectActiveContent() - >创建新UIFragment,而是重新使用previous RetainInstanceFragment。 (错误的行为)
3. selectActiveContent() - >创建新UIFragment和新RetainInstanceFragment。
4. selectActiveContent() - >创建新UIFragment,而是重新使用previous RetainInstanceFragment。 (错误的行为)

任何想法如何,我可以正常删除保留实例片段?


解决方案

作为建议的@Luksprog,下面的方法效果。 但是,它仍然没有解释为什么通过 onDetach 做了previous清理不起作用。如果任何人都可以解释为什么这个解决方案工程和previous不,我会非常感激。 :)

UIFragment

  @覆盖
公共无效onDetach(){
    super.onDetach();
}公共无效cleanu pretainInstanceFragment(){
    FragmentManager FM = getFragmentManager();
    。fm.beginTransaction()删除(this.retainInstanceFragment).commit();
}

MyFragmentActivity

 公共类MyFragmentActivity扩展SlidingFragmentActivity
    当在滑动菜单是不同的菜单项//被触发
    //选择。
    公共无效selectActiveContent(国家国家){        // *********
        //解决方案通过@Luksprog建议。有用!
        //但是我不知道为什么它的工作原理和previous没有工作...
        // *********
        片段oldFragment = getSupportFragmentManager()findFragmentById(R.id.content)。
        如果(oldFragment的instanceof UIFragment){
            ((UIFragment)oldFragment).cleanu pretainInstanceFragment();
        }        片段片段=新UIFragment(国家);
        。getSupportFragmentManager()调用BeginTransaction()取代(R.id.content,片段).commitAllowingStateLoss()。
    }


(编辑)由@Luksprog有用的注释


  

片段交易不发的时候了。我的假设是
  ,在onDetach()回调这样做,交易将不会删除
  在保留片段实例之前的UI片段的替换
  交易完成,因此新的UI片段仍然会看到
  保留片段的实例仍然可用,所以它不会创建一个新的
  一。您的previous方法不在片段的精神
  框架,碎片不知道其他的片段和的
  活动管理所有这些,因为它知道更多关于整体
  应用程序的状态。


Currently, I would like to retain an expensive data structure, during configuration changes. I choose not to use Bundle to handle it, as the expensive data structure is not parcelable.

Hence, I use a non-UI Fragment (Called it RetainInstanceFragment), with its setRetainInstance(true) to hold the data structure.

public class RetainInstanceFragment extends Fragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Creating expensive data structure
        expensiveDataStructure = CreateExpensiveDataStructure();

        // Tell the framework to try to keep this fragment around
        // during a configuration change.
        setRetainInstance(true);
    }

    public ExpensiveDataStructure expensiveDataStructure = null;
}

An UI Fragment (Called it UIFragment) will get the expensive data structure from RetainInstanceFragment. Whenever there is configuration changes on UIFragment, UIFragment will always try to get the "cached" RetainInstanceFragment from FragmentManager, before it decides to create a new RetainInstanceFragment.

Example code is as follow.

public class UIFragment extends SherlockListFragment
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        FragmentManager fm = getFragmentManager();

        // Check to see if we have retained the worker fragment.
        retainInstanceFragment = (RetainInstanceFragment)fm.findFragmentByTag("data");

        // If not retained (or first time running), we need to create it.
        if (retainInstanceFragment == null) {
            retainInstanceFragment = new RetainInstanceFragment();
            fm.beginTransaction().add(watchlistArrayFragment, "data").commit();
        } else {
            // We can re-use retainInstanceFragment.expensiveDataStructure even
            // after configuration change.
        }
    }
}

However, there's a problem. Whenever I destroy my old UIFragment, and replace it with new UIFragment, I expect old RetainInstanceFragment will be destroyed as well. Here is how I destroy and create new UIFragment

public class MyFragmentActivity extends SlidingFragmentActivity    
    // Being triggered when there is different menu item in sliding menu being
    // selected.
    public void selectActiveContent(Country country) {
        Fragment fragment = new UIFragment(country);
        getSupportFragmentManager().beginTransaction().replace(R.id.content, fragment).commitAllowingStateLoss();
    }

But old RetainInstanceFragment is never destroyed.

My guess is, perhaps I forget to perform clean up in UIFragment. Hence, I add the following code

UIFragment

@Override
public void onDetach() {
    super.onDetach();
    // To differentiate whether this is a configuration changes, or we are
    // removing away this fragment?
    if (this.isRemoving()) {
        FragmentManager fm = getFragmentManager();
        fm.beginTransaction().remove(retainInstanceFragment).commit();
    }
}

However, it doesn't work all the time. I perform several sliding menu clicks.

1. selectActiveContent() -> Create new UIFragment and new RetainInstanceFragment
2. selectActiveContent() -> Create new UIFragment, but re-use previous RetainInstanceFragment. (Wrong behavior)
3. selectActiveContent() -> Create new UIFragment, and new RetainInstanceFragment.
4. selectActiveContent() -> Create new UIFragment, but re-use previous RetainInstanceFragment. (Wrong behavior)

Any idea how I can properly remove retained instance Fragment?

解决方案

As suggested by @Luksprog, the following method works. However, it still do not explain why the previous cleanup done through onDetach doesn't work. If anyone can explain why this solution works and previous doesn't, I would be very thankful. :)

UIFragment

@Override
public void onDetach() {
    super.onDetach();
}

public void cleanupRetainInstanceFragment() {
    FragmentManager fm = getFragmentManager();
    fm.beginTransaction().remove(this.retainInstanceFragment).commit();
}

MyFragmentActivity

public class MyFragmentActivity extends SlidingFragmentActivity    
    // Being triggered when there is different menu item in sliding menu being
    // selected.
    public void selectActiveContent(Country country) {

        // *******************************************
        // Solution suggested by @Luksprog. It works!
        // But I have no idea why it works and previous doesn't work...
        // *******************************************
        Fragment oldFragment = getSupportFragmentManager().findFragmentById(R.id.content);
        if (oldFragment instanceof UIFragment) {
            ((UIFragment)oldFragment).cleanupRetainInstanceFragment();
        }

        Fragment fragment = new UIFragment(country);
        getSupportFragmentManager().beginTransaction().replace(R.id.content, fragment).commitAllowingStateLoss();
    }


(Edited) Useful comment by @Luksprog

The fragment transactions are not made right away. My assumption was that doing that transaction in the onDetach() callback will not remove the retain fragment instance before the UI fragment's replace transaction finished and so your new UI fragment will still see the retain fragment instance still available, so it will not create a new one. Your previous method is not in the spirit of the fragments framework where fragments are unaware of other fragments and the activity manages all of them as it knows more about the overall application state.

这篇关于如何正确地删除保留的实例片段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆