文章目录
-
- 添加hilt配置
- 数据库自动注入
-
- [常规kotlin 规范创建AppDatabase、表、查询封装Dao](#常规kotlin 规范创建AppDatabase、表、查询封装Dao)
- 创建DatabaseModule,向外提供数据库访问方法
- @InstallIn和@Provider上Scope关系
- [PlantRepository 使用 PlantDao](#PlantRepository 使用 PlantDao)
- ViewModel使用PlantRepository
- Fragment声明需要进行注入
- [sunflower 仓库地址](#sunflower 仓库地址)
根据理解,使用SunFlower实例演示hilt基本使用。
添加hilt配置
-
添加hilt gradle插件
buildscript {
dependencies {
classpath "com.google.dagger:hilt-android-gradle-plugin:$hiltVersion"
}
} -
配置module使用插件进行注解处理
apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin' -
配置hilt依赖库版本
dependencies {
kapt "com.google.dagger:hilt-android-compiler:rootProject.hiltVersion" implementation "com.google.dagger:hilt-android:rootProject.hiltVersion" -
App启用hilt
@HiltAndroidApp
class MainApplication : Application()
数据库自动注入
常规kotlin 规范创建AppDatabase、表、查询封装Dao
-
创建数据库
@Database(entities = [GardenPlanting::class, Plant::class], version = 1, exportSchema = false)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun gardenPlantingDao(): GardenPlantingDao
abstract fun plantDao(): PlantDaocompanion object { // For Singleton instantiation @Volatile private var instance: AppDatabase? = null fun getInstance(context: Context): AppDatabase { return instance ?: synchronized(this) { instance ?: buildDatabase(context).also { instance = it } } } // Create and pre-populate the database. See this article for more details: // https://medium.com/google-developers/7-pro-tips-for-room-fbadea4bfbd1#4785 private fun buildDatabase(context: Context): AppDatabase { return Room.databaseBuilder(context, AppDatabase::class.java, DATABASE_NAME) .addCallback( object : RoomDatabase.Callback() { override fun onCreate(db: SupportSQLiteDatabase) { super.onCreate(db) val request = OneTimeWorkRequestBuilder<SeedDatabaseWorker>().build() WorkManager.getInstance(context).enqueue(request) } } ) .build() } }
}
-
创建实体类
@Entity(tableName = "plants")
data class Plant(
@PrimaryKey @ColumnInfo(name = "id") val plantId: String,
val name: String,
val description: String,
val growZoneNumber: Int,
val wateringInterval: Int = 7, // how often the plant should be watered, in days
val imageUrl: String = ""
) {/** * Determines if the plant should be watered. Returns true if [since]'s date > date of last * watering + watering Interval; false otherwise. */ fun shouldBeWatered(since: Calendar, lastWateringDate: Calendar) = since > lastWateringDate.apply { add(DAY_OF_YEAR, wateringInterval) } override fun toString() = name
}
-
创建查询Dao
@Dao
interface PlantDao {
@Query("SELECT * FROM plants ORDER BY name")
fun getPlants(): Flow<List<Plant>>@Query("SELECT * FROM plants WHERE growZoneNumber = :growZoneNumber ORDER BY name") fun getPlantsWithGrowZoneNumber(growZoneNumber: Int): Flow<List<Plant>> @Query("SELECT * FROM plants WHERE id = :plantId") fun getPlant(plantId: String): Flow<Plant> @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertAll(plants: List<Plant>)
}
创建DatabaseModule,向外提供数据库访问方法
数据库、PlantDao等不能直接添加@Inject注解构造函数,需要创建单独的module进行对外提供。
@InstallIn(SingletonComponent::class)
@Module
class DatabaseModule {
@Singleton
@Provides
fun provideAppDatabase(@ApplicationContext context: Context): AppDatabase {
return AppDatabase.getInstance(context)
}
@Provides
fun providePlantDao(appDatabase: AppDatabase): PlantDao {
return appDatabase.plantDao()
}
@InstallIn和@Provider上Scope关系
@InstallIn指定module要注入的生成的component,@Provider函数可以添加Scoped限定符,但是必须与@InstallIn作用域一致。
@Provider函数添加Scoped限定符后,在component范围内仅仅创建一个实例。
Android 类 | 生成的组件 | 作用域 |
---|---|---|
Application | SingletonComponent | @Singleton |
Activity | ActivityRetainedComponent | @ActivityRetainedScoped |
ViewModel | ViewModelComponent | @ViewModelScoped |
Activity | ActivityComponent | @ActivityScoped |
Fragment | FragmentComponent | @FragmentScoped |
将模块安装到组件后,其绑定就可以用作该组件中其他绑定的依赖项,也可以用作组件层次结构中该组件下的任何子组件中绑定的依赖项。
这个函数直接向容器提供了AppDatabase、PlantDao对象。
PlantRepository 使用 PlantDao
@Singleton
class PlantRepository @Inject constructor(private val plantDao: PlantDao) {
fun getPlants() = plantDao.getPlants()
fun getPlant(plantId: String) = plantDao.getPlant(plantId)
fun getPlantsWithGrowZoneNumber(growZoneNumber: Int) =
plantDao.getPlantsWithGrowZoneNumber(growZoneNumber)
}
@Singleton 这个和dagger2 @Module Provider方法限定符效果一样,标志在注入Component范围内单例。
@Inject 标志当component需要注入PlantRepository对象时,可以直接调用该函数进行获取。
@Inject constructor 参数plantDao,标志component使用PlantRepository对象时,需要提供的对象。
ViewModel使用PlantRepository
@HiltViewModel标志ViewModel自动进行构造函数注入
且必须存在@Inject修饰的构造函数
@HiltViewModel
class PlantDetailViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
plantRepository: PlantRepository,
private val gardenPlantingRepository: GardenPlantingRepository,
) : ViewModel() {
val plantId: String = savedStateHandle.get<String>(PLANT_ID_SAVED_STATE_KEY)!!
Fragment声明需要进行注入
@AndroidEntryPoint标志注入入口点
@AndroidEntryPoint 标志,当前Activity、Fragment需要进行hilt注入。
注:Fragment添加后,其所在的Activity同样必须添加
@AndroidEntryPoint
class GardenActivity : AppCompatActivity() {
@AndroidEntryPoint
class PlantDetailFragment : Fragment() {
private val plantDetailViewModel: PlantDetailViewModel by viewModels()