Home > other >  Cannot create an instance of Application ViewModel
Cannot create an instance of Application ViewModel

Time:03-09

I'm Trying to make a viewmodel scoped to my application to control logic related to showing of not showing pin in multi activity app .

I've used AndroidViewModel to pass the application to it and here is the class for AppViewModel

                          @HiltViewModel
              class AppViewModel @Inject constructor(
                  private val getUserPassCodeUseCase: GetUserPassCodeUseCase,
                  private val isPasscodeInputUseCase: IsPasscodeInputUseCase,
                  private val clearAllDataUseCase: ClearAllDataUseCase,
                  @ApplicationContext private val context: Context
              ) : AndroidViewModel((context as App)) {
              
                  private val _openPin = MutableSharedFlow<Long>()
                  val openPin = _openPin.asSharedFlow()
              
                  // uptime in millis
                  private var time: Long = 0
                  private var restoreStatus = RestoreStatus.EMPTY
                  private var isPasscode = false
                  private var passCode = ""
              
                  init {
              
                     // get user status
              
                  }
                  private fun checkIfShouldLock() {
                      viewModelScope.launch {
              
                          isPasscode = withContext(IO) {
                              isPasscodeInputUseCase()
                          }
              
                          val userHasAccount = (restoreStatus == RestoreStatus.ID_SUBMISSION
                                  || restoreStatus == RestoreStatus.TERMS_AND_CONDITION
                                  || restoreStatus == RestoreStatus.ACTIVATE_CARD
                                  || restoreStatus == RestoreStatus.FULL_NAME
                                  || restoreStatus == RestoreStatus.COMPLETED)
              
                          if (true)
                              _openPin.emit (System.currentTimeMillis() )
                      }
                  }
              
                  fun onResume() {
                      updatePasscode()
                      if (!isPasscode) {
                          time = 0
                          return
                      }
              
                      val now = SystemClock.elapsedRealtime()
                      when {
                          time == 0L -> {
                              // remember first value
                              time = now
                          }
                          // check is session expired
                          now - time > sessionExpiredTime -> {
                              time = now
                              when (restoreStatus) {
                                  RestoreStatus.COMPLETED -> checkIfShouldLock()
                                  RestoreStatus.EMPTY -> {}
                                  else -> {}
                              }
                          }
                          else -> {
                              time = now
                          }
                      }
                  }
              
                  fun onPause() {
                      updatePasscode()
                      viewModelScope.launch {
                          delay(Constants.PASSCODE_DELAY)
                          if (!isPasscode) {
                              time = 0
                              return@launch
                          }
                          // start "timer"
                          time = SystemClock.elapsedRealtime()
                      }
                  }
              
                  private fun updatePasscode() {
                      viewModelScope.launch {
                          isPasscode = withContext(IO) {
                              isPasscodeInputUseCase()
                          }
                      }
              
                  }
              
                  fun logout() {
                      viewModelScope.launch {
                          withContext(Dispatchers.IO) {
                              clearAllDataUseCase()
                          }
                      }
                  }
              
                  companion object {
                      const val MAIN_VIEW_MODEL_TAG = "AppViewModel"
                  }
              }

and here is my application class and how i try to access the viewmodel

        @HiltAndroidApp
          class App : Application(), Application.ActivityLifecycleCallbacks, 
         Configuration.Provider {
          
              @Inject
              lateinit var workerFactory: HiltWorkerFactory
          
              override fun getWorkManagerConfiguration() =
                  Configuration.Builder()
                      .setWorkerFactory(workerFactory)
                      .build()
          
              // uptime in millis
              private var time: Long = 0
          
               var appViewModel : AppViewModel ?=null
               var currentActivity : String ?=null
          
              override fun onCreate() {
                  super.onCreate()
                  AndroidThreeTen.init(this)
          
                  appViewModel = ViewModelProvider.AndroidViewModelFactory(this).create(AppViewModel::class.java)
                  appViewModel?.openPin?.onEach {
          
                     // if (authToken.isNotEmpty())
                          when (currentActivity) {
                              SplashActivity::class.java.name,
                              PinActivity::class.java.name -> Unit
                              else -> {
                                  startActivity(Intent(this, PinActivity::class.java).apply {
                                     // flag of should end with result or not
                                      // putExtra(Constants.IS_CAME_FROM_BACKGROUND, true)
                                      flags = Intent.FLAG_ACTIVITY_NEW_TASK
                                  })
                              }
          
                      }
                  }
          
          
                  setupCrashlytics()
          
                  if (BuildConfig.DEBUG)
                      Timber.plant(Timber.DebugTree())
                  else
                      Timber.plant(CrashReportingTree())
          
          
                  DyScan.init(this, Constants.DYSCAN_API_KEY)
                  registerActivityLifecycleCallbacks(this)
          
              }
          
              private fun setupCrashlytics() {
                  with(FirebaseCrashlytics.getInstance()) {
                      setCrashlyticsCollectionEnabled(!BuildConfig.DEBUG)
                  }
              }
          
              private fun isDeviceRooted(): Boolean {
                  var process: Process? = null
                  return try {
                      process = Runtime.getRuntime().exec("su")
                      true
                  } catch (e: Exception) {
                      Timber.i(e, "Rooted device command exception")
                      false
                  } finally {
                      if (process != null) {
                          try {
                              process.destroy()
                          } catch (e: Exception) {
                              Timber.i(e, "Rooted device command close exception")
                          }
                      }
                  }
              }
          
              private fun hideSystemBars(activity: Activity) {
                  val windowInsetsController =
                      ViewCompat.getWindowInsetsController(activity.window.decorView) ?: return
                  windowInsetsController.systemBarsBehavior =
                      WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE
                  windowInsetsController.hide(WindowInsetsCompat.Type.navigationBars())
              }
          
              override fun onActivityCreated(activity: Activity, p1: Bundle?) {
                  currentActivity = activity.localClassName
                  if (isDeviceRooted()) {
                      Toast.makeText(
                          activity,
                          getString(R.string.rooted_device_message),
                          Toast.LENGTH_SHORT
                      ).show()
                      activity.finishAffinity()
                  }
              }
          
              override fun onActivityStarted(p0: Activity) {
                  appViewModel?.onResume()
          
              }
              override fun onActivityResumed(p0: Activity) {}
              override fun onActivityPaused(p0: Activity) {}
              override fun onActivityStopped(activity:  Activity) {
               appViewModel?.onPause()
              }
              override fun onActivitySaveInstanceState(p0: Activity, p1: Bundle) {}
              override fun onActivityDestroyed(p0: Activity) {}
          
          }

i keep getting RuntimeException: Cannot create an instance of class x.x.AppViewModel

           2022-03-08 22:29:44.189 10889-10889/com.x.x E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.x.x, PID: 10889
java.lang.RuntimeException: Unable to create application com.x.x.App: java.lang.RuntimeException: Cannot create an instance of class com.x.x.AppViewModel
    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6991)
    at android.app.ActivityThread.access$1700(ActivityThread.java:274)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2093)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:233)
    at android.app.ActivityThread.main(ActivityThread.java:8010)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:631)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:978)
 Caused by: java.lang.RuntimeException: Cannot create an instance of class com.x.x.AppViewModel
    at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:230)
    at com.x.x.App.onCreate(App.kt:54)
    at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1208)
    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6986)
    at android.app.ActivityThread.access$1700(ActivityThread.java:274) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2093) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loop(Looper.java:233) 
    at android.app.ActivityThread.main(ActivityThread.java:8010) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:631) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:978) 
 Caused by: java.lang.NoSuchMethodException: com.x.x.AppViewModel.<init> [class android.app.Application]
    at java.lang.Class.getConstructor0(Class.java:2332)
    at java.lang.Class.getConstructor(Class.java:1728)
    at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:228)
    at com.x.x.App.onCreate(App.kt:54) 
    at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1208) 
    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6986) 
    at android.app.ActivityThread.access$1700(ActivityThread.java:274) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2093) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loop(Looper.java:233) 
    at android.app.ActivityThread.main(ActivityThread.java:8010) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:631) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:978) 

What i am doing wrong in this implementation ? Is this the right way to implement a viewModel scoped to application ?

CodePudding user response:

From what I can tell, something is trying to call a no argument constructor on your ViewModel, but you have only defined a constructor that takes arguments.

CodePudding user response:

You have arguments in viewmodel constructor. You will have to extend viewmodel factory and handle the parameters passed. Later pass the required parameter values to custom viewmodel factory instance. Finally use the custom view model factory instance in ViewModelProvider.AndroidViewModelFactory(this ,customInstance).create (AppViewModel::class.java)

  • Related