#android #kotlin #dagger-hilt
#Android #kotlin #кинжал-рукоять
Вопрос:
Мне было интересно, как я могу передать зависимость приложения в ViewModel с помощью Hilt? Я пытался использовать AndroidViewModel, но у меня не получилось. Кто-нибудь может мне помочь? Какой-нибудь короткий пример мог бы многое значить для меня.
Это моя ViewModel:
class MainViewModel @ViewModelInject constructor(
private val application: Application,
private val repository: Repository,
@Assisted private val savedStateHandle: SavedStateHandle
) : ViewModel() {
Это мой модуль hilt
@Module
@InstallIn(ApplicationComponent::class)
object DatabaseModule {
@Singleton
@Provides
fun provideDatabase(
@ApplicationContext context: Context
) = Room.databaseBuilder(
context,
MyDatabase::class.java,
"my_database"
).build()
@Singleton
@Provides
fun provideDao(database: MyDatabase) = database.myDao()
@Singleton
@Provides
fun provideRepository(myDao: MyDao) = Repository(myDao)
@Singleton
@Provides
fun provideApplicationContext() = MyApplication()
}
Все остальное в порядке, и я получил сообщение об ошибке:
Вызвано: java.lang.RuntimeException: Не удается создать экземпляр класса com.example.пример.viewmodel.MainViewModel вызвано: java.lang.Исключение экземпляра: java.lang.Класс<com.example.пример.viewmodel.MainViewModel> не имеет конструктора с нулевым аргументом
Комментарии:
1. Стефанджо, есть ли какое-либо решение, которого вы достигли, передавая экземпляр приложения в AndroidViewModel с использованием hilt?
Ответ №1:
Вы можете увидеть полный исходный код https://github.com/Kotlin-Android-Open-Source/MVI-Coroutines-Flow/tree/dagger_hilt
- Репозиторий:
@Singleton
class UserRepositoryImpl @Inject constructor(
private val userApiService: UserApiService,
private val dispatchers: CoroutineDispatchers,
...
) : UserRepository { ... }
- Варианты использования:
class AddUserUseCase @Inject constructor(private val userRepository: UserRepository) {
suspend operator fun invoke(user: User) = userRepository.add(user)
}
class RemoveUserUseCase @Inject constructor(private val userRepository: UserRepository) {
suspend operator fun invoke(user: User) = userRepository.remove(user)
}
class RefreshGetUsersUseCase @Inject constructor(private val userRepository: UserRepository) {
suspend operator fun invoke() = userRepository.refresh()
}
...
- ViewModel:
class MainVM @ViewModelInject constructor(
private val getUsersUseCase: GetUsersUseCase,
private val refreshGetUsers: RefreshGetUsersUseCase,
private val removeUser: RemoveUserUseCase,
) : ViewModel() { ... }
- Активность:
@AndroidEntryPoint
class MainActivity : AppCompatActivity(), View {
private val mainVM by viewModels<MainVM>()
...
}
Отредактировано:
Для введения контекста приложения:
Во-первых, удалите это определение, поскольку Hilt
уже предоставляет контекст приложения:
@Singleton
@Provides
fun provideApplicationContext() = MyApplication()
Во-вторых, используйте аннотацию @ApplicationContext в вашем параметре контекста.
class MainViewModel @ViewModelInject constructor(
@ApplicationContext private val context: Context,
private val repository: Repository,
@Assisted private val savedStateHandle: SavedStateHandle
) : ViewModel() {
Комментарии:
1. Но у вас нет приложения, переданного в параметрах..
2. Обновленный ответ, надеюсь помочь вам
3. При этом отображается предупреждение
This field leaks a context object
Ответ №2:
Используйте @ApplicationContext Context context
в качестве параметра в конструкторе.