方向变化的多个碎片

时间:2017-02-24 11:49:03

标签: android android-fragments

Android中的一个令人讨厌的任务已经访问过我,这是维护片段在Orientation上的状态变化。

首先,我已经尝试了StackOver流程中的每个解决方案,而且我只有一个很好的结果,我没有要求。

我能够在方向更改中维护Fragment中的更改,但是当用户切换片段时无法保存片段状态,因此我已经删除了此解决方案并寻找新的更好的解决方案。

我的想法是显示/隐藏片段,而不需要将它们整体替换,因为它们只会被隐藏一小段时间,如果它们不再可见,再次创建它们就没有问题。 / p>

少说话,更多代码。

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使用'Material Drawer'库。

如代码所示,我有三个片段,分别为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();
    }


}

1 个答案:

答案 0 :(得分:0)

所以在尝试解决方案4天后,我坐下来喝了一杯,然后我找到了解决这个恼人问题的方法。

由于我在解释进度或步骤方面不是那么棒,我会直截了当地尽力做到亲们的答案。

首先,由于我的应用程序有一个导航抽屉,并且我想显示/隐藏片段而不重新创建它们,所以在不花费太多时间的情况下实现这样的任务是一项艰巨的任务,所以我需要了解生命周期和发生的事情,因此我已经将Log添加到每一步,以了解引擎盖下发生了什么。

当应用启动时,您只切换片段.show().hide(),该捆绑包将为空。因此

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子句中。首先我们检查所选片段(保存在包中)是否确实可以加载,如果是,我们分配它,如果它不可见,则意味着其他片段可见,因此我们称之为{{1 }}。

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

有了这段代码,我几乎可以解决每一个烦人的错误希望

ShowHideFrags的代码:

ShowHideFrags(int x)

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

希望这个答案对您有所帮助,随时提出并/或更正此答案。