繁体   English   中英

方向变化的多个片段

[英]Multiple Fragments on Orientation Changes

我在Android上遇到了一个烦人的任务,该任务是在定向更改时维护片段的状态。

首先,我在StackOver流上尝试了所有解决方案,但结果只有我没有要求的好结果。

我能够在“方向”更改上保留“片段”中的更改,但是当用户切换片段时,无法保存片段状态,因此我删除了此解决方案,并开始寻找新的更好的解决方案。

我的想法是显示/隐藏片段,而不需要整体替换它们,因为它们将仅隐藏一小段时间,并且如果它们不再可见,则再次创建它们也没有问题。

少说话,多代码。

int mID = (int) drawerItem.getIdentifier();

                        String mTag = "";
                        switch (mID){
                            case 0:
                                mTag = "ViewPager";
                                break;
                            case 1:
                                mTag = "Browser";
                                break;
                            case 2:
                                mTag = "Settings";
                                break;
                        }

                        if (savedInstanceState == null) {
                            ShowHideFrags(mID);
                        } else {
                            switch (mID){
                                case 0:
                                    Log.i("ASDSADSA","4");
                                    mViewPager = (ViewPagerFragment) getSupportFragmentManager().findFragmentByTag(mTag);
                                    ShowHideFrags(mID);
                                    break;
                                case 1:
                                    Log.i("ASDSADSA","5");
                                    mWebFrag = (WVFragment) getSupportFragmentManager().findFragmentByTag(mTag);
                                    ShowHideFrags(mID);
                                    break;
                                case 2:
                                    Log.i("ASDSADSA","6");
                                    mSettings = (SettingsFragment) getSupportFragmentManager().findFragmentByTag(mTag);
                                    ShowHideFrags(mID);
                                    break;
                            }
                        }

该代码处理“导航”抽屉中的单击,我正在使用Mikepenz “材料抽屉”库。

如代码所示,我有三个片段,分别是ViewPagerBrowserSettings

我的问题是,重新创建它,没有方向和getFragment方法,代码中没有问题,但是当我添加对此更改的支持时,将重新创建该片段。 我已经尝试了很多次来更改代码,记录更改并查看问题所在。

在第一次启动时,它将调用ShowHideFrags(int x)方法,然后转到else

ShowHideFrags(int x)的代码:

private void ShowHideFrags(int SelectedFrag){
    if(mFragmentManager == null)
        mFragmentManager = getSupportFragmentManager();

    android.support.v4.app.FragmentTransaction ft = mFragmentManager.beginTransaction();
    switch (SelectedFrag){
        case 0:
            if(mViewPager == null)
                mViewPager = new ViewPagerFragment();

            if(!mViewPager.isAdded())
                ft.add(R.id.fragment,mViewPager,"Viewpager");

            if(!mViewPager.isVisible()){
                if((mSettings != null && mSettings.isVisible()))
                    ft.hide(mSettings);

                if((mWebFrag != null && mWebFrag.isVisible()))
                    ft.hide(mWebFrag);

                ft.show(mViewPager);
            } else {
                if((mSettings != null && mSettings.isVisible()))
                    ft.hide(mSettings);

                if((mWebFrag != null && mWebFrag.isVisible()))
                    ft.hide(mWebFrag);
            }

            ft.commit();
            break;
        case 1:
            if(mWebFrag == null)
                mWebFrag = new WVFragment();


            if(!mWebFrag.isAdded())
                ft.add(R.id.fragment,mWebFrag,"Browser");

            if(!mWebFrag.isVisible()) {
                if((mSettings != null && mSettings.isVisible()))
                    ft.hide(mSettings);

                if(mViewPager != null && mViewPager.isVisible())
                    ft.hide(mViewPager);

                ft.show(mWebFrag);

            } else {
                if((mSettings != null && mSettings.isVisible()))
                    ft.hide(mSettings);

                if((mViewPager != null && mViewPager.isVisible()))
                    ft.hide(mViewPager);
            }
            ft.commit();
            break;
        case 2:
            if(mSettings == null)
                mSettings = new SettingsFragment();

            if(!mSettings.isAdded())
                ft.add(R.id.fragment,mSettings,"Settings");

            if(!mSettings.isVisible()) {
                if((mViewPager != null && mViewPager.isVisible()))
                    ft.hide(mViewPager);

                if((mWebFrag != null && mWebFrag.isVisible()))
                    ft.hide(mWebFrag);

                ft.show(mSettings);
            } else {
                if((mViewPager != null && mViewPager.isVisible()))
                    ft.hide(mViewPager);

                if((mWebFrag != null && mWebFrag.isVisible()))
                    ft.hide(mWebFrag);
            }
            ft.commit();
            break;
    }
}

我的onSaveInstanceState的代码:

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    try{
        long mSelectedItem = result.getCurrentSelection();
        android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
        android.support.v4.app.Fragment currentFragment = fragmentManager.findFragmentById(R.id.fragment);
        getSupportFragmentManager().putFragment(outState,currentFragment.getTag(),currentFragment);
        outState.putLong("SelectedItem",mSelectedItem);
    } catch (Exception e){
        e.printStackTrace();
    }


}

因此,在尝试解决方案4天后,我坐下来喝了一杯不错的饮料,然后我想出了一种解决此烦人问题的方法。

因为我在解释进度或步骤方面并不出色,所以我会直截了当,并尽我所能,像专业人士回答人们一样。

首先,由于我的应用程序具有导航抽屉,并且我想显示/隐藏片段而无需重新创建它们,因此要花费很长时间来实现这样的任务是一项艰巨的任务,因此我需要了解生命周期以及发生了什么,因此我在每个步骤中都添加了Log,以了解幕后发生的事情。

当应用启动时,仅切换片段.show().show() .hide() ,捆绑将为null。 因此

if (savedInstanceState == null) {
  LogMessage("Bundle Is Null, normal stuff");
  ShowHideFrags(mID);
}

最后使用的方法ShowHideFrags将被附加,它的任务是检查片段是否为空,并隐藏未被选择的片段,并显示所选的片段,如果为空,则该方法将创建一个新片段并添加它。

第一件事很容易,当方向发生时,捆绑包不会为空,它将具有已保存的片段,首先我们需要将其保存在捆绑包中。

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    long mSelectedItem = result.getCurrentSelection();

    try{
        FragmentManager mFM = getSupportFragmentManager();
        Fragment currentFragment = null;


        switch (mTag){
            case "ViewPager":
                currentFragment = mViewPager;
                break;
            case "Browser":
                currentFragment = mWebFrag;
                break;
            case "Settings":
                currentFragment = mSettings;
                break;
        }

        mFM.putFragment(outState,mTag,currentFragment);
        LogMessage(String.format("The following fragment '%1$s' with position %2$s was saved",mTag,String.valueOf(mSelectedItem)));
    } catch (Exception e){
        e.printStackTrace();
    }
    outState.putLong("SelectedItem",mSelectedItem);
}

将提出一个问题,为什么不使用硬编码的字符串而不将其作为变量? 因为我很懒。 重要说明,请勿通过findFragmentByTag方法保存当前片段,它会为您提供最后一个应用的片段,而不是选定的片段,因此,我必须手动检查是否选择了碎片。

别忘了提到片段,我在代码开头有以下片段

private ViewPagerFragment mViewPager;
private WVFragment mWebFrag;
private SettingsFragment mSettings;

mTag是片段标签,在导航抽屉的onClick方法中,我通过以下代码添加了mTag值:

switch (mID) {
  case 0:
  mTag = "Viewpager";
  break;

  case 1:
  mTag = "Browser";
  break;

  case 2:
  mTag = "Settings";
  break;
}

现在,我们分配了mTag,当bundle为null时,检查完成,并且bundle的保存部分也完成了,现在,当bundle不为null时,我们需要进行检查。

首先是代码,然后是解释

if(getSupportFragmentManager().findFragmentByTag(mTag) != null){
                                        LogMessage(String.format("Fragment with tag '%1$s' was found",mTag));
                                        mViewPager = (ViewPagerFragment) getSupportFragmentManager().findFragmentByTag(mTag);
                                        if(!mViewPager.isVisible()) {
                                            LogMessage("Not Visible");
                                            ShowHideFrags(mID);
                                        } else {
                                            LogMessage("Visible");
                                        }
                                    } else {
                                        LogMessage(String.format("Fragment with tag '%1$s' was NOT found", mTag));

                                           if(!ReturnCurrentFragment().equalsIgnoreCase(mTag)){
                                            LogMessage("Not the Same");
                                            ShowHideFrags(mID);
                                        } else {
                                            LogMessage("It's the Same");
                                        }
                                    }

private Fragment ReturnCurrentFragment(){
    return getSupportFragmentManager().findFragmentById(R.id.fragment);
}

当bundle不为null时,以上代码位于else子句中。 首先,我们检查选定的片段(已保存在捆绑包中)是否确实可以加载,如果可以加载,我们将其分配,如果不可见,则意味着其他片段可见,因此我们将其ShowHideFrags

当片段可见时,我们什么也不做。 此外,我们检查它是否不在捆绑包中,如果不存在,是否已经可以重新加载,所以我们不会两次创建它* 1。

有了这个代码,我已经几乎抓住每一个恼人的错误护理会发生的希望

ShowHideFrags(int x)的代码:

private void ShowHideFrags(int SelectedFrag){
    if(mFragmentManager == null)
        mFragmentManager = getSupportFragmentManager();

    android.support.v4.app.FragmentTransaction ft = mFragmentManager.beginTransaction();
    switch (SelectedFrag){
        case 0:
            if(mViewPager == null)
                mViewPager = new ViewPagerFragment();

            if(!mViewPager.isAdded())
                ft.add(R.id.fragment,mViewPager,"Viewpager");

            if(!mViewPager.isVisible()){
                if((mSettings != null && mSettings.isVisible()))
                    ft.hide(mSettings);

                if((mWebFrag != null && mWebFrag.isVisible()))
                    ft.hide(mWebFrag);

                ft.show(mViewPager);
            } else {
                if((mSettings != null && mSettings.isVisible()))
                    ft.hide(mSettings);

                if((mWebFrag != null && mWebFrag.isVisible()))
                    ft.hide(mWebFrag);
            }

            ft.commit();
            break;
        case 1:
            if(mWebFrag == null)
                mWebFrag = new WVFragment();


            if(!mWebFrag.isAdded())
                ft.add(R.id.fragment,mWebFrag,"Browser");

            if(!mWebFrag.isVisible()) {
                if((mSettings != null && mSettings.isVisible()))
                    ft.hide(mSettings);

                if(mViewPager != null && mViewPager.isVisible())
                    ft.hide(mViewPager);

                ft.show(mWebFrag);

            } else {
                if((mSettings != null && mSettings.isVisible()))
                    ft.hide(mSettings);

                if((mViewPager != null && mViewPager.isVisible()))
                    ft.hide(mViewPager);
            }
            ft.commit();
            break;
        case 2:
            if(mSettings == null)
                mSettings = new SettingsFragment();

            if(!mSettings.isAdded())
                ft.add(R.id.fragment,mSettings,"Settings");

            if(!mSettings.isVisible()) {
                if((mViewPager != null && mViewPager.isVisible()))
                    ft.hide(mViewPager);

                if((mWebFrag != null && mWebFrag.isVisible()))
                    ft.hide(mWebFrag);

                ft.show(mSettings);
            } else {
                if((mViewPager != null && mViewPager.isVisible()))
                    ft.hide(mViewPager);

                if((mWebFrag != null && mWebFrag.isVisible()))
                    ft.hide(mWebFrag);
            }
            ft.commit();
            break;
    }
}

* 1:例如,让我们删除该代码块,当该片段不存在且该块也不存在时,当您尝试切换时,所选片段可能会覆盖在前一个片段上,或者可能显示空白片段,因此如果它等于当前片段,则需要在其中显示ShowHideFrags,因此我们无需再次重新创建它,并使两个相同的片段彼此重叠。

希望此答案对您有帮助,请随时提出和/或更正此答案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM