2011年2月7日月曜日

Android 1画面 複数Activity で画面遷移 - ActivityGroup -

以前のエントリで「Android 複数画面 1 Activity で画面遷移 」を紹介しました。

今回は 1画面 複数Activity です。

# 複数の Activity は同じプロセスになります。

ActivityGroup を継承します。

TabActivity はこの ActivityGroup を継承していて、そのため各タブに Acitivity を割り当てることが可能なんです。

構造としてはこんな感じ


親Activity (ActivityGroup)
|
|+---- 子Activity1 (Activity)
|
|+---- 子Activity2 (Activity)
|
...


親 Activity は getLocalActivityManager() で取得した LocalActivityManagerstartActivity(String id, Intent intent) で子Activityを起動します。

startActivity(String id, Intent intent) は戻り値として Window を返すので、この Window の getDecorView() で取得した View を対応するコンテナ (LinearLayout とか FrameLayout) とかに addView() すればOK。

startActivity の第1引数の String は Activity の識別子(id)で、LocalActivityManager.getCurrentId() を使って現在の Activity の id を取得することが可能。

LocalActivityManager.getActivity(String id) で特定の id のActivity を取得することができるし、LocalActivityManagergetCurrentActivity() で現在の Activity を取得することもできる。


■ ボタンをクリックしたら 同じ画面で Activity を切り替えるサンプル

# まずは最小構成で。

親 Activity のレイアウト (parent.xml)
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical"   
  4.     android:layout_width="fill_parent"  
  5.     android:layout_height="fill_parent">  
  6.     <LinearLayout   
  7.         android:id="@+id/parent"  
  8.         android:orientation="horizontal"  
  9.         android:layout_height="wrap_content"   
  10.         android:layout_width="fill_parent">  
  11.         <Button   
  12.             android:layout_width="wrap_content"  
  13.             android:layout_height="wrap_content"  
  14.             android:onClick="showChild1"  
  15.             android:text="show child1 Activity"  
  16.             />  
  17.         <Button   
  18.             android:layout_width="wrap_content"  
  19.             android:layout_height="wrap_content"  
  20.             android:onClick="showChild2"  
  21.             android:text="show child2 Activity"  
  22.             />  
  23.     </LinearLayout>  
  24.   
  25.     <LinearLayout   
  26.         android:id="@+id/child"  
  27.         android:layout_width="fill_parent"   
  28.         android:layout_height="0dip"  
  29.         android:layout_weight="1"  
  30.         android:gravity="center">  
  31.     </LinearLayout>  
  32. </LinearLayout>  


id/child に子 Activity の View を入れることになります。

子1 Activity のレイアウト (child1.xml)
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"   
  4.     android:layout_height="fill_parent">  
  5.     <TextView  
  6.         android:layout_width="wrap_content"  
  7.         android:layout_height="wrap_content"  
  8.         android:text="This is child1 Activity"/>  
  9.     <ImageView  
  10.         android:layout_width="wrap_content"  
  11.         android:layout_height="wrap_content"  
  12.         android:src="@drawable/icon"/>  
  13. </LinearLayout>   


子2 Activity のレイアウト (child2.xml)
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"   
  4.     android:layout_height="fill_parent">  
  5.     <EditText  
  6.         android:layout_width="wrap_content"  
  7.         android:layout_height="wrap_content"  
  8.         android:text="This is child2 Activity"/>  
  9. </LinearLayout>  


親 Activity
  1. import android.app.ActivityGroup;  
  2. import android.content.Intent;  
  3. import android.os.Bundle;  
  4. import android.view.View;  
  5. import android.view.Window;  
  6. import android.widget.LinearLayout;  
  7.   
  8. public class MyActivityGroup extends ActivityGroup {  
  9.     LinearLayout container;  
  10.   
  11.     @Override  
  12.     public void onCreate(Bundle savedInstanceState) {  
  13.         super.onCreate(savedInstanceState);  
  14.         setContentView(R.layout.parent);  
  15.          
  16.         container = (LinearLayout) findViewById(R.id.child);  
  17.     }  
  18.   
  19.     public void showChild1(View v) {  
  20.         container.removeAllViews();  
  21.         Intent intent = new Intent(MyActivityGroup.this, Child1Activity.class);  
  22.         // intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  
  23.   
  24.         Window childActivity = getLocalActivityManager().startActivity("child1Activity",intent);  
  25.         container.addView(childActivity.getDecorView());  
  26.     }  
  27.   
  28.     public void showChild2(View v) {  
  29.         container.removeAllViews();  
  30.         Intent intent = new Intent(MyActivityGroup.this, Child2Activity.class);  
  31.         // intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  
  32.   
  33.         Window childActivity = getLocalActivityManager().startActivity("child2Activity",intent);  
  34.         container.addView(childActivity.getDecorView());  
  35.     }  
  36. }  



さて、ここからが応用です。

■ Tab の中で画面遷移

TabContent に入れる Activity を AcitivityGroup にすればタブの中で画面遷移ができます。
上記 MyActivityGroup をそのまま TabActivity の Content に入れてみます。





構造はこんな感じ

TabActivity (Activity)
|
|+--- Tab1 (ActivityGroup)
| |
| |+---- 子Activity1 (Activity)
| |
| |+---- 子Activity2 (Activity)
|
|+--- Tab2 (Activity)
|
|+--- Tab3 (Activity)


AndroidManifest.xml に Activity を宣言するの忘れずに!

  1. package yanzm.example.activitygroup2;  
  2.   
  3. import android.app.TabActivity;  
  4. import android.content.Intent;  
  5. import android.content.res.Resources;  
  6. import android.os.Bundle;  
  7. import android.widget.TabHost;  
  8.   
  9. public class MyActivity extends TabActivity {  
  10.   
  11.  @Override  
  12.  public void onCreate(Bundle savedInstanceState) {  
  13.   super.onCreate(savedInstanceState);  
  14.   setContentView(R.layout.tab_layout);  
  15.   
  16.   Resources res = getResources();  
  17.   
  18.   TabHost tabHost = getTabHost();  
  19.   
  20.   TabHost.TabSpec spec;  
  21.   Intent intent;  
  22.   
  23.   intent = new Intent().setClass(this, MyActivityGroup.class);  
  24.   spec = tabHost.newTabSpec("tab1")  
  25.     .setIndicator("Home", res.getDrawable(R.drawable.ic_tab_home))  
  26.     .setContent(intent);  
  27.   tabHost.addTab(spec);  
  28.   
  29.   intent = new Intent().setClass(this, Tab2Activity.class);  
  30.   spec = tabHost  
  31.     .newTabSpec("tab2")  
  32.     .setIndicator("Camera",  
  33.       res.getDrawable(R.drawable.ic_tab_camera))  
  34.     .setContent(intent);  
  35.   tabHost.addTab(spec);  
  36.   
  37.   intent = new Intent().setClass(this, Tab3Activity.class);  
  38.   spec = tabHost.newTabSpec("tab3")  
  39.     .setIndicator("Star", res.getDrawable(R.drawable.ic_tab_star))  
  40.     .setContent(intent);  
  41.   tabHost.addTab(spec);  
  42.   
  43.   tabHost.setCurrentTab(2);  
  44.  }  
  45. }  


LocalManager の startActivity() メソッドのリファレンスでも触れられているように、Activity のライフサイクルをちゃんと管理しないとダメでしょうね。

ここでは、

 * Intent が現在は知っているのとは異なる Activity コンポーネントにマップされる場合、現在の Activity は finish して、新しいのがスタートする。

* 現在の Activity が non-multiple launch mode (singleTop のような) を使っている場合、もしくは Intent に FLAG_ACTIVITY_SINGLE_TOP flag がセットされている場合、現在の Activity は走ったまま残り、Activity.onNewIntent() メソッドが呼ばれる。

* 新しい Intent が extras を除いて以前のと同じで、新しい Intent に FLAG_ACTIVITY_CLEAR_TOP が設定されていない場合、現在の Activity はそのままの状態で走り続ける。

* それ以外の場合、現在の Activity は finish して新しいのがスタートする

などが書かれています。


タブの中で画面遷移するサンプル zip はこちら ActivityGroupSample2.zip


 

1 件のコメント: