Jetpack Composeで開発を進めていると、MainActivity.kt
にあれもこれもとコードが増えてきて、気づけば「秘伝のタレ」のような巨大なファイルになっていませんか?
特に、画面遷移を管理する**NavHost
は、画面が増えるたびにどんどん長くなりがちです**。
この記事では、そんなMainActivity
をスッキリさせ、プロジェクトの見通しを劇的に良くする簡単なリファクタリング術をご紹介します。
なぜ整理が必要? 現状:MainActivity
が駅と路線図を兼任している状態
Composeを学び始めると、多くの場合MainActivity
にNavHost
を直接書きます。これは、小さなアプリなら問題ありません。
❌ 整理前のコード (MainActivity.kt
)
画面遷移の定義がMainActivity
の中に直接書かれており、非常に読みにくい状態です。
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
SimpleMemoAppAndroidTheme {
val navController = rememberNavController()
// MainActivityの中に直接、画面遷移の定義が書かれている
NavHost(navController = navController, startDestination = "memo_list") {
composable("memo_list") { MemoListScreen(navController) }
composable("memo_detail/{memoId}") { DetailScreen(navController) }
// ...画面が10個になったら、ここがすごく長くなる...
}
}
}
}
}
これを駅に例えてみましょう。MainActivity
はアプリの入口なので「駅舎」です。NavHost
は、どの電車がどのホームに来るかを定義する「路線図」です。今の状態は、駅舎の壁に、巨大な路線図が直接ペンキで描かれているようなものです。
【問題点】
- 駅舎の役割が多すぎる: 「建物の管理」と「路線図の管理」という2つの仕事が混ざっている。
- 見通しが悪い: 路線図の全体像を把握しにくい。
- メンテナンスが大変: 「路線図を修正したいだけなのに、駅舎全体の工事図面を開かないといけない」のは面倒。
解決策:路線図を「総合案内所」へお引越し!
ごちゃごちゃした壁の路線図を消して、代わりに**「総合案内所」を新設**し、そこに綺麗な路線図を設置しましょう。駅舎は「総合案内所はこちらです」と案内するだけになり、とてもスッキリします。
手順1:「総合案内所」の場所を作る
navigation
という名前の新しい置き場所(パッケージ)を作ります。
- Android Studioで
ui
パッケージなどを右クリック -
New
>Package
を選択 -
navigation
と入力して作成
手順2:「総合案内所」のファイルを作り、路線図を設置する
作成したnavigation
パッケージの中に、AppNavHost.kt
というファイルを作り、MainActivity
からNavHost
の部分を丸ごと引っ越してきます。
ui/navigation/AppNavHost.kt
(新しく作るファイル)
このファイルは、画面遷移の管理だけに責任を持つ、専門家になりました。
package com.example.simplememoapp_android.navigation // 新しい住所
import androidx.compose.runtime.Composable
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import com.example.simplememoapp_android.ui.screen.MemoDetailScreen
import com.example.simplememoapp_android.ui.screen.MemoListScreen
// これが「路線図」の本体!
@Composable
fun AppNavHost(navController: NavHostController) {
NavHost(navController = navController, startDestination = "memo_list") {
// 「メモ一覧」行きホーム
composable("memo_list") {
MemoListScreen(navController = navController)
}
// 「メモ詳細」行きホーム
composable("memo_detail/{memoId}") { backStackEntry ->
MemoDetailScreen(
navController = navController,
backStackEntry = backStackEntry
)
}
}
}
手順3:「駅舎」をスッキリさせる
最後に、MainActivity
からペンキの路線図を消して、「総合案内所を見てね」と案内するだけのシンプルな形に修正します。
MainActivity.kt
(修正後)
MainActivity
の責務は「アプリを起動すること」だけになり、とても見通しが良くなりました。
import com.example.simplememoapp_android.navigation.AppNavHost // 総合案内所をインポート
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
SimpleMemoAppAndroidTheme {
val navController = rememberNavController()
// 総合案内所(AppNavHost)を呼び出すだけ!超スッキリ!
AppNavHost(navController = navController)
}
}
}
}
これで完了です!
登場人物紹介!ナビゲーションの主要メンバー
今回の整理で使った3人の主要メンバーを、改めて紹介します。
① NavController
(電車の運転士 👨✈️)
- 役割: 実際に画面から画面へと連れて行ってくれる運転士です。「次はこの駅へ行け!」「一つ前の駅に戻れ!」と命令します。
-
呼び出し方:
val navController = rememberNavController()
-
命令の仕方:
navController.navigate("駅の名前")
やnavController.popBackStack()
② NavHost
(路線図 🗺️)
-
役割: アプリ内の全ての駅(画面)と、駅間の繋がりを定義した路線図です。
startDestination
で、最初にどの駅に停車するかを指定します。 -
使い方:
AppNavHost.kt
に設置し、中に各駅のホーム(composable
)を定義します。
③ composable("駅の名前")
(駅のホーム 🚉)
-
役割: 路線図に描かれた、一つ一つの駅のホームです。
"memo_list"
という名前のホームにはMemoListScreen
が、"memo_detail/{memoId}"
という名前のホームにはMemoDetailScreen
が来ます。 -
{memoId}
のように{}
で囲むと、「IDカード」などの**切符(引数)**を受け取ることができます。
まとめ
MainActivity
がごちゃごちゃしてきたら、それはリファクタリングの良いサインです。
今回のように、責務(役割)ごとにファイルを分割するだけで、コードは驚くほどクリーンで、未来のあなたが読んでも理解しやすいプロフェッショナルな状態になります。
ぜひ、あなたのプロジェクトでも試してみてください!