7

在 FragmentTabHost 中显示时如何维护片段的状态?

感谢本教程,我能够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);
    }
}

音频片段

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;
    }
}
4

4 回答 4

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

于 2013-10-19T15:00:45.310 回答
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,因此您可能希望在销毁 Activity 时将其设置为 false。

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

此答案只是一个选项,显示了我的个人喜好,而其他选项可能更适合您的情况。我建议看看http://developer.android.com/guide/topics/data/data-storage.html

于 2013-10-14T19:05:53.050 回答
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));
    }

}
于 2013-10-16T14:34:24.267 回答
0

如上所述,您可以通过 Bundle、Shared Preferences 或 SQLite db 保存然后恢复您的数据。您可能还想调用setRetainInstance(true)您的Fragment。这将阻止您的片段被重复重新创建。

于 2013-10-17T15:25:50.877 回答