(2013-01-30 更新) 接續Android TabHost中切換Activity記錄了使用ActivityGroup達到在TabHost中切換Activity的方法,也在Android Screen Orientation Event螢幕方向處理+Acitivity Liftcycle記錄了當螢幕方向改變時的處理,這篇小蛙繼續記錄用FragmentActivity取代ActivityGroup,透過FragmentActivity內建的BackStack來管理倒退歷程。

這個程式碼小蛙很早之前就實作完成,但礙於螢幕方向改變時的處理一直還找不到解決辦法,所以一直拖到現在,不囉嗦直接進程式碼。
MainTabActivity.java : 主要的Tabhost Activity。

public class MainTabActivity extends Activity {
    private TabHost mHost;
    // 在Activity中使用Tabhost必須要有LocalActivityManager物件來設定
    LocalActivityManager lam;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        // main layout採用預設的Tabhost
        mHost = (TabHost) findViewById(android.R.id.tabhost);
        lam = new LocalActivityManager(MainTabActivity.this, false);
        lam.dispatchCreate(savedInstanceState);
        mHost.setup(lam);
        mHost.addTab(mHost.newTabSpec("Tab1").setIndicator("Tab1").setContent(new Intent(MainTabActivity.this, FragmentActivity1.class)));
        mHost.addTab(mHost.newTabSpec("Tab2").setIndicator("Tab2").setContent(new Intent(MainTabActivity.this, FragmentActivity2.class)));
    }
    @Override
    protected void onPause() {
        // 漏掉這行一定出錯
        lam.dispatchPause(isFinishing());
        super.onPause();
    }
    @Override
    protected void onResume() {
        // 漏掉這行一定出錯
        lam.dispatchResume();
        super.onResume();
    }
}

FragmentActivity1.java : 第一個Tab中用來管理Fragment的FragmentActivity。(2012-05-07更新)經由Jay留言後,小蛙詳細測了一下,發現FragmentActivity主畫面中的Button是沒辦法消失的(因為FragmentActivity的目的關係),因此改成這樣,讓FragmentActivity純粹當成容器,主要的內容還是以Fragment為主。(這個方法不是唯一,但是一個可行的方法,應該也有更好的做法!)

public class FragmentActivity1 extends FragmentActivity {
    public static FragmentManager fm;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_activity_1);
        fm = getSupportFragmentManager();
        // 只當容器,主要內容已Fragment呈現
        initFragment(new Fragment1());
    }
    // 切換Fragment
    public static void changeFragment(Fragment f){
        changeFragment(f, false);
    }
    // 初始化Fragment(FragmentActivity中呼叫)
    public static void initFragment(Fragment f){
        changeFragment(f, true);
    }
    private static void changeFragment(Fragment f, boolean init){
        FragmentTransaction ft = fm.beginTransaction();
        ft.replace(R.id.simple_fragment, f);
        if(!init)
            ft.addToBackStack(null);
        ft.commit();
    }
}

Fragment1.java : 真正使用到的Fragment。

public class Fragment1 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_1, container, false);
        Button tv = (Button)v.findViewById(R.id.button2);
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 直接呼叫FragmentActivity1的靜態方法來做切換
                FragmentActivity1.changeFragment(new Fragment2());
            }
        });
        return v;
    }
}

fragment_acitivity_1.xml : FragmentActivity layout。(2012-05-07修改) FragmentActivity只用來當容器,而不真正呈現內容(僅把Fragment內容載入)。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:id="@+id/simple_fragment">
</LinearLayout>

fragment1.xml:Fragment layout,FragmentActivity載入的真正內容。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">
    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button" />
</LinearLayout>

最後別忘了在AndroidManifest.xml中加入android:configChanges=”orientation”設定。這樣就成功的使用在Activity中使用Tabhost並且透過FragmentActivity來管理Fragment囉!
2013-01-30 許多網友反應無法下載 MediaFire 的檔案,補上新連結。範例檔下載
2012-10-22 範例檔下載

21 Replies to “Android Tabhost with FragmentActivity”

  1. 多谢lz,tab实现的方式茫茫多,得每种都研究研究找到最适合自己需求的实现方式

  2. LocalActivityManager现在是个过期的类,不太想使用它,而TabHost直接用setup()方法会报错,看了网上其他的解决办法没能很好的解决,不知道版主有没有考虑过这个问题

  3. hi 非常感谢LZ共享这个方法,很实用。不过有个问题,一直没解决,请LZ帮忙看下,
    我在其中一个FRAGMENT中的 onCreateView 里调用了 startActivityForResult
    Intent securityIntent = new Intent(layoutView.getContext(),
    SecurityCheckActivity.class)
    startActivityForResult(securityIntent, SecurityCheckRequestCode);
    可是怎么都接收不到 onActivityResult事件,请问要怎么处理?

    1. Dear dean:
      在 Fragment 下是沒有辦法接收到 startActivityForResult 結果的喔!
      把 startActivityForResult(securityIntent, SecurityCheckRequestCode);
      改成
      getActivity().getParent().startActivityForResult(securityIntent, SecurityCheckRequestCode);
      透過 MainTabActivity 來呼叫 startActivityForResult,
      同時也要使用 MainTabActivity 的 onActivityResult 來處理這個事件!
      Good Luck !!

  4. 楼主真是太厉害了,解决了我的一个大问题,不知能不能和您深入的交流下,对于这个问题我还有点疑惑。我的qq是22340991 期待您的回复。 祝新年快乐

  5. 你好,我在找一个Tab的解决方案,要求如下:
    1. 多Tab,Tab页在下方,效果可以自定义.
    2. 每个Tab内可能会有多个子Activity.即在Tab也内新建的子Activity可以在Tab内部,也可以是是独立的Activity.
    3. 在每个Tab内子Actvitiy保证回退历史
    4. 能检测到已经到最后一个子Activity,并能提示用户退出
    你的代码我这里无法下载,无法知道最后的效果是否能满足我的需求.请问你是否方便把代码放到其他地方或者发一个给我[email protected]吗?谢谢.

  6. hi 你好,我看了DEMO示例,也成功实现了基本的跳转。
    想请教下,怎么实现页面之前的传参呢?
    之前两个ACTIVITY之前可以通过Intent 用Buddle进行传参,
    可是fragment我还是摸不到头脑~~~

    1. Dear dean:
      小蛙最近比較沒有時間去試看看,而之前開發的時候也沒有遇到這個需求,
      (寫這個範例只是想先知道怎麼用,然後記錄起來)
      不過小蛙問了一下同事,同事倒是提到可以試試看用fragment建構子的方式來傳遞,
      (至於可不可行小蛙就不清楚了,理論上聽起來應該是可以,實際上要試試看)
      Good Luck!!! ^_____^

      1. thx,我最近也是遇到这种需求才想起来研究的。
        主要就是想做一个一直存在的tabhost。继续研究,感谢

  7. 蛙大你好,
    我也是正要從TabHost中切換Activity的實作方式,改成Fragment Activity
    想請問有此一範例的程式碼嗎?因為我有點搞迷糊了
    是不是改成Fragment Activity後
    原先在TabHost切換Activity的裡的child activiy換到fragment activity就變成了fragment
    然後透過fragment activity的FragmentManager來切換各個fragment,並將其內容在id名稱為simple_fragmen的fragment layout當中做切換?

    1. Dear Jay:
      不好意思造成您的困擾,小蛙今天看了一下Code,才發現問題 ~ >_< 現在文章已經更新囉!先下載範例看看效果是不是自己要的, 不好意思!>____< 您說的沒錯原本的 TabHost 中變成啟動的是 FragmentActivity, 而新的作法中FragmentActivity當成容器,實際呈現以Fragment為主! 範例檔

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *