Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to Access ViewModel from Fragment #4563

Open
Cengizhanerturan opened this issue Jan 8, 2025 · 4 comments
Open

Unable to Access ViewModel from Fragment #4563

Cengizhanerturan opened this issue Jan 8, 2025 · 4 comments

Comments

@Cengizhanerturan
Copy link

Cengizhanerturan commented Jan 8, 2025

I want to access my ViewModel class from a Fragment as shown below:

//Error
private val viewModel: MyViewModel by viewModels()

//No Error
private val viewModel: MyViewModel by activityViewModels()

If no class is injected into my ViewModel class via its constructor, I can access it using this method without encountering any errors. However, when a class is injected into the ViewModel, I am unable to access it, and I encounter the following error:

Error;

2025-01-08 16:37:26.402 12233-12233 AndroidRuntime          com.example.hilttutorial             E  FATAL EXCEPTION: main
                                                                                                    Process: com.example.hilttutorial, PID: 12233
                                                                                                    java.lang.RuntimeException: Cannot create an instance of class com.example.hilttutorial.presentation.my_fragment.MyViewModel
                                                                                                    	at androidx.lifecycle.viewmodel.internal.JvmViewModelProviders.createViewModel(JvmViewModelProviders.kt:40)
                                                                                                    	at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.android.kt:193)
                                                                                                    	at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.android.kt:317)
                                                                                                    	at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.android.kt:299)
                                                                                                    	at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.android.kt:273)
                                                                                                    	at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.kt:128)
                                                                                                    	at androidx.lifecycle.ViewModelProvider$Factory.create(ViewModelProvider.android.kt:158)
                                                                                                    	at androidx.lifecycle.viewmodel.ViewModelProviderImpl_androidKt.createViewModel(ViewModelProviderImpl.android.kt:34)
                                                                                                    	at androidx.lifecycle.viewmodel.ViewModelProviderImpl.getViewModel$lifecycle_viewmodel_release(ViewModelProviderImpl.kt:65)
                                                                                                    	at androidx.lifecycle.viewmodel.ViewModelProviderImpl.getViewModel$lifecycle_viewmodel_release$default(ViewModelProviderImpl.kt:47)
                                                                                                    	at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.android.kt:91)
                                                                                                    	at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:51)
                                                                                                    	at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:35)
                                                                                                    	at com.example.hilttutorial.presentation.my_fragment.MyFragment.getViewModel(MyFragment.kt:15)
                                                                                                    	at com.example.hilttutorial.presentation.my_fragment.MyFragment.onViewCreated(MyFragment.kt:34)
                                                                                                    	at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:3152)
                                                                                                    	at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:608)
                                                                                                    	at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:286)
                                                                                                    	at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:114)
                                                                                                    	at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1685)
                                                                                                    	at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3319)
                                                                                                    	at androidx.fragment.app.FragmentManager.dispatchViewCreated(FragmentManager.java:3230)
                                                                                                    	at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:3153)
                                                                                                    	at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:608)
                                                                                                    	at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:286)
                                                                                                    	at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:114)
                                                                                                    	at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1685)
                                                                                                    	at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3319)
                                                                                                    	at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3237)
                                                                                                    	at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:263)
                                                                                                    	at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:350) at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:251)
                                                                                                    	at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1582)
                                                                                                    	at android.app.Activity.performStart(Activity.java:8628)
                                                                                                    	at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3807)
                                                                                                    	at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:225)
                                                                                                    	at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:205)
                                                                                                    	at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:177)
                                                                                                    	at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:98)
                                                                                                    	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2443)
                                                                                                    	at android.os.Handler.dispatchMessage(Handler.java:106)
                                                                                                    	at android.os.Looper.loopOnce(Looper.java:205)
                                                                                                    	at android.os.Looper.loop(Looper.java:294)
2025-01-08 16:37:26.403 12233-12233 AndroidRuntime          com.example.hilttutorial             E  	at android.app.ActivityThread.main(ActivityThread.java:8177)
                                                                                                    	at java.lang.reflect.Method.invoke(Native Method)
                                                                                                    	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
                                                                                                    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
                                                                                                    Caused by: java.lang.NoSuchMethodException: com.example.hilttutorial.presentation.my_fragment.MyViewModel.<init> []
                                                                                                    	at java.lang.Class.getConstructor0(Class.java:3325)
                                                                                                    	at java.lang.Class.getDeclaredConstructor(Class.java:3063)
                                                                                                    	at androidx.lifecycle.viewmodel.internal.JvmViewModelProviders.createViewModel(JvmViewModelProviders.kt:38)
                                                                                                    	... 46 more

Note 1

On the other hand, when I try to access the ViewModel using the following method, I don't encounter any issues:

private val viewModel: MyViewModel by activityViewModels()

Note 2

To help better understand the issue, I am attaching the relevant ViewModel, Fragment, and Hilt module files to this report.

AppModule.kt

package com.example.hilttutorial.data.di

import com.example.hilttutorial.data.repository.RepositoryImpl
import com.example.hilttutorial.domain.repository.Repository
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@InstallIn(SingletonComponent::class)
@Module
object AppModule {
    @Singleton
    @Provides
    fun provideRepository(): Repository = RepositoryImpl()

}

MyFragment.kt

package com.example.hilttutorial.presentation.my_fragment

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import com.example.hilttutorial.R

class MyFragment : Fragment() {

    // Error
    private val viewModel: MyViewModel by viewModels()

    //No Error
    //private val viewModel: MyViewModel by activityViewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_my, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        //ViewModel getData function started
        viewModel.getData()
    }
}

MyViewModel.kt

package com.example.hilttutorial.presentation.my_fragment

import androidx.lifecycle.ViewModel
import com.example.hilttutorial.domain.repository.Repository
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject

@HiltViewModel
class MyViewModel @Inject constructor(
    private val repository: Repository
) : ViewModel() {

    fun getData(): Boolean {
        return repository.getData()
    }
}

Repository.kt

package com.example.hilttutorial.domain.repository

interface Repository {
    fun getData(): Boolean
}

RepositoryImpl.kt

package com.example.hilttutorial.data.repository

import com.example.hilttutorial.domain.repository.Repository

class RepositoryImpl : Repository {
    override fun getData(): Boolean {
        return true
    }
}

MainActivity.kt

package com.example.hilttutorial.presentation

import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.navigation.fragment.NavHostFragment
import com.example.hilttutorial.R
import com.example.hilttutorial.databinding.ActivityMainBinding
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            insets
        }
    }
}

HiltTutorialApplication.kt

package com.example.hilttutorial.presentation

import android.app.Application
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class HiltTutorialApplication : Application() {
}

build.gradle (app)

plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.kotlin.android)
    id("androidx.navigation.safeargs.kotlin")
    id("kotlin-kapt")
    id("com.google.dagger.hilt.android")
}

android {
    namespace 'com.example.hilttutorial'
    compileSdk 35

    defaultConfig {
        applicationId "com.example.hilttutorial"
        minSdk 24
        targetSdk 35
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_11
        targetCompatibility JavaVersion.VERSION_11
    }
    kotlinOptions {
        jvmTarget = '11'
    }
    buildFeatures {
        viewBinding = true
        dataBinding = true
    }
}

dependencies {
    implementation libs.androidx.core.ktx
    implementation libs.androidx.appcompat
    implementation libs.material
    implementation libs.androidx.activity
    implementation libs.androidx.constraintlayout
    testImplementation libs.junit
    androidTestImplementation libs.androidx.junit
    androidTestImplementation libs.androidx.espresso.core

    implementation 'androidx.fragment:fragment-ktx:1.8.5'
    implementation 'androidx.activity:activity-ktx:1.9.3'

    // coroutine lifecycle scope
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7"
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.8.7"
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'

    // navigation
    implementation "androidx.navigation:navigation-fragment-ktx:2.8.5"
    implementation "androidx.navigation:navigation-ui-ktx:2.8.5"

    //hilt
    implementation "com.google.dagger:hilt-android:2.54"
    kapt "com.google.dagger:hilt-android-compiler:2.54"
    kapt("org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.5.0")
}

build.gradle (project)

plugins {
    alias(libs.plugins.android.application) apply false
    alias(libs.plugins.kotlin.android) apply false
    id("androidx.navigation.safeargs.kotlin") version "2.8.5" apply false
    id("com.google.dagger.hilt.android") version "2.54" apply false
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:name=".presentation.HiltTutorialApplication"
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.HiltTutorial"
        tools:targetApi="31">
        <activity
            android:name=".presentation.MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
@dmapr
Copy link

dmapr commented Jan 8, 2025

I'm guessing it's the missing @AndroidEntryPoint on the MyFragment class.

@Cengizhanerturan
Copy link
Author

I'm guessing it's the missing @AndroidEntryPoint on the MyFragment class.

@dmapr Thank you for your response.

Yes, when I add the @androidentrypoint annotation to my 'MyFragment' class, I do not encounter any errors.

However, is this the correct approach? I have already added the @androidentrypoint annotation to my MainActivity class, and this implies that I need to add @androidentrypoint to each of my fragment classes as well.

@dmapr
Copy link

dmapr commented Jan 8, 2025

@Cengizhanerturan — yes, it is the correct approach: Inject Dependencies into Android classes.

@Cengizhanerturan
Copy link
Author

@Cengizhanerturan — yes, it is the correct approach: Inject Dependencies into Android classes.

@dmapr Got it, thank you for your response.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants