Here is my AllFilesListViewModel class.
class AllFilesListViewModel #ViewModelInject constructor(
private val pdfItemRepository: PdfItemRepository):ViewModel() {
}
Here is PdfItemRepository class.
#Singleton
class PdfItemRepository #Inject constructor(private val pdfItemDao: PdfItemDao){
}
For pdfItemDao. I created a module named DatabaseModule. Below is the code -
#Module
#InstallIn(ApplicationComponent::class)
object DatabaseModule {
#Provides
fun provideDatabase(#ApplicationContext context: Context):AppDatabase{
return AppDatabase.getDataBase(context)
}
#Provides
fun providePdfItemDao(database:AppDatabase):PdfItemDao{
return database.pdfItemDao()
}
}
Here is the fragment class AllFilesFragment.kt where I am using viewModel.
#AndroidEntryPoint
class AllFilesFragment:Fragment(){
private lateinit var binding:AllFilesFragmentBinding
private val viewModel by viewModels<AllFilesListViewModel>()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = AllFilesFragmentBinding.inflate(inflater,container,false)
context?: return binding.root
initThings()
subscribeUi()
return binding.root
}
}
Here is logcat file.
06-19 19:22:20.203 23753-23753/com.emptysheet.pdfreader_autoscroll E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.emptysheet.pdfreader_autoscroll, PID: 23753
java.lang.RuntimeException: Cannot create an instance of class com.emptysheet.pdfreader_autoscroll.homeScreen.viewModel.AllFilesListViewModel
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:221)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:278)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:106)
at androidx.hilt.lifecycle.HiltViewModelFactory.create(HiltViewModelFactory.java:69)
at androidx.lifecycle.AbstractSavedStateViewModelFactory.create(AbstractSavedStateViewModelFactory.java:69)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelProvider.kt:54)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelProvider.kt:41)
at com.emptysheet.pdfreader_autoscroll.homeScreen.AllFilesFragment.getViewModel(AllFilesFragment.kt)
at com.emptysheet.pdfreader_autoscroll.homeScreen.AllFilesFragment.subscribeUi(AllFilesFragment.kt:72)
at com.emptysheet.pdfreader_autoscroll.homeScreen.AllFilesFragment.onCreateView(AllFilesFragment.kt:64)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:320)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1356)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1434)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:442)
at androidx.fragment.app.FragmentManager.executeOps(FragmentManager.java:2169)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1992)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1947)
at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1818)
at androidx.fragment.app.BackStackRecord.commitNow(BackStackRecord.java:297)
at androidx.viewpager2.adapter.FragmentStateAdapter.placeFragmentInViewHolder(FragmentStateAdapter.java:341)
at androidx.viewpager2.adapter.FragmentStateAdapter.onViewAttachedToWindow(FragmentStateAdapter.java:276)
at androidx.viewpager2.adapter.FragmentStateAdapter.onViewAttachedToWindow(FragmentStateAdapter.java:67)
at androidx.recyclerview.widget.RecyclerView.dispatchChildAttached(RecyclerView.java:7556)
at androidx.recyclerview.widget.RecyclerView$5.addView(RecyclerView.java:860)
at androidx.recyclerview.widget.ChildHelper.addView(ChildHelper.java:107)
at androidx.recyclerview.widget.RecyclerView$LayoutManager.addViewInt(RecyclerView.java:8601)
at androidx.recyclerview.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:8559)
at androidx.recyclerview.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:8547)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1641)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4134)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3851)
at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4404)
at android.view.View.layout(View.java:15689)
at android.view.ViewGroup.layout(ViewGroup.java:5048)
at androidx.viewpager2.widget.ViewPager2.onLayout(ViewPager2.java:527)
at android.view.View.layout(View.java:15689)
at android.view.ViewGroup.layout(ViewGroup.java:5048)
at com.google.android.material.appbar.HeaderScrollingViewBehavior.layoutChild(HeaderScrollingViewBehavior.java:148)
at com.google.android.material.appbar.V
This happens to me when using Hilt , and that was because I forgot to add the #AndroidEntryPoint annotation on top of the fragment class.
Both the fragment and the host activity should be annotated with this annotation.
This got solved after I used kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha01' in app's build.gradle. I had already added kapt "com.google.dagger:hilt-android-compiler:2.28-alpha". I still didn't understand the difference between two BTW. If anyone knows. Please explain it to me.
This is caused by a version mismatch between AndroidX Lifecycle, AndroidX Core, AndroidX Activity and AndroidX Fragment.
Hilt only works if getDefaultViewModelProviderFactory can be overridden.
This is only true if that method actually exists, which it doesn't if your dependencies are out of date. Namely, your androidx.fragment is lower than 1.2.0, and your androidx.activity is lower than 1.1.0.
Use this and it'll work:
implementation "androidx.appcompat:appcompat:1.4.1"
implementation "androidx.core:core-ktx:1.7.0"
implementation "androidx.activity:activity-ktx:1.4.0"
implementation "androidx.fragment:fragment-ktx:1.4.1"
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1'
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.1"
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.4.1"
But currently, this is what makes it work for me:
buildscript {
ext {
dagger_version = '2.41'
}
dependencies {
classpath "com.google.dagger:hilt-android-gradle-plugin:$dagger_version"
}
and
apply plugin: 'dagger.hilt.android.plugin'
apply plugin: 'kotlin-kapt'
implementation "com.google.dagger:dagger:$dagger_version"
kapt "com.google.dagger:dagger-compiler:$dagger_version"
implementation "com.google.dagger:hilt-android:$dagger_version"
kapt "com.google.dagger:hilt-android-compiler:$dagger_version"
kaptTest "com.google.dagger:hilt-android-compiler:$dagger_version"
kaptAndroidTest "com.google.dagger:hilt-android-compiler:$dagger_version"
kapt 'androidx.hilt:hilt-compiler:1.0.0'
#ViewModelInject is deprecated in the newer hilt version
Reference
Use HiltViewModel
#HiltViewModel
class AllFilesListViewModel #Inject constructor(
val pdfItemRepository: PdfItemRepository)
) : ViewModel() {
}
When I use Jetpack Compose, Hilt and Compose Navigation, my approach is to get all the dependencies in the docs, and make sure that all of their versions are up-to-date. The key is when you create ViewModel, you shouldn't use = viewModel() beacause you have use Compose Navigation, = hiltViewModel() should be used instead.
Jetpack Compose + ViewModel in NavGraph
This answer is for people who using Jetpack Compose and navigation (NavGraph)
According to Hilt and Navigation in documentation we have to use hiltViewModel instead of viewModel
Example:
dependencies {
implementation("androidx.hilt:hilt-navigation-compose:1.0.0")
}
// import androidx.hilt.navigation.compose.hiltViewModel
#Composable
fun MyApp() {
NavHost(navController, startDestination = startRoute) {
composable("example") { backStackEntry ->
// Creates a ViewModel from the current BackStackEntry
// Available in the androidx.hilt:hilt-navigation-compose artifact
val viewModel = hiltViewModel<MyViewModel>()
MyScreen(viewModel)
}
/* ... */
}
}
More and fresh information in the source
I faced this issue before and I have fixed it by passing SavedStateHandle to the main constructor of the view model.
class AuthViewModel #ViewModelInject constructor(#Assisted private val savedState: SavedStateHandle) : ViewModel()
For those who checked all the above solutions and still not working then the final check is to delete the Build folder and rebuild the project this will force the compiler to re-create the dagger dependency graph under the hood.
In my case, I have annotated my activity with #AndroidEntryPoint still facing the same issue. I have deleted my build folder and rebuild the project and it is working as expected.
In alpha03, Use the new #HiltViewModel and the normal #Inject now as shown below.
#HiltViewModel
class MyViewModel #Inject constructor(
private val repository: Repository,
private val savedStateHandle: SavedStateHandle
) : ViewModel(), LifecycleObserver {
// Some code
}
I have also faced this problem today, I tried all the possible fixes suggested but it was impossible to remove the error. I just post my solution here in case someone has the same problem in the future.
In my case I have a multi-module project, with 'UI module', 'ViewModel module' and 'Use-cases module'. The error on my side was that I was not importing all the modules in the application's gradle module, I was only importing UI module. I found this note in the Android developers website regarding hilt implementation:
Note: Because Hilt's code generation needs access to all of the Gradle modules that use Hilt, the Gradle module that compiles your Application class also needs to have all of your Hilt modules and constructor-injected classes in its transitive dependencies.
When I imported all the modules that were needed to generate the DI graph, this crash disappeared.
for me resolvec when moved = viewModel() from Compose function to Activity
Related
I am trying to use Koin to inject my viewModel (which has some dependencies as well) like this:
I don't understand why it cannot find getViewModel when I have the following import:
I am using this Koin version: implementation "io.insert-koin:koin-android:$koin_version"
where $koin_version = '3.2.0-beta-1'
Any thoughts why my import is ignored here?
You're using a wrong import, you should use:
import org.koin.androidx.compose.getViewModel
To use it you need the following dependency:
implementation("io.insert-koin:koin-androidx-compose:$koinVersion")
Here's how I did it in koin 3.3.2
#Composable
fun HomeScreen(viewModel: PokemonViewModel = koinViewModel()) {
}
I also added koin-core to build.gradle(:app)
def koin_version = '3.3.2'
implementation "io.insert-koin:koin-core:$koin_version"
implementation "io.insert-koin:koin-android:$koin_version"
implementation 'io.insert-koin:koin-androidx-compose:3.4.1'
SOURCE
When I use viewModels() as below
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
// ... more codes
}
Why is it available in
implementation 'androidx.fragment:fragment-ktx:1.3.0'
Instead, when I include things like below, it is not available in them?
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
I thought it supposed to be in the viewmodel-ktx library instead of fragment-ktx library
As per the documentation, the by viewModels() extension is an extension on the Fragment class and therefore, must belong in the fragment-ktx artifact - the lifecycle-viewmodel-ktx and lifecycle-runtime-ktx do not have any dependency on fragments and the lifecycle-extensions artifact is completely deprecated and should not be used at all as per the Lifecycle 2.2.0 release notes.
In Dagger Hilt View Model 1.0.0-alpha01
implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha01"
implementation 'com.google.dagger:hilt-android:2.28-alpha'
kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
kapt 'com.google.dagger:hilt-android-compiler:2.28-alpha'
I can use the below
class MyViewModel #ViewModelInject constructor(
private val repository: Repository,
#Assisted private val savedStateHandle: SavedStateHandle
) : ViewModel(), LifecycleObserver {
// Some codes...
}
However, when I migrate to Dagger Hilt View Model 1.0.0-alpha03
implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03"
implementation 'com.google.dagger:hilt-android:2.31.2-alpha'
kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha03'
kapt 'com.google.dagger:hilt-android-compiler:2.31.2-alpha'
I got the warnings
'Assisted' is deprecated. Deprecated in Java
'ViewModelInject' is deprecated. Deprecated in Java
'ViewModelInject' is deprecated. Deprecated in Java
'Assisted' is deprecated. Deprecated in Java
What's the new way of working on it?
In alpha03, Use the new #HiltViewModel and the normal #Inject now as shown below.
#HiltViewModel
class MyViewModel #Inject constructor(
private val repository: Repository,
private val savedStateHandle: SavedStateHandle
) : ViewModel(), LifecycleObserver {
// Some code
}
In the last update of dagger hilt, they made few changes, so in your case, you can use #HiltViewModel and #Inject to use it with ViewModel.
#HiltViewModel
class MyViewModel #Inject constructor(
private val repository: Repository,
private val savedStateHandle: SavedStateHandle
) : ViewModel(), LifecycleObserver {
// Some codes...
}
Also, if you were using ApplicationComponent, in the latest update it is changed to SingletonComponent.
So in your module class this way.
#Module
#InstallIn(SingletonComponent::class.java)
object hiltmodel....{}
#ViewModelInject has been deprecated and has been replaced by #HiltViewModel.
The ViewModel annotated with HiltViewModel will be available for creation by HiltViewModelFactory. The HiltViewModel containing a constructor annotated with Inject will have its dependencies defined in the constructor parameters injected by Dagger's Hilt.
https://dagger.dev/api/latest/dagger/hilt/android/lifecycle/HiltViewModel
A simple ViewModel will now look like :
#HiltViewModel
class MainViewModel #Inject constructor(application: Application) :
AndroidViewModel(application) {
}
or
#HiltViewModel
class MainViewModel #Inject constructor() :
ViewModel() {
}
whatever your use case might be.
Got below error after upgrading hilt to v2.31+ ?:
2021-04-02 20:05:22.443 3718-3718/com.demo.app E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.demo.app, PID: 3718
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.demo.app/com.demo.app.ux.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class com.demo.app.ux.viewmodels.MainViewModel
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808) .....
Tried most of things mentioned in here and also adding a seperate module with model view provider API, but that none of that worked one thing missed while upgrading was to change the classpath version too.
So to make this work we need to update the classpath to 2.31 and above which is present in your project gradle :
classpath "com.google.dagger:hilt-android-gradle-plugin:2.31-alpha"
releases before jan 2021 dont support the latest #HiltViewModel annotation.
So in the project level gradle in dependencies replace hilt version to 2.33-beta
buildscript{
ext.hiltVersion = "2.33-beta"
dependencies{
classpath "com.google.dagger:hilt-android-gradle-plugin:$hiltVersion"
}
}
and in the view model class instead of #viewmodelinject before constructor remove that and do this
#HiltViewModel
class TasksViewModel #Inject constructor(val taskDao: TaskDao) : ViewModel() {...}
I have implemented dependency injection in android before using dagger 2 but, recently, I have tried to use it in a new project but I get the following error:
error: cannot find symbol
import dagger.internal.InjectedFieldSignature;
^
symbol: class InjectedFieldSignature
location: package dagger.internal/location/to/App_MembersInjector.java:30: error: cannot find symbol
Here is my Application component:
#Singleton
#Component(
modules = [
(AndroidInjectionModule::class),
(VmModule::class),
(InjectorModule::class),
]
)
interface ApplicationComponent: AndroidInjector<Application> {
#Component.Builder
interface Builder{
#BindsInstance
fun application(application: App): Builder
fun build() : ApplicationComponent
}
fun inject(home: Home)
}
Then in my App class:
class App: Application(), HasAndroidInjector {
#Inject
lateinit var anAndroidInjector: DispatchingAndroidInjector<Any>
override fun onCreate() {
super.onCreate()
DaggerApplicationComponent.builder().application(this).build().inject(this)
}
override fun androidInjector(): AndroidInjector<Any> {
return anAndroidInjector
}
}
Then the injector module:
#Module
abstract class InjectorModule {
#ContributesAndroidInjector
abstract fun bindHomeActivity(): Home
}
The following is a small excerpt of my app Gradle to show the dagger version:
implementation 'com.google.dagger:dagger-android:2.24'
implementation 'com.google.dagger:dagger-android-support:2.24'
kapt 'com.google.dagger:dagger-android-processor:2.24'
kapt 'com.google.dagger:dagger-compiler:2.28'
If you have any clue, kindly let me know where the problem might be.
Your Dagger artifact versions don't match. Specifically, you are using dagger-compiler:2.28 to generate code, but including an dependency on Dagger 2.24 instead.
In the specific case of dagger.internal.InjectedFieldSignature, that class appears to have been introduced in Dagger version 2.25.3. Any later version of the Dagger compiler will expect that InjectedFieldSignature exists and can be used in generated code. However, since you're only including Dagger 2.24 in your project, the generated code ends up referring to a class that doesn't exist.
To fix this, make sure all of your Dagger dependencies use the same version.
I'm getting this note in the build whenever I do an inject into a kotlin class (btw, I have a mixed android project with both kotlin and java).
For example, after this gradle task: compileStagingDebugJavaWithJavac (StagingDebug is my build variant), I get this message:
"Note: Generating a MembersInjector or Factory for com.packageNameXXX.CourseDiscoveryMapFragment. Prefer to run the dagger processor over that class instead."
My CourseDiscoveryMapFragment code can be seen here:
class CourseDiscoveryMapFragment : Fragment(){
#Inject
lateinit var presenter: CourseDiscoveryMapPresenter
lateinit var mapView: MapView
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_discovery_map, container, false)
MapsInitializer.initialize(activity)
mapView = view.mapView
mapView.onCreate(savedInstanceState?.getBundle(BUNDLE_KEY_MAP_STATE))
(activity as BaseActivity)
.activityComponent.inject(this)
}
And my ActivityComponent is :
#ActivityScope
#Subcomponent(modules = ActivityModule.class)
public interface ActivityComponent {
void inject(BaseActivity baseActivity);
void inject(CourseDiscoveryMapFragment fragment);
//Exposed to sub-graphs.
Activity activity();
}
So, I'm having dagger component and modules written in Java, while having dagger injections in Kotlin.
Is this anything that I should be worried about?
Thank you.
I am afraid you can't. Why not write dependency modules in Kotlin?
To write dependency modules in java, you need to configure your Gradle script in this way:
compile 'com.google.dagger:dagger:2.8'
apt 'com.google.dagger:dagger-compiler:2.8'
But, to write dependency modules in Kotlin, you should configure your Gradle script in this way:
compile 'com.google.dagger:dagger:2.8'
kapt 'com.google.dagger:dagger-compiler:2.8'
dagger need the annotation processing tool to generate the dependency code during the compiling process. So I guess you just need to use the right APT(annotation processing tool) according to right language.