onAttachによるコールバックの実装 FragmentからActivityを操作する【Androidアプリ開発】

FragmentクラスのonAttachを用いたコールバックの実装方法を説明しています。この方法でFragmentからActivity側のメソッドを実行することが出来ます。また、DialogFragmentでも同様に実装可能です。

概要

FragmentからActivity(呼び出し元)のメソッドを実行します。

初めに以下の準備が必要となります。

  • Fragment側に実行したいメソッドを定義したインタフェースを作成する
  • Fragment側のonAtatchをoverrideして、インタフェースで定義したメソッドをセットする
  • Activity側でインタフェースで定義したメソッドをoverrideして実装する

ここまで出来たら、Fragmentの中の必要なタイミングで実行します。

実装例

レイアウト

activity_main.xml

メインアクテビティのレイアウトです。

上から順番にfragment、TextView、Buttonの3つです。

  • fragment
    fragmentの領域、fragment内のボタンを押すとTextViewを更新する
  • TextView
    コールバックの動作確認する
  • Button
    dialogを表示する、dialog内のボタンを押すとTextViewを更新する
メインレイアウト

fragment_sample.xml

フラグメントのレイアウトです。

ボタンを押すと、メインアクテビティのテキストの表示内容を更新します。

フラグメントレイアウト

dialog_sample.xml

ダイアログのレイアウトです。

Positiveボタン(OKボタン)を押すと、メインアクテビティのテキストの表示内容を更新します。

ダイアログレイアウト

実装方法

SampleFragment.kt

実装のポイントは以下の点です。

  • クラス内で参照できるようにListenerの変数を定義
  • Interfaceでメソッドを定義
    →MainActivityでoverrideする
  • onAttachでListenerの変数にセット
    →MainActivityでoverrideしたListenerをセットする
  • ボタンを押したときにInterfaceで定義したメソッドを実行
class SampleFragment : Fragment() {
    //Listenerをセットする変数
    private lateinit var listener: CallbackListener

    //実行するメソッドを定義したInterface
    interface CallbackListener {
        fun updateButtonClickFromFragment()
    }

    //この中でListenerにセットする
    override fun onAttach(context: Context) {
        super.onAttach(context)
        try {
            //MainActivity(呼び出し元)をListenerに変換する
            val mainActivity: MainActivity = activity as MainActivity
            listener = mainActivity
        } catch (e: ClassCastException) {
            throw ClassCastException((context.toString() +
                    " must implement NoticeDialogListener"))
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val root: View = inflater.inflate(R.layout.fragment_sample, container, false)

        //更新用ボタン
        val buttonUpdate: Button = root.findViewById(R.id.buttonUpdate)
        buttonUpdate.setOnClickListener {
            listener.updateButtonClickFromFragment()
        }

        return root
    }
}

SampleDialogFragment.kt

Fragmentと実装方法は変わりありません。

class SampleDialogFragment : DialogFragment() {
    //Listenerをセットする変数
    private lateinit var listener: CallbackListener

    //実行するメソッドを定義したInterface
    interface CallbackListener {
        fun updateButtonClickFromFragmentDialog()
    }

    //この中でListenerにセットする
    override fun onAttach(context: Context) {
        super.onAttach(context)
        try {
            //MainActivity(呼び出し元)をListenerに変換する
            val mainActivity: MainActivity = activity as MainActivity
            listener = mainActivity
        } catch (e: ClassCastException) {
            throw ClassCastException((context.toString() +
                    " must implement NoticeDialogListener"))
        }
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return activity?.let {
            val builder = AlertDialog.Builder(it)
            val inflater = requireActivity().layoutInflater;
            val root = inflater.inflate(R.layout.dialog_sample, null)

            //viewにレイアウトをセット
            builder.setView(root)
                .setPositiveButton("OK",
                    DialogInterface.OnClickListener { dialog, id ->
                        listener.updateButtonClickFromFragmentDialog()
                    })
                .setNegativeButton("CANCEL",
                    DialogInterface.OnClickListener { dialog, id ->
                        getDialog()?.cancel()
                    })
            builder.create()
        } ?: throw IllegalStateException("Activity cannot be null")
    }
}

MainActivity.kt

Fragmentのインタフェースで定義したメソッドをoverrideして実装しています。

  • updateButtonClickFromFragment
    Fragmentで定義したメソッド
  • updateButtonClickFromFragmentDialog
    FragmentDialogで定義したメソッド
//FragmentのListenerを継承する
class MainActivity : AppCompatActivity()
    , SampleFragment.CallbackListener
    , SampleDialogFragment.CallbackListener {

    //Fragmentのボタンを押したときの処理
    override fun updateButtonClickFromFragment() {
        val textView: TextView = findViewById(R.id.textView)
        textView.text = "Update From Fragment!!"
    }

    //FragmentDialogのボタンを押したときの処理
    override fun updateButtonClickFromFragmentDialog() {
        val textView: TextView = findViewById(R.id.textView)
        textView.text = "Update From FragmentDialog!!"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        //Dialog表示ボタン
        val buttonShowDialog: Button = findViewById(R.id.buttonShowDialog)
        buttonShowDialog.setOnClickListener {
            val newFragment = SampleDialogFragment()
            newFragment.show(supportFragmentManager, "test")
        }
    }
}

実行結果

アプリ起動時
アプリ起動時
Fragmentのボタンを押したとき

Fragment内のボタン(画面上部)を押すと、中央のテキストの表示が変わっています。FragmentからActivityの更新が行えていることが分かります。

Fragmentボタン
DialogFgmentのボタンを押したとき

DialogFragment内のOKボタンを押すと、中央のテキストの表示が変わっています。DialogFragmentからActivityの更新が行えていることが分かります。

FragmentDialogボタン

まとめ

FragmentクラスのonAttachを用いたコールバックの実装方法を説明しました。

説明した実装方法を用いると、FragmentからActivity側のメソッドを実行することが出来ます。また、DialogFragmentでも同様に実装可能です。

要点は以下の通りです。

  • Fragment側のInterfaceでメソッドを定義する
  • Activity側でメソッドを実装する
  • onAttachで実装したメソッドを取得して、Fragment側で実行する

Fragment(遷移先)からActivity(呼び出し元)を操作したい場面で活用しましょう。

参考

フラグメント|Android Developers

Androidアプリ開発
この記事を書いた人

エンジニアとして仕事をしています。
仕事や趣味を通して、開発やプログラミングについて学んだことを綴っていきます。
 ・実務経験は、WEBシステムのサーバーサイドコーディングがメイン
 ・アプリ開発は趣味程度

akihiro-takedaをフォローする
akihiro-takedaをフォローする
プログラミング・開発の備忘録
タイトルとURLをコピーしました