0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Kotlin + Android + ViewModelだってDIしたい!!!

Posted at

概要

Android超絶初心者の僕がkotlinでViewModelをDIするときに苦戦したのでメモ程度にViewModelをDIする方法を書きます。

全体設計

今回作っていたのでTodoリストのようなもので
スクリーンショット 2020-05-28 18.00.37.png
めちゃくちゃざっくりした設計はこんな感じです。

今回やりたかったこと

TodoViewModelからFirestoreRepositoryをDIしたかった。

普段のDI

firestoreRepositoryからFirebaseFirestoreをDIするときは

class FirestoreRepository(val db: FirebaseFirestore = FirebaseFirestore.getInstance()) {

こんな感じでかけていたので特に苦戦することはなかったのですが....

詰まった点

同じようにTodoViewModelの方で

class TodoViewModel(
    application: Application,
    private val firestoreRepository: FirestoreRepository = FirestoreRepository()
) : AndroidViewModel(application) {

こんな感じで書いた所、実行時に

 Process: com.example.myapplication, PID: 12747
    java.lang.RuntimeException: Cannot create an instance of class com.example.myapplication.TodoViewModel
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:269)
        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.myapplication.fragment.IndexFragment.onCreateView(IndexFragment.kt:31)
        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:310)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1185)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1354)
        at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1432)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1495)
        at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:447)
        at androidx.fragment.app.FragmentManager.executeOps(FragmentManager.java:2167)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1990)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1945)
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1847)
        at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
     Caused by: java.lang.NoSuchMethodException: com.example.myapplication.TodoViewModel.<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.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.myapplication.fragment.IndexFragment.onCreateView(IndexFragment.kt:31) 
        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698) 
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:310) 
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1185) 
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1354) 
        at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1432) 
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1495) 
        at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:447) 
        at androidx.fragment.app.FragmentManager.executeOps(FragmentManager.java:2167) 
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1990) 
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1945) 
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1847) 
        at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413) 
        at android.os.Handler.handleCallback(Handler.java:883) 
        at android.os.Handler.dispatchMessage(Handler.java:100) 
        at android.os.Looper.loop(Looper.java:214) 
        at android.app.ActivityThread.main(ActivityThread.java:7356) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 

このようなエラーが吐かれてしまった...

解決策

Factoryクラスなるものを作ればいけるとのこと。
基本的にここに書かれてるんですけど、Javaなんですよね...
https://stackoverflow.com/questions/46283981/android-viewmodel-additional-arguments

kotlinバージョンだと

Factoryクラスは

package com.example.myapplication

import android.app.Application
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider

class TodoViewModelFactory(
    private var application: Application
) : ViewModelProvider.Factory {

    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return TodoViewModel(application) as T
    }
}

こんな感じで、呼び出し側は

viewModel = ViewModelProvider(
            requireActivity(),
            TodoViewModelFactory(mainActivity.application)
        ).get(TodoViewModel::class.java)

こんな感じになるかと

解決。
Dagger?とか使えばこれも簡単らしい...???

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?