How to maintain fragment state in application

How to maintain fragment state when it is displayed inside FragmentTabHost?

Thanks to this tutorial, I can implement FragmentTabHost in my application.

I intend to create an application whose main action contains some tabs (which are located at the top of the application). Clicking on each tab opens a new fragment under the tabs.

The problem is when I click on the tab to do something, and then go to the duster tab, which opens a new fragment, and then returns to the first tab - my changes are not supported here.

Flow:

enter image description here

I really need to implement this logic. If my approach is wrong, suggest an alternative.

thanks

Code:

Primary activity

 public class FagTabHostMain extends FragmentActivity { FragmentTabHost mTabHost; @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); mTabHost.addTab(mTabHost.newTabSpec("audio").setIndicator("Audio"), AudioContainerFragmentClass.class, null); mTabHost.addTab(mTabHost.newTabSpec("video").setIndicator("Video"), VideoContainerFragmentClass.class, null); } @Override public void onBackPressed() { boolean isPopFragment = false; String currentTabTag = mTabHost.getCurrentTabTag(); if (currentTabTag.equals("audio")) { isPopFragment = ((AudioContainerFragmentClass) getSupportFragmentManager() .findFragmentByTag("audio")).popFragment(); } else if (currentTabTag.equals("video")) { isPopFragment = ((VideoContainerFragmentClass) getSupportFragmentManager() .findFragmentByTag("video")).popFragment(); } // Finish when no more fragments to show in back stack finish(); } } 

Primary occupation

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <android.support.v4.app.FragmentTabHost android:id="@android:id/tabhost" android:layout_width="match_parent" android:layout_height="match_parent" > <!-- Not Using this one right now --> <FrameLayout android:id="@android:id/tabcontent" android:layout_width="0dip" android:layout_height="0dip" android:layout_weight="0" /> </android.support.v4.app.FragmentTabHost> <FrameLayout android:id="@+id/realtabcontent" android:layout_width="match_parent" android:layout_height="0dip" android:layout_weight="1" /> </LinearLayout> 

AudioContainerFragmentClass

 public class AudioContainerFragmentClass extends Fragment implements OnClickListener { final String TAG = "AudioContainerFragmentClass"; private Boolean mIsViewInitiated = false; private boolean addToBackStack = true; private Button bNextFragment; private LinearLayout linearLayout; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { try { Log.e("AudioContainerFragmentClass", "onCreateView called"); linearLayout = (LinearLayout) inflater.inflate( R.layout.audio_fragment_container, container, false); } catch (Exception e) { printException(e.toString()); } return linearLayout; } @Override public void onActivityCreated(Bundle savedInstanceState) { try { super.onActivityCreated(savedInstanceState); Log.e("AudioContainerFragmentClass", "onActivityCreated called"); if (!mIsViewInitiated) { mIsViewInitiated = true; initView(); } } catch (Exception e) { printException(e.toString()); } } private void initView() { try { Log.e("AudioContainerFragmentClass", "initView called"); bNextFragment = (Button) linearLayout .findViewById(R.id.bNextFragment); bNextFragment.setOnClickListener(this); replaceFragment(new AudioFragment(), false); } catch (Exception e) { printException(e.toString()); } } private void replaceFragment(AudioFragment audioFragment, boolean b) { try { FragmentTransaction ft = getChildFragmentManager() .beginTransaction(); if (addToBackStack) { ft.addToBackStack(null); } ft.replace(R.id.audio_sub_fragment, audioFragment); ft.commit(); getChildFragmentManager().executePendingTransactions(); } catch (Exception e) { printException(e.toString()); } } // Called from FagTabHostMain Activity public boolean popFragment() { boolean isPop = false; try { Log.e("AudioContainerFragmentClass", "popFragment called"); if (getChildFragmentManager().getBackStackEntryCount() > 0) { isPop = true; getChildFragmentManager().popBackStack(); } } catch (Exception e) { printException(e.toString()); } return isPop; } @Override public void onClick(View arg0) { TextView tv = (TextView)getActivity().findViewById(R.id.tvaudioTitle); tv.setText("Text changed"); } private void printException(String string) { Log.e("__ERRORR__", string); } } 

AudioFragment

 public class AudioFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.audio_sub_fragment, container, false); return view; } } 
+6
source share
4 answers

In my application it was the same. You will need to copy FragmentTabHost into your project, specify the code to use the new custom FragmentTabHost , and then change the doTabChanged code to the next 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 made is that instead of the deattach/attach fragment we do hide/show

+20
source

I believe that your fragment is updated every time you switch the tab, which means that your field variables are reset.

You can probably use the saveInstance package to control the state of your fragment, but I find it more useful and easier to use SharedPreferences. It also has the advantage of saving a saved state, even if your application is restarted.

To read and write variables to SharedPreferences, I use this little 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 the mIsViewInitiated variable, then in onPause:

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

And return 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 indicates whether any user interface has been loaded, then you can set it to false when destroying the activity.

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

This answer is just one option and shows my personal preferences, while other options are better suited to your situation. I would suggest taking a look at http://developer.android.com/guide/topics/data/data-storage.html

+2
source

Change your activity to override onSaveInstanceState and the onCreate method to restore from "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
source

As stated above, you can save and restore your data through Bundle, Shared Preferences or SQLite db. You can also call setRetainInstance(true) on a Fragment . This will stop repeating again.

0
source

Source: https://habr.com/ru/post/955826/


All Articles