更新於 2025/01/25閱讀時間約 16 分鐘

Hilt 依賴注入教學:透過 Android 實例深入理解

raw-image
GitHub 開源程式碼:連結

前言

在現代 Android 開發中,依賴注入是一個非常重要的概念,它可以幫助我們更好地管理程式中的依賴關係,提高程式的可維護性和可測試性。Hilt 是 Google 推出的一個依賴注入框架,它基於 Dagger 2,並對其進行了擴展,使得在 Android 應用中使用依賴注入變得更加簡單和方便。今天,我們將透過一個具體的 Android 範例專案「Android-DI-Hilt-Demo」來學習 Hilt 的基本使用。

技術架構概述

這個範例專案採用了多種現代 Android 開發技術和最佳實踐,其技術架構如下:

  • 開發語言:Kotlin
  • UI 框架:Jetpack Compose
  • 依賴注入:Hilt
  • 資料庫:Room
  • 架構模式:MVVM
  • 非同步處理:Kotlin Coroutines & Flow
  • UI 設計:Material Design 3

系統需求

在開始之前,請確保你的開發環境滿足以下要求:

  • Android Studio Hedgehog 或更新版本
  • Kotlin 1.9.0 或更新版本
  • Android SDK 34
  • Gradle 8.2 或更新版本

專案結構

讓我們先來了解一下專案的結構:

app/src/main/java/com/hkt/hiltdemo/
├── HiltDemoApplication.kt # 應用程式入口點
├── MainActivity.kt # 主活動
├── data/ # 資料層
│ ├── AppDatabase.kt # Room 資料庫設定
│ ├── User.kt # 使用者資料模型
│ ├── UserDao.kt # 資料庫訪問介面
│ └── UserRepository.kt # 資料存取倉庫
├── di/ # 依賴注入
│ └── DatabaseModule.kt # 資料庫相關依賴配置
└── ui/ # UI
├── UserScreen.kt # 使用者介面
└── UserViewModel.kt # 視圖模型

Hilt 依賴注入的基本使用

初始化應用程式

在 Android 應用中使用 Hilt,首先需要在應用程式的入口點進行初始化。在我們的專案中,HiltDemoApplication.kt 是應用程式的入口點:

package com.hkt.hiltdemo

import android.app.Application
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class HiltDemoApplication : Application()

這裡使用了 @HiltAndroidApp 註解來標記這個類,Hilt 會自動生成必要的代碼來處理依賴注入的初始化工作。

注入 Activity

在需要使用依賴注入的 Activity 中,我們可以使用 @AndroidEntryPoint 註解來注入所需的依賴。雖然在我們的範例中沒有直接展示 @AndroidEntryPoint 的使用,但通常會在 Activity 類上添加這個註解,例如:

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
// ...
}

注入 ViewModel

在 MVVM 架構中,ViewModel 是一個重要的組件,Hilt 也提供了方便的方式來注入 ViewModel。在 UserViewModel.kt 中,我們可以看到如下代碼:

package com.hkt.hiltdemo.ui

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.hkt.hiltdemo.data.User
import com.hkt.hiltdemo.data.UserRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class UserViewModel @Inject constructor(
private val userRepository: UserRepository
) : ViewModel() {

val users: StateFlow<List<User>> = userRepository.getAllUsers()
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = emptyList()
)

fun addUser(name: String) {
if (name.isBlank()) return
viewModelScope.launch {
userRepository.insertUser(User(name = name))
}
}
}

這裡使用了 @HiltViewModel 註解來標記這個 ViewModel 類,並通過 @Inject 註解的構造函數來注入 UserRepository

Room 資料庫的實現

在這個專案中,我們使用 Room 來進行本地資料存儲。Room 是 Android 官方推薦的一個 SQL 庫,它提供了一個抽象層,使得在 Android 中使用 SQLite 變得更加簡單。

定義資料表

首先,我們需要定義資料表的結構。在 User.kt 中,我們定義了一個 User 資料模型:

package com.hkt.hiltdemo.data

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "users")
data class User(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
val name: String
)

這裡使用了 @Entity 註解來標記這個類是一個 Room 實體,並指定了資料表的名稱為 users

資料庫訪問介面

接下來,我們需要定義一個 DAO(Data Access Object)來進行資料操作。在 UserDao.kt 中,我們可以定義一些增刪改查的方法:

// 假設 UserDao.kt 的部分代碼
interface UserDao {
@Insert
suspend fun insertUser(user: User)

@Query("SELECT * FROM users")
fun getAllUsers(): Flow<List<User>>
}

資料存取倉庫

為了更好地管理資料訪問,我們通常會創建一個 Repository 類。在 UserRepository.kt 中,我們可以看到如下代碼:

package com.hkt.hiltdemo.data

import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class UserRepository @Inject constructor(
private val userDao: UserDao
) {
fun getAllUsers(): Flow<List<User>> = userDao.getAllUsers()

suspend fun insertUser(user: User) {
userDao.insertUser(user)
}
}

這個 UserRepository 類使用了 @Singleton 註解,表示它是一個單例類,並通過 @Inject 註解的構造函數來注入 UserDao

MVVM 架構的應用

在這個專案中,我們採用了 MVVM 架構。MVVM 架構將 UI 層和資料層分離,使得程式的結構更加清晰,也更方便進行單元測試。

視圖模型(ViewModel)

前面已經介紹了 UserViewModel,它負責處理 UI 層和資料層之間的交互。通過使用 LiveData 或 StateFlow,ViewModel 可以將資料的變化通知到 UI 層。

使用者介面(UI)

UserScreen.kt 中,我們可以看到使用 Jetpack Compose 構建的使用者介面:

package com.hkt.hiltdemo.ui

import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel

@Composable
fun UserScreen(
viewModel: UserViewModel = hiltViewModel()
) {
val users by viewModel.users.collectAsState()
var userName by remember { mutableStateOf("") }

Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
// 新增用戶區域
OutlinedTextField(
value = userName,
onValueChange = { userName = it },
label = { Text("使用者名稱") },
modifier = Modifier.fillMaxWidth()
)

Spacer(modifier = Modifier.height(8.dp))

Button(
onClick = {
viewModel.addUser(userName)
userName = ""
},
modifier = Modifier.align(Alignment.End)
) {
Text("新增")
}

Spacer(modifier = Modifier.height(16.dp))

// 用戶列表
LazyColumn(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
items(users) { user ->
Card(
modifier = Modifier.fillMaxWidth()
) {
Text(
text = user.name,
modifier = Modifier.padding(16.dp)
)
}
}
}
}
}

這個介面使用了 hiltViewModel() 函數來獲取 UserViewModel 的實例,並通過 collectAsState() 函數來觀察 users 的變化,實現了響應式 UI 更新。

總結

透過這個範例專案,我們學習了 Hilt 依賴注入的基本使用,包括初始化應用程式、注入 Activity 和 ViewModel;了解了 Room 資料庫的實現,包括定義資料表、資料庫訪問介面和資料存取倉庫;還看到了 MVVM 架構在 Android 開發中的應用。希望這篇文章能幫助你更好地理解和使用 Hilt 進行 Android 開發。

分享至
成為作者繼續創作的動力吧!
© 2025 vocus All rights reserved.