I am new in adroid , so I have a simple project, I want to create simple register project, so I have viewmodel in my project and I amusing Hilt library also in there, and when I build project it is throw an error for
myViewModel = ViewModelProvider(this)[MyViewModel::class.java]
as a "Cannot create an instance of class com.app.myapp.viewModel", I do not know what I missed?
class Register : ComponentActivity() {
private lateinit var myViewModel: MyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
myViewModel = [ViewModelProvider(this)::class.java]
setContent {
RegisterScreen(myViewModel)
}
}
}
#Composable
fun RegisterScreen(
myViewModel: MyViewModel
) {
}
Reasons may cause system can not create viewModel:
Your viewModel class is not Public
Your package name which contains viewModel contains special keywords (such a "package.new.feature")
If you are using dagger hilt you should putt annotation #HiltViewModel above the class declaration and create constructor like
#HiltViewModel
class viewModel #Inject constructor() : ViewModel()
With the dagger hilt You should use hiltViewModel() function to create instance for compose instead of viewModel()
dependency: androidx.hilt:hilt-navigation-compose
#Composable
fun MyExample (viewModel: MyViewModel = hiltViewModel())
Your ViewModel class does not extend from androidx.lifecycle.ViewModel
You should create your ViewModel class extending from the ViewModel, something like RegisterViewModel.
Take a look at the documentation for more info:
https://developer.android.com/topic/libraries/architecture/viewmodel
You are trying to create a view model from the base class ViewModel. it doesn't work like this
You need to create your own viewmodel class and extend it from the base class ViewModel like this
class MyViewModel : ViewModel() {
}
So your code will be like
class MyViewModel : ViewModel() {
// your implementation
}
class Register : ComponentActivity() {
private lateinit var viewModel: MyViewModel // changes to this line
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel = ViewModelProvider(this)[MyViewModel::class.java] // changes to this line
setContent {
RegisterScreen(viewModel)
}
}
}
BUT if you are using compose you should look at the integration between viewmodel and compose
to make your composable use the viewModel without you creating it then passing it to the composable
#Composable
fun MyExample(
viewModel: MyViewModel = viewModel()
) {
// use viewModel here
}
Probably it has a simple solution that I cant see. I have a fragment with a ViewModel, The Viewmodel has a method inside of it that I want to call from my fragment and supply the arguments for. but when I try to call the method it shows an error "Unsolved Reference"
class DetailFragmentViewModel : ViewModel() {
private val repo = Crepository.get()
private val itemIdlivedata = MutableLiveData<UUID>()
var crimeLiveDate: LiveData<Crime?> = Transformations.switchMap(itemIdlivedata){ it ->
repo.getitem(it) }
fun LoadItem(itemuuid:UUID){
itemIdlivedata.value = itemuuid
}
}
Fragment Class:
private val crimeDetailVM : ViewModel by lazy {
ViewModelProvider(this).get(DetailFragmentViewModel::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
crimeDetailVM.LoadItem <- Unsolved Reference
}
Thanks for the help!
EDIT:IT HAS A SIMPLE SOLUTION, I DID NOT CAST THE VIEW MODEL TO THE VIEW MODEL CLASS,THANKS FOR THE HELP EVERYONE
You are doing downcasting DetailFragmentViewModel to ViewModel. That is why you are not accessing to DetailFragmentViewModel methods.
Use
private val crimeDetailVM : DetailFragmentViewModel by lazy {
ViewModelProvider(this).get(DetailFragmentViewModel::class.java)
}
Instead of
private val crimeDetailVM : ViewModel by lazy {
ViewModelProvider(this).get(DetailFragmentViewModel::class.java)
}
Also this way is not idiomatic i suggest you to use kotlin extension
val viewModel by viewModels<DetailFragmentViewModel>()
But before do that you need to add the dependency which is Fragment KTX to your app gradle file.
https://developer.android.com/kotlin/ktx
You need activity context
try:
ViewModelProvider(requireActivity()).get(DetailFragmentViewModel::class.java)
you can use also extend view model by ActivityViewModel
eg.-> class DetailFragmentViewModel(application:Application) : AndroidViewModel(applivation){}
I'm using lifecycle version 2.2.0-rc03 and the official docs and articles found don't even list the correct class name or constructor arguments. I think I have to get the ViewModel instance through something like this
viewModel = ViewModelProvider(this, SavedStateViewModelFactory(requireActivity().application, savedStateRegistryOwner))
.get(SelectedTracksViewModel::class.java)
but I can't figure out the SavedStateRegistryOwner.
Can someone give a simple example of how to create the saved state ViewModel instance and the correct way to save and restore a value in the ViewModel?
For using Saved State module for View Model you have to add the androidx.lifecycle:lifecycle-viewmodel-savedstate dependency to your project. This example has been written based on version 1.0.0-rc03.
Please add the following line to your project Gradle file:
implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:1.0.0-rc03'
ViewModel implementation:
class SavedStateViewModel(private val state: SavedStateHandle) : ViewModel() {
val liveData = state.getLiveData("liveData", Random.nextInt().toString())
fun saveState() {
state.set("liveData", liveData.value)
}
}
Activity implementation:
class SavedStateActivity : AppCompatActivity() {
lateinit var viewModel: SavedStateViewModel;
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityStateBinding = DataBindingUtil.setContentView(this, R.layout.activity_state)
viewModel = ViewModelProvider(this, SavedStateViewModelFactory(this.application, this)).get(SavedStateViewModel::class.java)
binding.viewModel = viewModel
binding.lifecycleOwner = this
}
override fun onSaveInstanceState(outState: Bundle) {
if(::viewModel.isInitialized)
viewModel.saveState()
super.onSaveInstanceState(outState)
}
}
I have tested this code and it works fine.
I am adding an answer to this old post just in case someone might find it useful.
I managed to do it as follows:
Add the following dependency to your "build.gradle (Module: app)" file
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
Add savedState: SavedStateHandle property to the constructor of the ViewModel
class SelectedTracksViewModel(private val savedState: SavedStateHandle) : ViewModel() {
companion object {
private const val SAVED_TRACK_INDEX = "savedTrackIndex"
}
private var trackIndex: Int
set(value) {
field = value
// Simply update the savedState every time your saved property changes
savedState.set(SAVED_TRACK_INDEX, value)
}
init {
trackIndex = savedState.get<Int>(SAVED_TRACK_INDEX) ?: 0
}
fun moveToNextTrack() {
trackIndex++
// Initially I was updating savedState here - now moved to setter
// Some more code here
}
}
Finally in the activity/fragment
private val selectedTracksViewModel: SelectedTracksViewModel by lazy {
ViewModelProvider(this).get(SelectedTracksViewModel::class.java)
}
And that's it. No need for SavedStateViewModelFactory, simply add the savedState property to your ViewModel constructor and update it when tracked properties change. Everything else works as if you're not using savedState: SavedStateHandle and this way is very similar to the traditional onSaveInstanceState(Bundle) in activities/fragments.
Update: Initially I was updating savedState after changing trackIndex. This means one has to update savedState every time saved properties are changed. This is a huge potential future bug if one forgets to add that line. A better and more robust pattern is to update the savedState in the setter of the property.
As far as I understand you want to create View model with spec constructor.
You can use ViewModelProvider.Factory.
viewModel = ViewModelProvider(this, SavedStateViewModelFactory.create(state)
.get(SelectedTracksViewModel::class.java)
example of ViewModelFactory
public class SavedStateViewModelFactory {
public static <E> ViewModelProvider.Factory create(State state){
return new ViewModelProvider.Factory() {
#NonNull
#Override
#SuppressWarnings("unchecked")
public <T extends ViewModel> T create(#NonNull Class<T> modelClass) {
if (modelClass.isAssignableFrom(SelectedTracksViewModel.class)) {
return (T) new SelectedTracksViewModel<>(state);
} else {
throw new IllegalArgumentException("Unknown ViewModel class");
}
}
};
}
}
I'm building the architecture of a new Android application using Kotlin and Android Architecture Components (ViewModel, LiveData) and I'm also using Koin as my dependency injection provider.
The problem is that I'm not been able to initialize the ViewModel in a generic way inside my BaseActivity via koin injection. The current code looks like this:
abstract class BaseActivity<ViewModelType : ViewModel> : AppCompatActivity() {
// This does not compile because of the generic type
private val viewModel by lazy {
// Koin implementation to inject ViewModel
getViewModel<ViewModelType>()
}
#CallSuper
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Fabric.with(this, Crashlytics())
}
/**
* Method needed for Calligraphy library configuration
*/
#CallSuper
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase))
}
}
I'd like to know if is there a way to do this in Kotlin because I'm pretty sure I would be able to do in Java easily.
Thanks.
The solution was provided by the koin team in version 0.9.0-alpha-11 and the final code looks like this:
open class BaseActivity<out ViewModelType : BaseViewModel>(clazz: KClass<ViewModelType>) :
AppCompatActivity() {
val viewModel: ViewModelType by viewModel(clazz)
fun snackbar(message: String?) {
message?.let { longSnackbar(find(android.R.id.content), it) }
}
fun toast(message: String?) {
message?.let { longToast(message) }
}
}
Here is example of not passing Class and Generic to base implementation
In your base fragment/activity:
abstract class BaseFragment<T : BaseViewModel> : Fragment() {
...
#Suppress("UNCHECKED_CAST")
private val clazz: KClass<T> = ((this.javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<T>).kotlin
protected val viewModel: T by viewModel(clazz = clazz)
...
}
It looks ugly, but it works.
you can use a delegate version declaration for your ViewModel and avoid using directly a lazy expression. Try with this:
abstract class BaseActivity<T : ViewModel> : AppCompatActivity() {
val model by viewModel<T>()
}
This will give you a lazy of
getViewModel<T>()
Throw an eye on the quick ref: https://insert-koin.io/docs/1.0/getting-started/android-viewmodel/
Hope it will help.
I am trying to write a sample app using Android architecture components and but even after trying for days I could not get it to work. It gives me the above exception.
Lifecycle owner:-
public class MainActivity extends LifecycleActivity {
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = findViewById(R.id.tv_user);
PostViewModel viewModel = ViewModelProviders.of(this).get(PostViewModel.class);
viewModel.loadPosts();
viewModel.getPost().observe(this, new Observer<Post>() {
#Override
public void onChanged(#Nullable Post post) {
if(post != null) {
textView.setText(post.toString());
}
}
});
}
}
ViewModel:-
public class PostViewModel extends ViewModel {
private MediatorLiveData<Post> post;
private PostRepository postRepo;
PostViewModel() {
post = new MediatorLiveData<>();
postRepo = new PostRepository();
}
public LiveData<Post> loadPosts() {
post.addSource(postRepo.getPost(),
post -> this.post.setValue(post)
);
return post;
}
#NonNull
public LiveData<Post> getPost() {
return post;
}
}
if you are using Hilt, ensure your activity/fragment is having #AndroidEntryPoint annotation
Make your constructor public.
If you are using Kotlin make sure to replace any annotationProcessor in build.gradle with kapt.
Like:
annotationProcessor "android.arch.persistence.room:compiler:$rootProject.roomVersion"
Will become
kapt "android.arch.persistence.room:compiler:$rootProject.roomVersion"
and add
apply plugin: 'kotlin-kapt' on top of the buidl.gradle file.
Annotation Processing with Kotlin
Make sure your ViewModel has constructor with only one parameter i.e. Application.
example:
public YourViewModel(Application application) {
super(application);
...
DaggerHilt can also be the reason, If you are using it make sure your activity/fragment is having #AndroidEntryPoint annotation on it.
There are few reason to throw the exception . I have mention some of them..
Make sure your view Model class is public
Make sure your view model class constructor is public
Make sure you have added the dependency in your gradle file for
lifecycle also if you use room and other libraries you have added ..
if you create object any other dependent class in your view model
class constructor . Other class can throw error to create the
instance of viewModel
I had this problem following google's roomdb CodeLab. Solution was changing the following.
Edited
Add the following Build dependencies to Gradle file (as of 2/22/2020)
implementation 'androidx.fragment:fragment:1.2.2'
implementation 'androidx.lifecycle:lifecycle-process:2.2.0'
implementation 'androidx.lifecycle:lifecycle-service:2.2.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0'
annotationProcessor 'androidx.lifecycle:lifecycle-compiler:2.2.0'
Imports within the fragment
import androidx.lifecycle.ViewModelProvider;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
Creating the viewModel. Add one of the following methods.
Note: I'v seen this done many ways. I believe the correct way is using getDefaultViewModelProviderFactory(). But I have been using requireActivity().
new ViewModelProvider(requireActivity(),getDefaultViewModelProviderFactory()).get(YourViewModel.class);
|
new ViewModelProvider(requireActivity()).get(YourViewModel.class);
ViewModelProvider Docs
Deprecated
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0-rc01'
annotationProcessor 'androidx.lifecycle:lifecycle-compiler:2.2.0-rc01'
Add #HiltViewModel on top of your viewModel .
For people using Jetpack Compose, Navigation and Hilt
Make sure to use the hiltNavGraphViewModel instead of viewModel.
This is provided by androidx.hilt:hilt-navigation-compose dependency.
More details in the docs.
It was not completely obvious to me, but when getting this error I resolved it by creating a public constructor. My constructor was derived from the Android Developer examples and contained the Repository as a parameter. Creating an additional constructor that was empty with no params and having it public solved the issue.
i.e., in your case
public PostViewModel() {}
Make the class and constructor public it solved my problem .
Extend AndroidViewModel from your ViewModel class.
public class YourViewModel extends AndroidViewModel {
public YourViewModel(Application application) {
super(application);
//Todo: ...
}
}
If you used viewmodel inside your activity check that your activity extends "DaggerAppCompatActivity" or not
For instance
public class UserComments extends AppCompatActivity
change this to
public class UserComments extends DaggerAppCompatActivity
Mostly, Solution is making Class and Constructor Public as the other answers
It may also be a runtime error, check the Logcat Error Logs if there are multiple causes listed.
If you are using Hilt then don't forget to add these four dependencies.
implementation "com.google.dagger:hilt-android:2.28-alpha"
kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"
implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha01'
kapt "androidx.hilt:hilt-compiler:1.0.0-alpha01"
Note:- If any of these dependencies are missing you will get Cannot create an instance of class ViewModel error
In my case, the reason was that I was trying to get a shared instance of the ViewModel in my fragment too soon - before the activity was created. What happens when the application is restoring its state after being killed.
Preconditions:
My ViewModel has a public constructor.
My ViewModel has multiple arguments. But this is absolutely fine as I use ViewModelFactory to construct the ViewModel.
My Fragment and Activity shares the same instance of the ViewModel. In other words: Activity creates the ViewModel and the fragment receives the same instance later.
Code in activity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//factory is constructed using Dagger
val factory = App.get().components().appComponent.getMapViewModelFactory()
//activity creates the instance of MapViewModel
viewModel = ViewModelProviders.of(this, factory)[MapViewModel::class.java]
}
Code in fragment:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//fragment receives the instance of MapViewModel
viewModel = ViewModelProviders.of(activity!!)[MapViewModel::class.java]
...
}
When I open the app for the first time, everything works fine: activity creates an instance of ViewModel; I open Fragment, which gets the instance of ViewModel. But when the application is trying to restore its state after being killed, first it calls the body of onCreate of the Fragment and then the body of onCreate of the Activity. At that point, the fragment can't get the ViewModel as Activity had not created it yet.
Solution 1: Move the code when the fragment gets the ViewModel from onCreate to onViewCreated. This is fine as I observe all live data in onViewCreated as well.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = activity?.run { ViewModelProviders.of(this)[MapViewModel::class.java] } ?: throw Exception("Invalid Activity")
viewModel.getSurveyDateLiveData().observe(viewLifecycleOwner, Observer<String> { dateTextView.text = it })
...
}
Solution 2:
Create the instance of ViewModel in Activity.onCreate before super.onCreate is called. In this case, you can get the ViewModel in your fragment's onCreate.
override fun onCreate(savedInstanceState: Bundle?) {
val factory = App.get().components().appComponent.getMapViewModelFactory()
viewModel = ViewModelProviders.of(this, factory)[MapViewModel::class.java]
super.onCreate(savedInstanceState)
Timber.d("cc: onCreate: $this ")
}
Solution 3:
If you are injecting repository instance in your ViewModel, Check that you are not using #Inject constructor(...): ViewModel() to inject your repository, but rather **#ViewModelInject constructor(...): ViewModel()**
I fixed the same problem by doing this.
Note:- I am using Dagger hilt, Room database, MVVM, Data binding
Added the annotation.
class AlertViewModel
#Inject
constructor(private val userRepository: AlertRepository) : ViewModel(){
val getList:LiveData<List<Alert>> get() =
userRepository.getList.flowOn(Dispatchers.Main)
.asLiveData(context = viewModelScope.coroutineContext)
fun insert(user:Alert){
viewModelScope.launch {
userRepository.insert(user)
}
}
}
To
#HiltViewModel // Added this annotation
class AlertViewModel
#Inject
constructor(private val userRepository: AlertRepository) : ViewModel(){
val getList:LiveData<List<Alert>> get() =
userRepository.getList.flowOn(Dispatchers.Main)
.asLiveData(context = viewModelScope.coroutineContext)
fun insert(user:Alert){
viewModelScope.launch {
userRepository.insert(user)
}
}
}
I got this after migrating to AndroidX.
There's a bug in androidx.lifecycle:lifecycle-viewmodel:2.0.0-beta01 where Proguard removes the constructor.
https://issuetracker.google.com/issues/112230489
Fix by upgrading to 2.0.0, and remember to update your proguard rules if needed.
My error message looked like this:
java.lang.RuntimeException: Cannot create an instance of class my.custom.viewmodel.CustomViewModel
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:202)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:135)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:103)
......
Caused by: java.lang.NoSuchMethodException: <init> [class android.app.Application]
at java.lang.Class.getConstructor0(Class.java:2204)
at java.lang.Class.getConstructor(Class.java:1683)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:200)
... 34 more
androidx.test.espresso.PerformException: Error performing 'single click - At Coordinates: 539, 1167 and precision: 16, 16' on view 'with id: my.test:id/button_return_to_main_menu'.
at androidx.test.espresso.PerformException$Builder.build(PerformException.java:82)
at androidx.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:79)
.....
Caused by: java.lang.RuntimeException: Unable to start activity ComponentInfo{my.custom.domain.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class my.custom.viewmodel.CustomViewModel
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
if your PostViewModel class is an inner class, make sure its public and static
Please add below code. It worked for me
val binding = FragmentLayoutBinding.inflate(inflater, container, false)
val viewModel = ViewModelProvider(
requireActivity(),
defaultViewModelProviderFactory
).get(MainViewModel::class.java)
If you face this issue in Kotlin Dagger Hilt even after #HiltViewModel and using #Inject, make sure you have updated all hilt dependencies.
In my case I needed to use a ListItemViewModelFactory to pass in a parameter to my view model.
In my case, it was gradle a dependencies problem.
If you are using Livedata,,
build.gradle(Module.app)
not
implementation 'android.arch.lifecycle:extensions:1.1.1'
kapt 'android.arch.lifecycle:common-java8:1.1.1'
use these
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
kapt 'androidx.lifecycle:lifecycle-common-java8:2.2.0'
If you're using Hilt Dependency Injection, You probably have missed #ViewModelInject. Because, Hilt provide its own injection for viewmodel.
In my case, I used and #Inject due to this caught into the error.
I had a different scenario when creating a view model instance:
I was requesting for the instance in a fragment.
My ViewModel required a parameter to be passed on the constructor.
I was not using Dependency Injection.
Solution
In a scenario where your viewmodel requires a parameter to be passed you have to create a ViewModelFactory to define your instances
Solution In Practice
- ViewModel Sample
class SharedViewModel(private val repository: UserRepository) : ViewModel() {
init {
viewModelScope.launch {
repository.refreshDataInDb()
}
}
}
- Creating ViewModel Factory
class ViewModelFactory(
private val repository: UserRepository
) : ViewModelProvider.NewInstanceFactory(){
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return SharedViewModel( repository as UserRepository) as T
}
}
- Creating ViewModel Instannce in a Fragment
private lateinit var factory: ViewModelFactory
private lateinit var searchViewModel: SharedViewModel
private lateinit var repository: UserRepository
repository = UserRepository()
factory = ViewModelFactory(repository)
searchViewModel = ViewModelProvider(requireActivity(), factory)[SharedViewModel::class.java]
My problem was that the IDE had added a "abstract" modifier to my ViewModel class.
Make ViewModal class and constructure public
If constructor of your viewmodel is public and accepts only application then make sure you can create your own model without ViewModelProvider. Error message might be much more clear:
val model = YouViewModel(app)
I'm a proficient Android developer and I have used ViewModel 100s of times with no issue. Today I came across this issue. Spent hours and scrolled through various SO posts. Didn't get solved.
Then I saw that the package name in which I have the ViewModel contains new. Like this:
com.myapp.myfeature.new.feature
I changed new to neww for testing like this:
com.myapp.myfeature.neww.feature
and it worked! I hope someone find it useful.
If you are using version 2.33-beta and upper remove these dependencies;
implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03"
kapt "androidx.hilt:hilt-compiler:1.0.0-beta01"
Keep only these two dependency
implementation "com.google.dagger:hilt-android:2.33-beta"
kapt "com.google.dagger:hilt-android-compiler:2.33-beta"