フラグメント間の通信

複数のフラグメント間の UI を利用する場合であっても、あたかも一つのアクティビティ内で振る舞いを定義するように、 簡単に動作を定義できます。

ここでは簡単なサンプルを作ることで、異なるフラグメント内のウィジェットにアクセスする様子を見てみましょう。

なお、フラグメントは Android 3.0 以降のものであることに注意してください。Android 2 以前の環境では動作しません。

異なるフラグメントに属する UI 要素へのアクセス

ここで作るプログラムは次のようなものです。

まず、黒(デフォルト背景色) と青のフラグメントがあります。黒い側にはエディットテキストとボタンが配置されています。 一方、青いフラグメント内には TextView がひとつ配置されています。

アンドロイドフラグメント

エディットテキストに何か文字を入力して、ボタンを押すと・・・

アンドロイドフラグメント

TextView にその文字が表示されます。

こうした動きはどのように実現するのでしょうか。さっそく実装してみましょう。

まず基本的なプログラムの枠組みは 『フラグメントの一番簡単な利用例』 の通りです。

フラグメントのレイアウトをレイアウトリソース fragment1.xml、fragment2.xml で定義して、クラスは Fragment1.java、Fragment2.java で定義します。 そしてそれらを res/layout/main.xml から静的に取り込みます。

その上で、リソースファイルと Fragment1.java を以下のように書き換えます。

res/layout/fragment1.xml は次のとおり。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:padding="10dp">
  <EditText 
    android:id="@+id/editText1"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:textSize="30sp"
    android:text="Hello"/>
  <Button 
    android:id="@+id/okButton"
    android:layout_width="100dp"
    android:layout_height="wrap_content"
    android:textSize="30sp"
    android:text="OK"/>
</LinearLayout>

res/layout/fragment2.xml は次のとおり。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="#0000ff"
  android:padding="10dp">
  <TextView
    android:id="@+id/textView1"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:textSize="30sp"
    android:textColor="#FFFF00"
    android:text=""/>
</LinearLayout>

Fragment1.java は次のとおりです。

package com.keicode.android.test;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class Fragment1 extends Fragment {

  EditText editText1;
  Button okButton;
  TextView textView1;
  
  @Override
  public View onCreateView(
    LayoutInflater inflater, 
    ViewGroup container, 
    Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment1, container, false);
  }

  @Override
  public void onStart() {
    super.onStart();
    findViews();
    
    okButton.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        textView1.setText(editText1.getText());
      }
    });
  }
  
  protected void findViews(){
    editText1 = (EditText)getActivity().findViewById(R.id.editText1);
    okButton = (Button)getActivity().findViewById(R.id.okButton);
    textView1 = (TextView)getActivity().findViewById(R.id.textView1);
  }

}

Fragment1.java をみれば分かるように、フラグメントに UI を分割せずに、 アクティビティに直接ウィジェットを配置した場合とあまり変わらない方法で、UI 要素にアクセスできていることがわかります。

ポイントはひとつ。ウィジェットのビューを取得する際に、getActivity でそのフラグメントが属するアクティビティを取得している点です。

フラグメントは必ずいずれかのアクティビティに属する必要があります。getActivity メソッドによって、フラグメントが属しているアクティビティを取得でき、 そのアクティビティを経由して、フラグメントをまたぐ他の UI ウィジェットを取得できる、というわけです。

疎結合フラグメントの実装

以上、getActivity() でアクティビティのインスタンスを取得し、その findViewById を用いることで直接ウィジェットの参照を取得できることを確認しました。 上記の方法は実装が簡単で単純という意味ではよいのですが、モジュール間の依存関係に問題があります。依存関係は極力減らしたほうが、維持しやすい良いコードになります。

例えば上記で文字の表示を TextView から EditText に変更したら、もう片方のフラグメントでも参照をとる方法を変えなければなりません。

そこでフラグメント間の繋がり、フラグメントとアクティビティのかかわりを疎結合にすることが望ましいといえます。それについては次の記事をみてください。

» 柔軟性の高い、疎結合なフラグメント間通信の実装方法

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Android 開発入門