Search code examples
androidkotlinandroid-runtime

AndroidViewModel Cannot Create An Instance Kotlin


I've checked the all related topics. But couldn't find a solution for myself. I was using ApiCall to load live data and it was OK. But now i need to use Roo so that even without internet connection, users will be able to use it for a while. Ok let me introduce my errors to you.

    2020-11-27 13:11:46.317 15232-15232/com.example.jirataskmvvm E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.jirataskmvvm, PID: 15232
    java.lang.RuntimeException: Cannot create an instance of class com.example.jirataskmvvm.viewModel.CityRmViewModel
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:275)
        at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:106)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
        at com.example.jirataskmvvm.view.citySelectPage.citySelectionPage.onCreateView(citySelectionPage.kt:29)
        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.addAddedFragments(FragmentManager.java:2224)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1997)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1953)
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1849)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2629)
        at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2577)
        at androidx.fragment.app.Fragment.performActivityCreated(Fragment.java:2722)
        at androidx.fragment.app.FragmentStateManager.activityCreated(FragmentStateManager.java:346)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1188)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1356)
        at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1434)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1497)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2625)
        at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2577)
        at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:247)
        at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:541)
        at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:210)
        at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1435)
        at android.app.Activity.performStart(Activity.java:8024)
        at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3475)
        at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
        at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
     Caused by: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Constructor.newInstance0(Native Method)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:267)
        at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:106) 
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185) 
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150) 
        at com.example.jirataskmvvm.view.citySelectPage.citySelectionPage.onCreateView(citySelectionPage.kt:29) 
        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.addAddedFragments(FragmentManager.java:2224) 
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1997) 
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1953) 
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1849) 
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2629) 
        at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2577) 
        at androidx.fragment.app.Fragment.performActivityCreated(Fragment.java:2722) 
        at androidx.fragment.app.FragmentStateManager.activityCreated(FragmentStateManager.java:346) 
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1188) 
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1356) 
        at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1434) 
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1497) 
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2625) 
        at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2577) 
        at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:247) 
        at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:541) 
        at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:210) 
        at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1435) 
        at android.app.Activity.performStart(Activity.java:8024) 
        at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3475) 
        at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221) 
        at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201) 
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.app.ActivityThread.main(ActivityThread.java:7656) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 
     Caused by: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
        at androidx.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:267)
        at androidx.room.RoomDatabase.query(RoomDatabase.java:323)
2020-11-27 13:11:46.317 15232-15232/com.example.jirataskmvvm E/AndroidRuntime:     at androidx.room.util.DBUtil.query(DBUtil.java:83)
        at com.example.jirataskmvvm.Room.CityDao_Impl.readAllCities(CityDao_Impl.java:70)
        at com.example.jirataskmvvm.Room.CityRoomRepository.<init>(CityRoomRepository.kt:17)
        at com.example.jirataskmvvm.viewModel.CityRmViewModel.<init>(CityRmViewModel.kt:28)
            ... 41 more
2020-11-27 13:11:46.335 15232-15232/com.example.jirataskmvvm I/Process: Sending signal. PID: 15232 SIG: 9

As you can see i get RuntimeException that says me "i cannot create an instance of class". I've searched but only thing i could find was related to just ordinary ViewModel and that didnt worked for my AndroidViewModel, all other AndroidViewModel related topics also wasn't helpful or wasn't for me.

Here is my classes.

class CityRmViewModel (application: Application):AndroidViewModel(application){

    val allCities = MutableLiveData<List<CityRm>>()

    private val cityRoomRepository: CityRoomRepository

    init {
        val cityDao = EventsDatabase.getEventsDatabase(application).cityDao()
        cityRoomRepository = CityRoomRepository(cityDao)
    }

    private fun readFromDB(){
        cityRoomRepository.readAll(allCities)

    }

    fun loadData(){
        readFromDB()
    }

    private fun addCity(cityRm: CityRm){
        viewModelScope.launch(Dispatchers.IO){
            cityRoomRepository.addCity(cityRm)
        }
    }

    fun loadDataToDB(){
        val request = cityService.buildService(CityEndPoint::class.java)
        val call = request.getCities()

        call.enqueue(object : Callback<List<City>> {
            override fun onResponse(call: Call<List<City>>, response: Response<List<City>>) {
                if (response.isSuccessful) {
                    for(i in 0..response.body()!!.size){
                        val cityRm = CityRm(response.body()!![i].id,response.body()!![i].name)
                        addCity(cityRm)
                    }
                }
            }
            override fun onFailure(call: Call<List<City>>, t: Throwable) {
                Log.d("api response:", t.message.toString())
            }
        })
    }
}

my first fragment :

class citySelectionPage : Fragment() {

    lateinit var cityViewModel: CityRmViewModel
    private val cityAdapter = cityScPageAdapter(arrayListOf())


    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        val view = inflater.inflate(R.layout.fragment_city_selection_page, container, false)

        cityViewModel = ViewModelProvider(this).get(CityRmViewModel::class.java)
        cityViewModel.loadData()


        val recyclerView = view.findViewById<RecyclerView>(R.id.cityPageRecycler)
        recyclerView.apply {
            layoutManager = LinearLayoutManager(activity)
            adapter = cityAdapter
        }

        observeViewModel()
        return view
    }

    fun observeViewModel(){
        cityViewModel.allCities.observe(viewLifecycleOwner, { cities -> cities?.let {
                cityAdapter.updateCities(it)
        }
        })
    }
}

Finally, I don't wanna make logical operations in view, at least how much i can manage to not to, because i just started a new job as a new grad student. This is my training and i need to be about clear code for company projects


Solution

  • The relevant part of the stacktrace is this

    Caused by: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
    

    You need to query your database on a non UI thread. There are many options for this, I recommend searching for info on Kotlin Coroutines as this is currently a well documented and supported feature.