I use hilt for the first in my dictionary app, but when I run my app, it crash and show this log:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: ir.arinateam.dictionary, PID: 23787
java.lang.RuntimeException: Cannot create an instance of class ir.arinateam.dictionary.feature_dictionary.presentation.WordInfoViewModel
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.kt:204)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:322)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:304)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.kt:175)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.kt:138)
this is my module class: `@Module @InstallIn(SingletonComponent::class) object WordInfoModule {
@Provides
@Singleton
fun provideGetWordInfoUseCase(repository: WordInfoRepository): GetWordInfo {
return GetWordInfo(repository)
}
@Provides
@Singleton
fun provideWordInfoDatabase(app: Application): WordInfoDatabase {
return Room.databaseBuilder(
app.applicationContext, WordInfoDatabase::class.java, "word_db"
).addTypeConverter(Converters(GsonParser(Gson())))
.build()
}
@Provides
@Singleton
fun provideWordInfoRepository(
db: WordInfoDatabase,
api: DictionaryApi
): WordInfoRepository {
return WordInfoRepositoryImpl(api, db.dao)
}
@Provides
@Singleton
fun provideDictionaryApi(): DictionaryApi {
return Retrofit.Builder()
.baseUrl(DictionaryApi.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(DictionaryApi::class.java)
}
}`
And this is my mainActivity class that init viewmodel and try to use it:
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private lateinit var bindingActivity: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
bindingActivity = DataBindingUtil.setContentView(this, R.layout.activity_main)
val viewModel: WordInfoViewModel by viewModels {
SavedStateViewModelFactory(application, this)
}
lifecycleScope.launch {
viewModel.eventFlow.collectLatest { event ->
when (event) {
is WordInfoViewModel.UIEvent.ShowSnackbar -> {
Snackbar.make(bindingActivity.root, event.message, Snackbar.LENGTH_SHORT)
.show()
}
}
}
}
}
}
And this is my ViewModel:
@HiltViewModel
class WordInfoViewModel @Inject constructor(
private val getWordInfo: GetWordInfo
) : ViewModel() {
private val _searchQuery = mutableStateOf<String>("")
val searchQuery: State<String> = _searchQuery
private val _state = mutableStateOf<WordInfoState>(WordInfoState())
val state: State<WordInfoState> = _state
private val _eventFlow = MutableSharedFlow<UIEvent>()
val eventFlow = _eventFlow.asSharedFlow()
private var searchJob: Job? = null
fun onSearch(query: String) {
_searchQuery.value = query
searchJob?.cancel()
searchJob = viewModelScope.launch {
delay(500L)
getWordInfo(query)
.onEach { result ->
when (result) {
is Resource.Success -> {
_state.value = state.value.copy(
wordInfoItems = result.data ?: emptyList(),
isLoading = false
)
}
is Resource.Error -> {
_state.value = state.value.copy(
wordInfoItems = result.data ?: emptyList(),
isLoading = false
)
_eventFlow.emit(UIEvent.ShowSnackbar(result.message ?: "Unknown Error"))
}
is Resource.Loading -> {
_state.value = state.value.copy(
wordInfoItems = result.data ?: emptyList(),
isLoading = true
)
}
}
}.launchIn(this)
}
}
sealed class UIEvent {
data class ShowSnackbar(val message: String) : UIEvent()
}
}
where is the problem and how can i solve it?
CodePudding user response:
In your activity, you can now just use KTX viewModels() directly.
val viewModel: WordInfoViewModel by viewModels {
SavedStateViewModelFactory(application, this)
}
replace that part to
private val viewModel: MyViewModel by viewModels()
CodePudding user response:
Hilt lets you to inject SavedStateHandle into viewmodels, you could use it as:
@HiltViewModel
class WordInfoViewModel @Inject constructor(
private val savedStateHandle: SavedStateHandle,
private val getWordInfo: GetWordInfo
) : ViewModel() {
...
}
And in your activity:
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private val viewModel: WordInfoViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) { ... }
}
If you feel comfortable with the still alpha library:
implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03'