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)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:id="@+id/parent"
android:orientation="horizontal"
android:layout_height="wrap_content"
android:layout_width="fill_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showChild1"
android:text="show child1 Activity"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showChild2"
android:text="show child2 Activity"
/>
</LinearLayout>

<LinearLayout
android:id="@+id/child"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:gravity="center">
</LinearLayout>
</LinearLayout>


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

子1 Activity のレイアウト (child1.xml)

<?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">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is child1 Activity"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon"/>
</LinearLayout>


子2 Activity のレイアウト (child2.xml)

<?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">
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is child2 Activity"/>
</LinearLayout>


親 Activity

import android.app.ActivityGroup;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.LinearLayout;

public class MyActivityGroup extends ActivityGroup {
LinearLayout container;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.parent);

container = (LinearLayout) findViewById(R.id.child);
}

public void showChild1(View v) {
container.removeAllViews();
Intent intent = new Intent(MyActivityGroup.this, Child1Activity.class);
// intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

Window childActivity = getLocalActivityManager().startActivity("child1Activity",intent);
container.addView(childActivity.getDecorView());
}

public void showChild2(View v) {
container.removeAllViews();
Intent intent = new Intent(MyActivityGroup.this, Child2Activity.class);
// intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

Window childActivity = getLocalActivityManager().startActivity("child2Activity",intent);
container.addView(childActivity.getDecorView());
}
}



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

■ Tab の中で画面遷移

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





構造はこんな感じ

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


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


package yanzm.example.activitygroup2;

import android.app.TabActivity;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.widget.TabHost;

public class MyActivity extends TabActivity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tab_layout);

Resources res = getResources();

TabHost tabHost = getTabHost();

TabHost.TabSpec spec;
Intent intent;

intent = new Intent().setClass(this, MyActivityGroup.class);
spec = tabHost.newTabSpec("tab1")
.setIndicator("Home", res.getDrawable(R.drawable.ic_tab_home))
.setContent(intent);
tabHost.addTab(spec);

intent = new Intent().setClass(this, Tab2Activity.class);
spec = tabHost
.newTabSpec("tab2")
.setIndicator("Camera",
res.getDrawable(R.drawable.ic_tab_camera))
.setContent(intent);
tabHost.addTab(spec);

intent = new Intent().setClass(this, Tab3Activity.class);
spec = tabHost.newTabSpec("tab3")
.setIndicator("Star", res.getDrawable(R.drawable.ic_tab_star))
.setContent(intent);
tabHost.addTab(spec);

tabHost.setCurrentTab(2);
}
}


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 件のコメント: