Android
 Computer >> コンピューター >  >> プログラミング >> Android

Androidでフラグメント間のデータ受け渡しを実装する方法【サンプルコード付き】

はじめに

本記事では、Androidアプリ開発において、あるフラグメント(Fragment)から別のフラグメントへデータを受け渡す方法を解説します。ここではインターフェース(コールバック)を使用し、ホストとなるActivityを経由して2つのフラグメント間でメッセージをやり取りする、定番の実装パターンをサンプルコード付きでステップごとに紹介します。

全体の仕組み

今回のサンプルでは、以下のような流れでデータを受け渡します。

  • FirstFragment:TextViewがタップされると、リスナー経由でメッセージを送信する
  • MainActivity:FirstFragmentからのコールバックを受け取り、SecondFragmentへ中継する
  • SecondFragment:受け取ったメッセージをTextViewに表示する

手順1:新規プロジェクトを作成する

Android Studioを起動し、メニューから「File」→「New Project」を選択します。必要な項目を入力して、新しいプロジェクトを作成してください。

手順2:activity_main.xmlを編集する

res/layout/activity_main.xml に以下のコードを記述します。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/linearlayout01"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#ccc"
        android:layout_weight="1"
        android:orientation="vertical">

        <fragment
            android:name="com.example.myapplication.FirstFragment"
            android:id="@+id/frag_1"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/linearlayout02"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1"
        android:background="#eee"
        android:orientation="vertical">

        <fragment
            android:name="com.example.myapplication.SecondFragment"
            android:id="@+id/frag_2"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" />
    </LinearLayout>
</LinearLayout>

上記のレイアウトでは、画面を上下に分割し、上半分に FirstFragment、下半分に SecondFragment を配置しています。この2つのフラグメント間でデータの受け渡しを行います。

手順3:MainActivity.javaを編集する

src/MainActivity.java に以下のコードを記述します。

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;

public class MainActivity extends FragmentActivity implements OnButtonPressListener {

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

    @Override
    public void onButtonPressed(String msg) {
        SecondFragment obj = (SecondFragment) getSupportFragmentManager().findFragmentById(R.id.frag_2);
        obj.onFragmentInteraction(msg);
    }
}

MainActivityは OnButtonPressListener インターフェースを実装しており、FirstFragmentからの通知を受け取ると、ID(frag_2)でSecondFragmentを取得し、onFragmentInteraction() を呼び出してメッセージを中継します。

手順4:FirstFragment.javaを編集する

src/FirstFragment.java に以下のコードを記述します。

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class FirstFragment extends Fragment {

    OnButtonPressListener buttonListener;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment, null);
        init(root);
        return root;
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            buttonListener = (OnButtonPressListener) getActivity();
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement onButtonPressed");
        }
    }

    void init(ViewGroup root) {
        TextView text = (TextView) root.findViewById(R.id.text);
        text.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                buttonListener.onButtonPressed("Message From First Fragment");
            }
        });
    }
}

onAttach() 内でホストActivityを OnButtonPressListener としてキャストしています。これにより、TextViewがクリックされたタイミングでActivityへメッセージを通知できます。もしActivityがインターフェースを実装していなければ、ClassCastException がスローされる仕組みです。

手順5:SecondFragment.javaを編集する

src/SecondFragment.java に以下のコードを記述します。

import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class SecondFragment extends Fragment {

    TextView textView;
    View view;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment, container, false);
        return view;
    }

    public void onFragmentInteraction(String uri) {
        Log.d("sai", uri);
        textView = view.findViewById(R.id.text);
        textView.setText(uri);
    }
}

onFragmentInteraction() は、MainActivityから中継されたメッセージを受け取るための公開メソッドです。受け取った文字列をLogcatに出力するとともに、TextViewのテキストとして画面に反映します。

手順6:fragment.xmlを編集する

res/layout/fragment.xml に以下のコードを記述します。このレイアウトは両方のフラグメントで共通して使用します。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:gravity="center"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/text"
        android:textSize="30sp"
        android:text="Click"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

手順7:OnButtonPressListener.javaを作成する

src/OnButtonPressListener.java として、以下のインターフェースを定義します。

public interface OnButtonPressListener {
    void onButtonPressed(String msg);
}

このインターフェースが、FirstFragmentとMainActivityをつなぐ「契約」の役割を果たします。

アプリを実行して動作を確認する

それでは、実際にアプリを起動してみましょう。Android端末をPCに接続した状態で、Android Studioのツールバーにある「Run」アイコンをクリックし、接続した端末を選択して実行します。

起動直後は、上下に配置された2つのフラグメントに「Click」というテキストが表示された初期画面になります。

Androidでフラグメント間のデータ受け渡しを実装する方法【サンプルコード付き】

次に、上側のフラグメント(FirstFragment)のTextViewをタップしてみてください。「Message From First Fragment」というメッセージが下側のフラグメント(SecondFragment)へ渡され、テキストが更新されます。

Androidでフラグメント間のデータ受け渡しを実装する方法【サンプルコード付き】

補足:より現代的な手法について

本記事で紹介したインターフェース経由のパターンは、サポートライブラリ時代からの定番手法です。ただし、現在のAndroidX環境では、Fragment Result APIsetFragmentResultListener / setFragmentResult)や共有ViewModelを利用することで、ライフサイクルを考慮したより安全かつシンプルなデータ受け渡しが可能になっています。新規プロジェクトでは、これらのモダンなAPIの採用も検討するとよいでしょう。

  1. Androidでアクティビティ間を画像を受け渡す方法をわかりやすく解説

    はじめに 本記事では、Androidアプリであるアクティビティ(Activity)から別のアクティビティへ画像を受け渡す方法を解説します。ここでは、Intentに画像のリソースIDを格納して渡す、最もシンプルで確実な手法を紹介します。 手順1:新規プロジェクトの作成 Android Studioで新しいプロジェクトを作成します。メニューから「File」→「New Project」を選択し、必要事項をすべて入力してプロジェクトを作成しましょう。 手順2:activity_main.xml の編集 res/layout/activity_main.xml に以下のコードを追加します。「Send

  2. 【Android】1つのフラグメントから別のフラグメントへデータを送信する方法(インターフェース活用の実装例)

    はじめに このチュートリアルでは、Androidアプリで1つのフラグメント(Fragment)から別のフラグメントへデータを送信する方法を解説します。フラグメント同士は直接通信することができません。そこで本記事では、カスタムインターフェース「SendMessage」を定義し、ホストとなるMainActivityを仲介してデータを受け渡す、定番かつ推奨されるパターンを紹介します。 具体的には、タブで切り替えられる2つのフラグメントを用意し、1つ目のフラグメントで入力したテキストをボタン操作で2つ目のフラグメントに表示させるサンプルアプリを作成します。 ステップ1:新しいプロジェクトを作成する