How to maintain fragment's state when it is shown within FragmentTabHost?
Thanks to this tutorial, I'm able to implement FragmentTabHost
in my application.
My intention is to create an app whose main activity contains some tabs (which sticks on the top throughout the app). Clicking each tab opens a new fragment below the tabs.
Issue is when I click on a tab do something, then go to anther tab which opens a new fragment, then comes back to first tab - my changes here are not maintained.
Flow:
I really need to implement this logic. If my approach is wrong, please suggest alternative.
Thanks
Code:
Main 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();
}
}
Main activity layout
<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;
}
}
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