Fragment 間の遷移 (3) 第二のFragmentからの遷移

2019年12月13日金曜日

Android Kotlin

t f B! P L

概要

 前回までで、第一の Fragment から第二の Fragment に画面が遷移するところまでを作つた。 今回は、逆に、第二の Fragment から第一の Fragment に遷移するところを作る。 作業自体は、前回とほぼ同じことの繰り返しになる。
 最後に、このプログラムの潜在的な問題に触れる。

 使ふているバージョンは同じく次。

 Android Studio : 3.5.2
 Kotlin : 1.3.61

第二のFragmentのコード実装 - SecondFragment.kt

 既に、第二のFragmentのレイアウトは fragment_second.xmlとして前回までに作成済。ボタン部品のidは button2として設定済。 あとは、MainFragment.ktで行つたのと同じやうに、listtenerインタフェースを準備し、ボタンのイベント listenerの設定を行ふ。
 SecondFragment.ktのコードは次の通り。

class SecondFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val view = inflater.inflate(R.layout.fragment_second, container, false)
        val button2 = view.findViewById<Button>(R.id.button2)
        button2.setOnClickListener {
            val listener = context as? OnButtonClickListener2
            listener?.onButtonClicked2()
        }

        return view
    }

    interface OnButtonClickListener2 {
        fun onButtonClicked2()
    }

    override fun onDestroy() {
        Log.i("mylog", "SecondFragment:onDestroy")
        super.onDestroy()
    }
}

  • 13行目:
    • インタフェースの名称は、onButtonClickListener2としている。
  • 23行目
    • MainFragment.ktの場合と同様、この fragmentがdestroyされてゐることを確認するために、onDestroy( ) call back関数を実装し、その中でログを表示してゐる。

ボタン イベント処理 - MainActivity.kt

 第二の fragmentのボタンが押されたら、MainFragmentに戻る処理を実装する。 やることは、MainFragmentから第二の fragmentに遷移する実装と同じ。 既に SecondFragment.ktで定義したインタフェースの onButtonClickListener の実装になる。MainActivity.ktのコードは次のやうになる。


class MainActivity : AppCompatActivity(), MainFragment.OnButtonClickListener,SecondFragment.OnButtonClickListener2 {

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

        if (savedInstanceState == null) {
            supportFragmentManager.beginTransaction()
                .replace(R.id.container, MainFragment.newInstance())
                .commitNow()
        }
      }

    override fun onButtonClicked() {
        Log.i("mylog", "onButtonClicked")
        val secondFragment = SecondFragment()
        supportFragmentManager.beginTransaction().replace(R.id.container, secondFragment).commitNow()
    }

    override fun onButtonClicked2() {
        Log.i("mylog", "onButtonClicked2")
        supportFragmentManager.beginTransaction().replace(R.id.container,MainFragment.newInstance()).commitNow()
    }
}

  • 1行目
    • MainActivityでは、第二のfragmentの fragment_second.ktで定義したインタフェース SecondFragment.OnButtonClickListener2の派生でもあるのでこれを追加。
  • 20行目:
    • MainFragmentに切り替へる処理。

 ここまででビルドし実行。

動作の確認 Fragmentの破棄と戻るボタンでアプリ終了

 動作させてみる。

 第一の Fragment の画面にある To Second Fragmentのボタンを押して、画面が 第二のFragmentに切り替はることを確認する。また、その切り替はるときに、Logcatのウィンドウで、MainFragmentが破棄(destroy) されることも確認する。

 次に、第二の fragmentの画面で、To Main Fragmentのボタンを押し、画面が第一の Fragment に切り替はることを確認する。その切り替はりのときに、Logcatのウィンドウで、SecondFragment が破棄(destroy) されることも確認する。

 最後に、それぞれの Fragmentの画面で、戻るボタンを押すと、アプリケーションが終了することも確認する。

設計動作

 ここまでで、次のことを理解する。
  • 画面が切り替はる都度、新たな fragmentの実体が生成され表示されてゐること
  • 切り替はる前の画面は、都度、破棄 (destroy) されてゐること
  • 同時には常に1つの fragment だけが存在し表示されていること
  • 戻るボタンでアプリケーションが終了すること
これが期待した設計ならば、設計どほりに動作してゐることになる。

隠れた問題

 第二の Fragmentで、戻るボタンを押すと、アプリが終了するのではなく、最初の Fragmentに切り替はるやうに作り変へたいとする。 そのための支援関数として addToBackStack ( ) といふものある。しかし、これをそのまま使ふと、動作がおかしくなる。具体的には、画面が切り替はるたびに、古い Fragment が破棄されないまま、次の新しい Fragment が作り続けられることが起こる。

 これが期待動作でないならば、実装に誤りがあることになる。 つづく。 

(了)




アーカイブ