上一篇我們說明了 RoomRush 的第一條分支--「課表管理」;今天的第二條分支是「教室詳細設定」。
DetailChooseActivity.kt 這檔案是顯示教室清單,讓管理者點選其中一間教室時,並傳遞教室名稱傳給下一頁,而 ClassroomAdapter.kt 的用意是把教室清單變成 RecyclerView Adapter,並讓管理者可以點選。
一開始在設計這個頁面時,我曾直覺認為既然核心就是列表呈現,把邏輯與 RecyclerView.Adapter 全寫在同一個檔案最省事,甚至一度想把 DetailChooseActivity.kt 與 ClassroomAdapter.kt 混在一起寫。
但這正好呼應了前面一再強調的職責分離:
ClassroomAdapter 專注於「View 的渲染與資料綁定」:只管每一列 UI 怎麼畫。DetailChooseActivity 專注於「流程控制與使用者互動」:只管點擊後的邏輯跳轉與事件處理。這樣的拆分大幅降低了單一檔案的複雜度。未來若要修改列表排版,或是微調教室選取後的行為,都能各自獨立維護。
| UI 畫面 | 操作流程 |
|---|---|
![]() |
![]() |
DetailChooseActivity.kt 和 ClassroomAdapter.kt 負責什麼和 Hermes Agent 一起重讀教室細項頁面和其 Adapter 後,這兩個檔案扮演的是「挑選教室」的入口關卡:讓管理者從清單中點選特定教室,並將教室代號(如 SF304)傳遞到下一頁的管理畫面。
兩者的分工非常純粹:DetailChooseActivity.kt 負責「抓取資料與協調」, ClassroomAdapter.kt 負責「繪製畫面與觸發跳頁」。
DetailChooseActivity.kt:資料中繼與畫面監聽角色定位:只負責觀察資料與組裝介面。
核心實作:
1.薄 ViewModel(Thin ViewModel): 透過 AppContainer 注入 Repository,將全校課表轉為 LiveData 供畫面觀察。
2.資料加工後分發: 監聽到資料庫更新時,提取出不重複的教室名稱並排序,整包交給 Adapter:
viewModel.allClassrooms.observe(this) { schedules ->
val classroomNames = schedules.map { it.classroom }.sorted()
adapter.updateData(classroomNames)
}
可維護性觀察: 檔案名稱為 DetailChooseActivity.kt,但內部 Class 名稱卻是 ClassroomChooseManageActivity,是早期開發遺留下的命名不一致。
ClassroomAdapter.kt:文字渲染與跳頁事件角色定位:單純接收 List<String>(教室名稱清單),將字串轉化為單列 Item。
核心實作:
Intent 帶著教室名稱跳轉至下一頁:holder.itemView.setOnClickListener {
val intent = Intent(it.context, ClassroomManageActivity::class.java).apply {
putExtra("CLASSROOM_NAME", classroom)
}
it.context.startActivity(intent)
}
可維護性觀察:
notifyDataSetChanged(),未來若資料量擴大,可導入 ListAdapter 搭配 DiffUtil。DetailChooseActivity.kt)ManagerActivity
「點擊教室細項設定」
↓
ClassroomChooseManageActivity
↓
ViewModel
「取得所有教室課表」
↓
Activity
「整理成教室名稱清單」
↓
ClassroomAdapter
「顯示教室列表」
↓
管理者選擇一間教室
↓
傳遞教室名稱 CLASSROOM_NAME
↓
ClassroomManageActivity
「進入教室設定頁」
ClassroomAdapter.kt 內部流程教室名稱清單
↓
adapter.updateData()
「更新 Adapter 的資料」
↓
ClassroomAdapter
「顯示教室列表」
↓
管理者點選教室
↓
回傳所選教室名稱
ClassroomAdapter 負責將教室名稱清單顯示在列表中。
當管理者點選某間教室時,Adapter 會透過點擊事件將選取的教室名稱傳回 Activity,再由 Activity 使用 Intent 將 CLASSROOM_NAME 傳給 ClassroomManageActivity。
DetailChooseActivity是教室詳細設定流程中的教室選擇頁。實際的 class 名稱是 ClassroomChooseManageActivity ,layout 是 detail_choose.xml。
ManagerActivity 的「教室細項設定」入口進入,透過 ClassroomChooseManageViewModel 從 Repository 取得所有課表資料。allClassrooms 後,將 List<ClassroomSchedule> 轉成排序後的 List<String> 教室名稱清單,交給 ClassroomAdapter 顯示在 RecyclerView。ClassroomAdapter 會建立前往 ClassroomManageActivity 的 Intent,並用 CLASSROOM_NAME 傳出被點選的教室名稱。這頁本身不修改資料庫,而是負責選擇要設定哪一間教室。
ClassroomAdapter 是教室詳細設定流程中的 RecyclerView Adapter。
List<String> 教室名稱清單,使用 item_classroom.xml 作為每一列的 layout。onCreateViewHolder() 會建立 item view,onBindViewHolder() 會把目前位置的教室名稱綁定到 classroom_name 這個 TextView,並設定點擊事件。ClassroomManageActivity 的 Intent,並用 putExtra("CLASSROOM_NAME", classroom) 傳出教室名稱。updateData() 則會用新教室清單取代舊資料,並呼叫 notifyDataSetChanged() 讓整個列表重新刷新。DetailChooseActivity.kt,裡面的 class 卻是 ClassroomChooseManageActivity。Kotlin 語法雖允許檔名與 class 不同名,但搜尋類別時很容易找不到檔案,在專案架構導覽上增加不必要的認知成本。startActivity),越權處理了頁面導航的職責。理想做法應利用 Lambda 或 Callback 將點擊事件拋回給 Activity,由 Activity 統一控制畫面流向,讓 Adapter 專注於資料綁定與展示。notifyDataSetChanged(),會迫使整個 RecyclerView 重繪所有 item,既浪費效能也缺少流暢的過渡動畫。未來可遷移至 ListAdapter 搭配 DiffUtil,透過差量比對達成精準的局部刷新。在管理者功能裡,教室細項設定不是直接進入修改頁,而是先經過一個教室選擇頁。
這個頁面的 class 叫 ClassroomChooseManageActivity,但實際檔案是 DetailChooseActivity.kt,layout 是 detail_choose.xml。這種命名不一致不會讓程式不能跑,但讀專案時很容易迷路,也是一個可維護性觀察。
這頁的流程很單純:它從 Repository 取得所有教室資料,轉成教室名稱清單,交給 RecyclerView 顯示。管理者點選其中一間教室後,Adapter 會把教室名稱用 CLASSROOM_NAME 傳給 ClassroomManageActivity。所以這頁比較像「選擇入口」,真正修改教室詳細資料的邏輯要到下一個頁面才會出現。
ClassroomAdapter 是一個很短的檔案,但它剛好連接了教室選擇頁和教室詳細設定頁。
前一頁 ClassroomChooseManageActivity 只負責取得所有教室名稱並交給 Adapter,Adapter 則把這些名稱顯示成 RecyclerView 的列表項目。
比較值得注意的是,這個 Adapter 不只是顯示資料,它也直接處理點擊跳頁。當使用者點擊某一間教室時,Adapter 會建立 Intent,前往 ClassroomManageActivity,並用 CLASSROOM_NAME 傳出教室名稱。這樣寫可以讓程式短一點,但 Adapter 會知道下一頁是誰,和頁面跳轉產生耦合。若未來要改善,可以改成 Adapter 只回傳點擊事件,讓 Activity 決定跳轉邏輯。
各用一句話總結這兩個檔案:
DetailChooseActivity顯示所有教室清單,讓管理者點選一間教室,並把CLASSROOM_NAME傳給DetailSetupActivity。
ClassroomAdapter把教室名稱清單顯示成 RecyclerView 列表,並在點擊某一間教室時,把CLASSROOM_NAME傳給DetailSetupActivity。
到這裡,我們完成了「教室清單選取」的流程,讓 App 能夠精確鎖定管理者想異動的目標教室。然而,光是選定「哪一間」還不夠,真正的核心在於 如何修改教室的細項設定。
下一篇,我們將正式走進「教室細項設定」的最後一哩路--解密 DetailSetupActivity.kt 。看看畫面如何接收傳遞過來的 CLASSROOM_NAME 參數,最終完成教室類型(Classroom Type)的更新與存檔。