如何在FragmentTabHost中显示片段的状态?
感谢这个tutorial,我可以在我的应用程序中实现FragmentTabHost
。
我的目的是创建一个应用程序,其主要活动包含一些标签(在整个应用程序的顶部)。单击每个选项卡将在选项卡下方打开一个新片段。
问题是当我点击选项卡时执行某些操作,然后转到另一个选项卡,该选项卡会打开一个新的片段,然后返回到第一个选项卡 - 此处的更改不会保留。
流量:
我真的需要实现这个逻辑。如果我的方法有误,请建议替代方案。
由于
代码:
主要活动
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();
}
}
主要活动布局
<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;
}
}
答案 0 :(得分:19)
在我的应用中有同样的事情。
您需要将FragmentTabHost复制到项目中,将代码指向使用新的自定义FragmentTabHost
,然后将doTabChanged
的代码更改为以下实现:
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;
}
所做的更改是代替deattach/attach
片段,我们正在进行hide/show
答案 1 :(得分:2)
我相信每次切换标签时都会重新实例化您的片段,这意味着您的字段变量会被重置。
您可能可以使用saveInstance包来管理片段的状态,但我发现使用SharedPreferences更有用也更简单。即使您的应用程序重新启动,这也有保持保存状态的好处。
要读取和写入SharedPreferences的变量,我使用这个小助手类:
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);
}
}
现在,举个例子,保存你的mIsViewInitiated变量,然后在onPause:
@Override
protected void onPause() {
PreferencesData.saveBoolean(this, "isViewInitiated", mIsViewInitiated);
super.onPause();
}
再次检索它:
@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());
}
}
由于此示例变量指示是否已加载某个UI,因此您可能希望在销毁活动时将其设置为false。
@Override
protected void onDestroy() {
PreferencesData.saveBoolean(this, "isViewInitiated", false);
super.onDestroy();
}
这个答案只是一个选项,显示了我个人的偏好,而其他选项可能更适合您的情况。我建议你看看http://developer.android.com/guide/topics/data/data-storage.html
答案 2 :(得分:0)
修改您的Activity以覆盖onSaveInstanceState,并使用onCreate方法从“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));
}
}
答案 3 :(得分:0)
如上所述,您可以通过Bundle,Shared Preferences或SQLite数据库保存并恢复数据。您可能还想在Fragment上致电setRetainInstance(true)
。这将阻止您的片段重复重新创建。