1

When I'm visiting the application and once accessing this fragment(MenstrualFragment), the application crashes and this is displayed in the Logcat -

2022-06-23 15:44:59.110 11278-11278/com.miniproject.monthlies E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.miniproject.monthlies, PID: 11278
    java.lang.RuntimeException: Cannot create an instance of class com.miniproject.monthlies.ui.fragments.menstruation.menstrual.MenstrualViewModel
        at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.kt:188)
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:238)
        at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:112)
        at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:146)
        at dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.create(HiltViewModelFactory.java:111)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:171)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:139)
        at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:44)
        at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:31)
        at com.miniproject.monthlies.ui.fragments.MenstrualFragment.getMViewModel(MenstrualFragment.kt:52)
        at com.miniproject.monthlies.ui.fragments.MenstrualFragment.observeViewModel(MenstrualFragment.kt:127)
        at com.miniproject.monthlies.ui.fragments.MenstrualFragment.onCreateView(MenstrualFragment.kt:72)
        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2963)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:518)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2106)
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
        at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:524)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:255)
        at android.app.ActivityThread.main(ActivityThread.java:8212)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:632)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1049)
     Caused by: java.lang.InstantiationException: java.lang.Class<com.miniproject.monthlies.ui.fragments.menstruation.menstrual.MenstrualViewModel> has no zero argument constructor
        at java.lang.Class.newInstance(Native Method)
        at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.kt:186)
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:238) 
        at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:112) 
        at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:146) 
        at dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.create(HiltViewModelFactory.java:111) 
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:171) 
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:139) 
        at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:44) 
        at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:31) 
        at com.miniproject.monthlies.ui.fragments.MenstrualFragment.getMViewModel(MenstrualFragment.kt:52) 
        at com.miniproject.monthlies.ui.fragments.MenstrualFragment.observeViewModel(MenstrualFragment.kt:127) 
        at com.miniproject.monthlies.ui.fragments.MenstrualFragment.onCreateView(MenstrualFragment.kt:72) 
        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2963) 
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:518) 
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282) 
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189) 
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2106) 
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002) 
        at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:524) 
        at android.os.Handler.handleCallback(Handler.java:938) 
        at android.os.Handler.dispatchMessage(Handler.java:99) 
        at android.os.Looper.loop(Looper.java:255) 
        at android.app.ActivityThread.main(ActivityThread.java:8212) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:632) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1049)

MenstrualViewModel-

package com.miniproject.monthlies.ui.fragments.menstruation.menstrual

import android.content.Context
import androidx.lifecycle.MutableLiveData
import com.miniproject.monthlies.feature.mapper.MenstrualPeriodResumeMapper
import com.google.firebase.firestore.ktx.toObject
import com.miniproject.monthlies.data.firebase.FirebaseUtil
import com.miniproject.monthlies.data.model.menstrual.MenstrualPeriodMonthly
import com.miniproject.monthlies.data.model.menstrual.MenstrualPeriodResume
import com.miniproject.monthlies.data.remote.RemoteRepository
import com.miniproject.monthlies.feature.model.menstrual.MenstrualPeriodMonthlyIntent
import com.miniproject.monthlies.feature.model.menstrual.MenstrualPeriodResumeIntent
import com.miniproject.monthlies.ui.activities.base.BaseFirebaseListener
import com.miniproject.monthlies.ui.activities.base.BaseViewModel
import com.miniproject.monthlies.util.Const
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.*
import javax.inject.Inject

//@HiltViewModel
class MenstrualViewModel @Inject constructor(
    val firebaseUtil: FirebaseUtil,
    private val repository: RemoteRepository,
) : BaseViewModel() {
//private val sharePreferenceUtil: SharePreferenceUtil,
    //@ApplicationContext private val application: Context
//class MenstrualViewModel(private val repository: Repository): ViewModel() {
    private val menstrualPeriodResumeMapper = MenstrualPeriodResumeMapper.getInstance()

    var activeYear = ""

    var activeYearData: MenstrualPeriodMonthlyIntent? = null

    var maxCycleLong = 0
    var minCycleLong = 0
    var periodLong = 0
    var activeMonth = 0

    val progressGetMenstrualRecord = MutableLiveData<Boolean>()
    val successGetMenstrualRecord = MutableLiveData<MenstrualPeriodMonthlyIntent>()
    val errorGetMenstrualRecord = MutableLiveData<String>()
    fun getMenstrualPeriod(year: String){
        CoroutineScope(Dispatchers.IO).launch {
            try {
                progressGetMenstrualRecord.postValue(true)
                val user = firebaseUtil.firebaseAuth.currentUser
                activeYear = year
                periodLong = 0
                activeMonth = 0
                firebaseUtil.fireStoreDb
                    .collection(Const.COLLECTION_MENSTRUAL_PERIOD)
                    .document(user?.uid?:"")
                    .collection(activeYear)
                    .get()
                    .addOnSuccessListener {result ->
                        val menstrualPeriodMonthly = MenstrualPeriodMonthlyIntent()
                        if (!result.isEmpty){
                            for (querySnapshot in result){

                                val data = querySnapshot?.toObject<MenstrualPeriodResumeIntent>()

                                if (data != null){
                                    if (maxCycleLong == 0 && minCycleLong == 0){
                                        maxCycleLong = data.longCycle
                                        minCycleLong = data.longCycle
                                    }
                                    if (data.longCycle > maxCycleLong){
                                        maxCycleLong = data.longCycle
                                    }
                                    if (data.longCycle < minCycleLong){
                                        minCycleLong = data.longCycle
                                    }
                                    periodLong += data.longPeriod
                                    activeMonth++
                                }

                                when (querySnapshot.id){
                                    Const.KEY_JAN -> { menstrualPeriodMonthly.jan = data }
                                    Const.KEY_FEB -> { menstrualPeriodMonthly.feb = data }
                                    Const.KEY_MAR -> { menstrualPeriodMonthly.mar = data }
                                    Const.KEY_APR -> { menstrualPeriodMonthly.apr = data }
                                    Const.KEY_MAY -> { menstrualPeriodMonthly.may = data }
                                    Const.KEY_JUN -> { menstrualPeriodMonthly.jun = data }
                                    Const.KEY_JUL -> { menstrualPeriodMonthly.jul = data }
                                    Const.KEY_AUG -> { menstrualPeriodMonthly.aug = data }
                                    Const.KEY_SEP -> { menstrualPeriodMonthly.sep = data }
                                    Const.KEY_OCT -> { menstrualPeriodMonthly.oct = data }
                                    Const.KEY_NOV -> { menstrualPeriodMonthly.nov = data }
                                    Const.KEY_DEC -> { menstrualPeriodMonthly.dec = data }
                                }
                            }
                            periodLong /= activeMonth
                        }
                        progressGetMenstrualRecord.postValue(false)
                        successGetMenstrualRecord.postValue(menstrualPeriodMonthly)
                    }
                    .addOnFailureListener {exception ->
                        progressGetMenstrualRecord.postValue(false)
                        errorGetMenstrualRecord.postValue(exception.message)
                    }
            }catch (e: Exception){
                progressGetMenstrualRecord.postValue(false)
                errorGetMenstrualRecord.postValue(e.message)
            }
        }
    }

    val progressAddMenstrualRecord = MutableLiveData<Boolean>()
    val successAddMenstrualRecord = MutableLiveData<MenstrualPeriodResumeIntent>()
    val errorAddMenstrualRecord = MutableLiveData<String>()

    fun addMenstrualPeriod(menstrualPeriodResume: MenstrualPeriodResumeIntent, date: Date){
        val month = SimpleDateFormat("MMMM", Locale.US).format(date)
        addMenstrualResumeDataMonth(month, menstrualPeriodResume)
        CoroutineScope(Dispatchers.IO).launch {
            repository.addMenstrualPeriod(menstrualPeriodResumeMapper.mapFromIntent(menstrualPeriodResume)!!, object:
                BaseFirebaseListener<MenstrualPeriodResume> {
                override fun onLoading(isLoading: Boolean) {
                    progressAddMenstrualRecord.postValue(isLoading)
                }

                override fun onSuccess(data: MenstrualPeriodResume) {
                    successAddMenstrualRecord.postValue(menstrualPeriodResumeMapper.mapToIntent(data))
                }

                override fun onFailed(errorMessage: String) {
                    errorAddMenstrualRecord.postValue(errorMessage)
                }
            })
        }
    }

    fun getMenstrualResumeDataCurrentMonth(month: String): MenstrualPeriodResumeIntent? {
        return when (month){
            Const.KEY_JAN -> activeYearData?.jan
            Const.KEY_FEB -> activeYearData?.feb
            Const.KEY_MAR -> activeYearData?.mar
            Const.KEY_APR -> activeYearData?.apr
            Const.KEY_MAY -> activeYearData?.may
            Const.KEY_JUN -> activeYearData?.jun
            Const.KEY_JUL -> activeYearData?.jul
            Const.KEY_AUG -> activeYearData?.aug
            Const.KEY_SEP -> activeYearData?.sep
            Const.KEY_OCT -> activeYearData?.oct
            Const.KEY_NOV -> activeYearData?.nov
            Const.KEY_DEC -> activeYearData?.dec
            else -> null
        }
    }

    private fun addMenstrualResumeDataMonth(month: String, data: MenstrualPeriodResumeIntent) {
        when (month){
            Const.KEY_JAN -> activeYearData?.jan = data
            Const.KEY_FEB -> activeYearData?.feb = data
            Const.KEY_MAR -> activeYearData?.mar = data
            Const.KEY_APR -> activeYearData?.apr = data
            Const.KEY_MAY -> activeYearData?.may = data
            Const.KEY_JUN -> activeYearData?.jun = data
            Const.KEY_JUL -> activeYearData?.jul = data
            Const.KEY_AUG -> activeYearData?.aug = data
            Const.KEY_SEP -> activeYearData?.sep = data
            Const.KEY_OCT -> activeYearData?.oct = data
            Const.KEY_NOV -> activeYearData?.nov = data
            Const.KEY_DEC -> activeYearData?.dec = data
        }
    }
}

2 things are present in logcat i.e "cannot create an instance of ViewModel" and "ViewModel has no zero argument constructor". In this scenario, what should be done?

I recently came into the field of Android development so I'm not having much idea on what to do next.

 

2 Answers2

4

It's because you commented out @HiltViewModel.

Change

//@HiltViewModel

to

@HiltViewModel
Ivo
  • 18,659
  • 2
  • 23
  • 35
  • I tried that also but I got another error saying - error: [Dagger/MissingBinding] com.miniproject.monthlies.data.remote.RemoteRepository cannot be provided without an Inject constructor or an @Provides-annotated method. – Varsha Myadam Jun 23 '22 at 11:23
  • class RemoteRepository( private val menstrualPeriodMonthlyMapper: MenstrualPeriodMonthlyMapper, private val menstrualPeriodResumeMapper: MenstrualPeriodResumeMapper, val firebaseAuth: FirebaseAuth, val firestore: FirebaseFirestore, ){ companion object{ private var INSTANCE: RemoteRepository? = null fun getInstance() = INSTANCE ?: RemoteRepository( MenstrualPeriodMonthlyMapper.getInstance(), MenstrualPeriodResumeMapper.getInstance(), FirebaseAuth.getInstance(), Firebase.firestore, ) } } – Varsha Myadam Jun 23 '22 at 11:27
  • 1
    @VarshaMyadam that means you need to add annotations to the `RemoteRepository` as well. Something like `class RemoteRepository @Inject constructor(` though seeing that that one also expects parameters I'm not sure if it will work, unless they all can get `@Inject` annotations as well. – Ivo Jun 23 '22 at 11:32
0

I was having the same error. I my case I was missing @AndroidEntryPoint annotation in fragment that created the viewModel and you need to annotate your viewModel as @HiltViewModel.