當前項目使用的是TabHost+Activity進行分頁,目前要作個報表功能,須要在一個Tab頁內進行Activity的切換。比方說我有4個Tab頁分別爲Tab1,Tab2,Tab3,Tab4,如今的需求是須要將Tab1內的Activity動態切換。找了不少資料最終使用了ActivityGroup解決了問題,在這過程當中順便嘗試了一下使用Fragment+FragmentActivity+TabHost和Fragment+FragmentActivity+ActionBar試圖淘汰掉舊版的ActivityGroup和TabHost,可是發現若是要使用Fragment,我須要修改已有的各個Tab頁內的Activity,工做量較大,而使用ActionBar還有着許多版本兼容性問題,而且ActionBar不支持多層嵌套,最終放棄。如今寫一下我我的實驗用的TabHost+ActivityGroup、Fragment+FragmentActivity+TabHost和Fragment+FragmentActivity+ActionBar的Demo,供參考。android
首先是TabHost+ActivityGroup。在最初的想法中,我是使用經過清空TabHost現有內容,再添加新內容來實現動態加載Tab頁效果,具體代碼不說了,舉個例子:我有4個Tab頁分別爲Tab一、Tab二、Tab3和Tab4,存放4個Activity分別爲Tab1Activity、Tab2Activity、Tab3Activity和Tab4Activity,如今我須要將Tab1位置的Tab1Activity變成Tab5Activity,個人作法是先所有清空,而後從新添加Tab一、Tab二、Tab3和Tab4,在添加的時候,將Tab1指向的Activity變成Tab5Activity。這種方法無疑是很是蠢得,並且在這一切換以後,會發現Ta5Activity的生命週期出現異常,每次在Tab1和其餘Tab之間切換時,Ta5Activity都會被destroy掉從新create。這個問題我至今沒找到緣由。app
而後找到了ActivityGroup。ActivityGroup也是繼承至Activity類,能夠當作是一個Actvity的容器類。 以上面的例子爲例,當咱們把ActivityGroup放入Tab1內時,咱們就能夠經過管理ActivityGroup來達到動態切換Activity的效果,貼上ActivityGroup的代碼:ide
public class ActivityGroup1 extends ActivityGroup { private ScrollView container = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.layout); //存放Activity的容器 container = (ScrollView) findViewById(R.id.containerBody); // 模塊1 ImageView btnModule1 = (ImageView) findViewById(R.id.btnModule1); btnModule1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //清空容器內現有內容 container.removeAllViews(); //加載activity container.addView(getLocalActivityManager().startActivity( "Module1", new Intent(ActivityGroup1.this, Tab1Activity.class) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)) .getDecorView()); } }); // 模塊2 ImageView btnModule2 = (ImageView) findViewById(R.id.btnModule2); btnModule2.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { container.removeAllViews(); container.addView(getLocalActivityManager().startActivity( "Module2", new Intent(ActivityGroup1.this, Tab2Activity.class) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)) .getDecorView()); } }); // 模塊3 ImageView btnModule3 = (ImageView) findViewById(R.id.btnModule3); btnModule3.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { container.removeAllViews(); container.addView(getLocalActivityManager().startActivity( "Module3", new Intent(ActivityGroup1.this, Tab3Activity.class) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)) .getDecorView()); } }); } }
layout.xmlthis
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:orientation="vertical" android:layout_height="fill_parent"> <LinearLayout android:gravity="center_horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/cust_title" android:textColor="@android:color/white" android:textSize="28sp" android:text="模塊1" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView> </LinearLayout> <!-- 中間動態加載View --> <ScrollView android:measureAllChildren="true" android:id="@+id/containerBody" android:layout_weight="1" android:layout_height="fill_parent" android:layout_width="fill_parent"> </ScrollView> <LinearLayout android:background="@android:color/black" android:layout_gravity="bottom" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <!-- 功能模塊按鈕1 --> <ImageView android:id="@+id/btnModule1" android:src="@android:drawable/ic_dialog_dialer" android:layout_marginLeft="7dp" android:layout_marginTop="3dp" android:layout_marginBottom="3dp" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <!-- 功能模塊按鈕2 --> <ImageView android:id="@+id/btnModule2" android:src="@android:drawable/ic_dialog_info" android:layout_marginLeft="7dp" android:layout_marginTop="3dp" android:layout_marginBottom="3dp" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <!-- 功能模塊按鈕3 --> <ImageView android:id="@+id/btnModule3" android:src="@android:drawable/ic_dialog_alert" android:layout_marginLeft="7dp" android:layout_marginTop="3dp" android:layout_marginBottom="3dp" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> </LinearLayout>
在TabHost中的調用方式和普通的activity同樣spa
TabSpec tabSpec=mtabHost.newTabSpec("1").setIndicator("TAB1").setContent( new Intent(this, FragmentActivity1.class)); mtabHost.addTab(tabSpec);
這樣經過點擊三個按鈕就能達到動態切換Activity的效果了。3d
順便說下,當ActivityGroup內嵌套Activity時,Activity的生命週期跟TabHost內嵌套Activity同樣。具體的百度。code
較新的版本中TabHost和ActivityGroup都已經被淘汰了,取而代之的是FragmentActivity+Fragment。但我很疑惑Fragment是否真能徹底取代ActivityGroup的效果。就拿上述功能來講,我要想使用FragmentActivity替換ActivityGroup,那麼我現有的Activity就必須重寫,改裝成Fragment。這種狀況下,我在其餘地方要使用這些Activity該怎麼辦呢?我沒找到如何使用Fragment裝載Activity的辦法,因此暫時就無法用FragmentActivity替代ActivityGroup了。貼下使用FragmentActivity+Fragment+TabHost的實現代碼:xml
Fragment1Activity:blog
public class FragmentActivity1 extends FragmentActivity{ public static FragmentManager fm; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.fragment_acitivity_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(); } }
這裏的FragmentActivity1並不顯示具體內容,只作Fragment得容器使用,具體顯示內容經過調用changeFragment方法動態加載。繼承
Fragment1和Fragment2的代碼以下,點擊按鈕二者互相切換:
public class Fragment1 extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment1, 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; } }
public class Fragment2 extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment2, 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 Fragment1()); } }); return v; } }
一樣,在TabHost添加中跟普通的Activity同樣:
TabSpec tabSpec=mtabHost.newTabSpec("1").setIndicator("TAB1").setContent( new Intent(this, FragmentActivity1.class)); mtabHost.addTab(tabSpec);
這三者的layout都很簡單,就不寫了。對比ActivityGroup方法發現,其實二者實現思路是同樣的,都是先用一個「容器」(ActivityGroup和FragmentActivity)佔住Tab1的位置,而後每次相應時,經過改變「容器」內的元素來達到動態改變的效果,區別就是ActivityGroup存放的是Activity,而FragmentActivity存放的是Fragment。(本人目前已經知道能夠將Fragment嵌套到Activity中,是否有方法能夠將Activity嵌套到Fragment中呢?那麼就能夠達到兩個方法的徹底兼容了,而不用像我我擔憂的,須要改造目前已有的Activity成Fragment來達到使用FragmentActivity替換ActivityGroup的效果)
最後說下ActionBar+FragmentActivity+Fragment來替換掉TabHost。在使用過程當中發現這個ActionBar限制有點多,因而捨棄了,貼下實現代碼。
public class FragmentActivity1 extends FragmentActivity implements ActionBar.TabListener{ public static FragmentManager fm; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.fragment_acitivity_1); fm = getSupportFragmentManager(); ActionBar actionBar=this.getActionBar(); this.getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); this.getActionBar().setDisplayShowTitleEnabled(false); this.getActionBar().setDisplayShowHomeEnabled(false); setBar("Tab 1"); setBar("Tab 2"); setBar("Tab 3"); setBar("Tab 4"); // 只當容器,主要內容已Fragment呈現 initFragment(new Fragment1()); } /** * */ private void setBar(String s) { Tab tab = this.getActionBar().newTab(); tab.setContentDescription(s); tab.setText(s); tab.setTabListener(this); getActionBar().addTab(tab); } // 切換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(); } @Override public void onTabReselected(Tab arg0, android.app.FragmentTransaction arg1) { // TODO Auto-generated method stub } @Override public void onTabSelected(Tab arg0, android.app.FragmentTransaction arg1) { // TODO Auto-generated method stub if(arg0.getText().equals("Tab 1")) { changeFragment(new Fragment1()); } else { changeFragment(new Fragment2()); } } @Override public void onTabUnselected(Tab arg0, android.app.FragmentTransaction arg1) { // TODO Auto-generated method stub } }
在minSdkVersion設置爲11後就能調用getActionBar()方法了,能夠給它添加tab,而後重點是爲ActionBar.TabListener寫點擊Tab時要實現的功能,這裏我進行了Fragment的切換,以達到TabHost相同的效果。要注意的是若是該FragmentActivity是嵌套在其餘Activity中(比方說TabHost)時,getAction將會返回null,即沒法進行分頁,其餘狀況下也有可能返回null,限制仍是比較多的。