簡體   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