How to maintain fragment's state in the application

前端 未结 4 1824
长情又很酷
长情又很酷 2020-12-09 22:01

How to maintain fragment\'s state when it is shown within FragmentTabHost?

Thanks to this tutorial, I\'m able to implement FragmentTabHost in my applica

相关标签:
4条回答
  • 2020-12-09 22:47

    Had the same thing in my app. You will need to copy the FragmentTabHost to your project, point your code to use the new custom FragmentTabHost and then change the code of doTabChanged to following implementation:

        private FragmentTransaction doTabChanged(String tabId, FragmentTransaction ft) {
        TabInfo newTab = null;
        for (int i=0; i<mTabs.size(); i++) {
            TabInfo tab = mTabs.get(i);
            if (tab.tag.equals(tabId)) {
                newTab = tab;
            }
        }
        if (newTab == null) {
            throw new IllegalStateException("No tab known for tag " + tabId);
        }
        if (mLastTab != newTab) {
            if (ft == null) {
                ft = mFragmentManager.beginTransaction();
            }
            if (mLastTab != null) {
                if (mLastTab.fragment != null) {
                    ft.hide(mLastTab.fragment);
                }
            }
            if (newTab != null) {
                if (newTab.fragment == null) {
                    newTab.fragment = Fragment.instantiate(mContext,
                            newTab.clss.getName(), newTab.args);
                    ft.add(mContainerId, newTab.fragment, newTab.tag);
                    findViewById(mContainerId).setContentDescription("DEBUG. add fragment to this container");
                } else {
                    if (newTab.fragment.isHidden()){
                        ft.show(newTab.fragment);
                    }
                    else{
                        ft.attach(newTab.fragment); 
                    }
                }
            }
    
            mPreviousTab = mLastTab;
            mLastTab = newTab;
        }
        return ft;
    }
    

    The change that was made is that instead of deattach/attach the fragment, we are doing hide/show

    0 讨论(0)
  • 2020-12-09 22:53

    Modify your Activity to override onSaveInstanceState and your onCreate method to restore from a "savedInstanceState".

    public static final String TAB_STATE = "TAB_STATE";
    
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outstate.putParcelable(TAB_STATE, mTabHost.onSaveInstanceState());
        super.onSaveInstanceState(outState);
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fag_tab_host_main);
    
        mTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
        mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
        if(savedInstanceState==null || savedInstanceState.getParcelable(TAB_STATE)==null){
        mTabHost.addTab(mTabHost.newTabSpec("audio").setIndicator("Audio"),
                AudioContainerFragmentClass.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("video").setIndicator("Video"),
                VideoContainerFragmentClass.class, null);
        } else{
            mTabHost.onRestoreInstanceState(savedInstanceState.getParcelable(TAB_STATE));
        }
    
    }
    
    0 讨论(0)
  • 2020-12-09 22:55

    As stated above you can save and then restore your data via the Bundle, Shared Preferences, or a SQLite db. You may also want to call setRetainInstance(true) on your Fragment. This will stop your fragments from being re-created repeatedly.

    0 讨论(0)
  • 2020-12-09 23:00

    I believe your fragment is being re-instantiated each time you switch tab, which means that your field variables are reset.

    You probably could use the saveInstance bundle to manage the state of your fragment but I find it more useful and simpler to use SharedPreferences. This also has the benefit of keeping the saved state even if your application is restarted.

    To read and write variables to SharedPreferences I use this small helper class:

    public class PreferencesData {
    
    public static void saveString(Context context, String key, String value) {
        SharedPreferences sharedPrefs = PreferenceManager
                .getDefaultSharedPreferences(context);
        sharedPrefs.edit().putString(key, value).commit();
    }
    
    public static void saveInt(Context context, String key, int value) {
        SharedPreferences sharedPrefs = PreferenceManager
                .getDefaultSharedPreferences(context);
        sharedPrefs.edit().putInt(key, value).commit();
    }
    
    
    public static void saveBoolean(Context context, String key, boolean value) {
        SharedPreferences sharedPrefs = PreferenceManager
                .getDefaultSharedPreferences(context);
        sharedPrefs.edit().putBoolean(key, value).commit();
    }
    
    public static int getInt(Context context, String key, int defaultValue) {
        SharedPreferences sharedPrefs = PreferenceManager
                .getDefaultSharedPreferences(context);
        return sharedPrefs.getInt(key, defaultValue);
    }
    
    public static String getString(Context context, String key, String defaultValue) {
        SharedPreferences sharedPrefs = PreferenceManager
                .getDefaultSharedPreferences(context);
        return sharedPrefs.getString(key, defaultValue);
    }
    
    public static boolean getBoolean(Context context, String key, boolean defaultValue) {
        SharedPreferences sharedPrefs = PreferenceManager
                .getDefaultSharedPreferences(context);
        return sharedPrefs.getBoolean(key, defaultValue);
    }
    }
    

    Now, as an example, to save your mIsViewInitiated variable, then in onPause:

    @Override
    protected void onPause() {
        PreferencesData.saveBoolean(this, "isViewInitiated", mIsViewInitiated);
        super.onPause();
    }
    

    And to retrieve it again:

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        try {
            super.onActivityCreated(savedInstanceState);
            Log.e("AudioContainerFragmentClass", "onActivityCreated called");
            // will now be true if onPause have been called
            mIsViewInitiated = PreferencesData.getBoolean(this, "isViewInitiated", false);
            if (!mIsViewInitiated) {
                mIsViewInitiated = true;
                initView();
            }
        } catch (Exception e) {
            printException(e.toString());
        }
    }
    

    Since this example variable tells whether some UI has been loaded, then you might want to set it to false when the activity is destroyed.

    @Override
    protected void onDestroy() {
        PreferencesData.saveBoolean(this, "isViewInitiated", false);
        super.onDestroy();
    }
    

    This answer is just a single option and shows my personal preference, whereas other options might suit your situation better. I would suggest taking a look at http://developer.android.com/guide/topics/data/data-storage.html

    0 讨论(0)
提交回复
热议问题