まず、startActivityForResultメソッドが非推奨となった理由を見てみましょう。このメソッドは、別のアクティビティを起動し、そのアクティビティから結果を受け取るために使用されました。しかし、このアプローチは古くなり、新しいアーキテクチャーパターンである「Jetpack Navigation Component」と組み合わせることが推奨されています。
Jetpack Navigation Componentを使用すると、画面間のナビゲーションをより簡単に管理できます。まず、Jetpack Navigationライブラリをプロジェクトに追加します。build.gradleファイルに依存関係を追加しましょう。
dependencies {
def nav_version = "2.4.0"
// Navigation
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}
次に、ナビゲーショングラフを作成します。resフォルダ内にnavigationディレクトリを作成し、nav_graph.xmlという名前のファイルを作成します。このファイルには、アクティビティ間のナビゲーションのフローを定義します。
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
app:startDestination="@id/firstFragment">
<fragment
android:id="@+id/firstFragment"
android:name="com.example.myapp.FirstFragment"
android:label="First Fragment">
<action
android:id="@+id/action_firstFragment_to_secondFragment"
app:destination="@id/secondFragment" />
</fragment>
<fragment
android:id="@+id/secondFragment"
android:name="com.example.myapp.SecondFragment"
android:label="Second Fragment">
<action
android:id="@+id/action_secondFragment_to_thirdFragment"
app:destination="@id/thirdFragment" />
</fragment>
<fragment
android:id="@+id/thirdFragment"
android:name="com.example.myapp.ThirdFragment"
android:label="Third Fragment" />
</navigation>
ナビゲーショングラフが作成されたら、アクティビティでNavHostFragmentを使用してナビゲーションを実行できます。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navController = findNavController(R.id.nav_host_fragment)
NavigationUI.setupActionBarWithNavController(this, navController)
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment)
return navController.navigateUp() || super.onSupportNavigateUp()
}
}
これで、アクティビティ間のナビゲーションが構成されました。次に、結果を取得する方法を見てみましょう。
たとえば、FirstFragmentからSecondFragmentに移動し、結果を受け取る場合を考えます。まず、SecondFragmentに遷移するアクションをナビゲーショングラフで定義します。
<fragment
android:id="@+id/firstFragment"
android:name="com.example.myapp.FirstFragment"
android:label="First Fragment">
<action
android:id="@+id/action_firstFragment_to_secondFragment"
app:destination="@id/secondFragment"
app:launchSingleTop="true"
app:popUpTo="@id/firstFragment"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="@+id/secondFragment"
android:name="com.example.myapp.SecondFragment"
android:label="Second Fragment">
<argument
android:name="myResult"
app:argType="string" />
<action
android:id="@+id/action_secondFragment_to_thirdFragment"
app:destination="@id/thirdFragment" />
</fragment>
ここで、app:launchSingleTop="true"とapp:popUpTo="@id/firstFragment"の設定が重要です。これにより、SecondFragmentが既にスタックに存在する場合は再生成せず、戻るボタンでFirstFragmentに戻ることができます。
次に、FirstFragmentからSecondFragmentに遷移するコードを実装します。
val action = FirstFragmentDirections.actionFirstFragmentToSecondFragment()
findNavController().navigate(action)
また、SecondFragmentで結果を受け取るためのコードを追加します。
val navController = findNavController()
val result = "This is the result"
val bundle = bundleOf("myResult" to result)
navController.previousBackStackEntry?.savedStateHandle?.set("myResult", bundle)
navController.popBackStack()
これで、結果を受け取る準備が整いました。FirstFragmentに戻り、結果を取得するために以下のコードを追加します。
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val navController = findNavController()
val resultObserver = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_RESUME && navController.currentBackStackEntry?.savedStateHandle?.contains("myResult") == true) {
val result = navController.currentBackStackEntry?.savedStateHandle?.get<Bundle>("myResult")
val myResult = result?.getString("myResult")
// 結果を使用する処理をここに追加します
}
}
viewLifecycleOwner.lifecycle.addObserver(resultObserver)
}