【问题标题】:Unresolved inject method on Dagger2 methodDagger2 方法上未解决的注入方法
【发布时间】:2018-06-12 10:37:47
【问题描述】:

我正在尝试将一组 Room 组件注入到一个 Repository 中,该 Repository 本身使用 Dagger2 注入到一个 ViewModel(在一个片段中)。

代码如下。

片段:

class MyFragment : Fragment() {
    private var viewModel: MyViewModel? = null

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        viewModel = ViewModelProviders.of(this).get(MyViewModel::class.java)
        viewModel!!.init()
        viewModel!!.getUser().observe(this, Observer<MyClass?> {...})
    }
    ...
}

查看模型:

class MyViewModel : ViewModel() {

    @Inject lateinit var myRepo: MyRepository

    private var instance: LiveData<MyClass>? = null

    fun init() {
        DaggerAppComponent.builder()
                .build().daggerInject(this)
        if (this.instance != null) {
            return
        }
        instance = myRepo.getInstance()
    }
}

我的仓库:

@Singleton
class MyRepository {
    @Inject lateinit var myDao: MyDao
    @Inject lateinit var executor: Executor

    init {
        DaggerAppComponent.builder().build().daggerInject(this)
    }
}

最后,对于我的匕首类,我有两个模块:

@Module(includes = [AndroidInjectionModule::class])
abstract class AppModule {

    @Binds
    abstract fun application(app: MyApplication): MyApplication
}


@Module
class DataModule {

    @Inject
    lateinit var application: MyApplication

    val myDatabase = Room.databaseBuilder(application, MyDatabase::class.java, "my-database").build()

    @Provides
    @Singleton
    fun provideRepository(): MyRepository {
        return MyRepository()
    }

    @Provides
    fun provideMyDao(): MyDao {
        return MyDao_Impl(myDatabase)
    }

    @Provides
    fun providesExecutor(): Executor {
        return Executors.newSingleThreadExecutor()
    }

}

还有我的 AppComponent:

@Singleton
@Component(modules = [AppModule::class, DataModule::class])
interface AppComponent : AndroidInjector<MyApplication> {
    fun daggerInject(viewModel: MyViewModel)
    fun daggerInject(myRepo: MyRepository)

    @Component.Builder
    abstract class Builder: AndroidInjector.Builder<MyApplication>()
}

Dagger 编译良好,我可以访问 DaggerAppComponent 并构建它。但是,dataModule 是不可访问的(检查类将其显示为私有),我需要实际注入依赖项的 daggerInject 方法也是如此。结果我得到了错误:

Unresolved reference: daggerInject

我该如何解决这个问题?

【问题讨论】:

  • 我们将不胜感激:-)
  • 如果您为正在创建的每个类都创建一个新组件,那么@Singleton 的意义何在...?
  • 是的,我也对此感到困惑。我一直在阅读很多高度冲突的指南,因此代码可能看起来有点奇怪。

标签: android kotlin dagger-2 android-room


【解决方案1】:
inline fun <reified T: ViewModel> AppCompatActivity.createViewModel(crossinline factory: () -> T): T = T::class.java.let { clazz ->
    ViewModelProviders.of(this, object: ViewModelProvider.Factory {
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            if(modelClass == clazz) {
                @Suppress("UNCHECKED_CAST")
                return factory() as T
            }
            throw IllegalArgumentException("Unexpected argument: $modelClass")
        }
    }).get(clazz)
}

inline fun <reified T: ViewModel> Fragment.createViewModel(crossinline factory: () -> T): T = T::class.java.let { clazz ->
    ViewModelProviders.of(this, object: ViewModelProvider.Factory {
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            if(modelClass == clazz) {
                @Suppress("UNCHECKED_CAST")
                return factory() as T
            }
            throw IllegalArgumentException("Unexpected argument: $modelClass")
        }
    }).get(clazz)
}

和片段:

class MyFragment : Fragment(), Injectable {
    private lateinit var viewModel: MyViewModel

    @Inject lateinit var appComponent: AppComponent 

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        viewModel = createViewModel { appComponent.myViewModel() }
        viewModel.getUser().observe(this) {...}
    }
    ...
}

查看模型:

class MyViewModel @Inject constructor(private val myRepo: MyRepository): ViewModel() {

    private var instance: LiveData<MyClass>? = myRepo.getInstance()
}

我的仓库:

@Singleton
class MyRepository @Inject constructor(
    private val myDao: MyDao, 
    private val executor: Executor
) {
}

最后,对于我的匕首类,我有两个模块:

@Module(includes = [AndroidInjectionModule::class])
abstract class AppModule {
    fun application(myApplication: MyApplication): Application = myApplication
}
@Module
abstract class DataModule {
    @Provides
    fun myDatabase(application: Application) = 
        Room.databaseBuilder(application, MyDatabase::class.java, "my-database").build()

    @Provides
    fun myDao(): MyDao = myDatabase.myDao()

    @Provides
    fun providesExecutor(): Executor =
        Executors.newSingleThreadExecutor()
}

还有我的 AppComponent:

@Singleton
@Component(modules = [AppModule::class, DataModule::class])
interface AppComponent : AndroidInjector<MyApplication> {
    @Component.Builder
    abstract class Builder: AndroidInjector.Builder<MyApplication>()

    fun myViewModel(): MyViewModel
}

和 AppInjector:

import android.app.Activity
import android.app.Application
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentActivity
import android.support.v4.app.FragmentManager
import dagger.android.AndroidInjection
import dagger.android.support.AndroidSupportInjection
import dagger.android.support.HasSupportFragmentInjector

/**
 * Helper class to automatically inject fragments if they implement [Injectable].
 */
object AppInjector {
    fun init(myApp: MyApplication) {
        DaggerAppComponent.builder().application(myApp)
            .build().inject(myApp)
        myApp
            .registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
                override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
                    handleActivity(activity)
                }

                override fun onActivityStarted(activity: Activity) {

                }

                override fun onActivityResumed(activity: Activity) {

                }

                override fun onActivityPaused(activity: Activity) {

                }

                override fun onActivityStopped(activity: Activity) {

                }

                override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle?) {

                }

                override fun onActivityDestroyed(activity: Activity) {

                }
            })
    }

    private fun handleActivity(activity: Activity) {
        if (activity is HasSupportFragmentInjector) {
            AndroidInjection.inject(activity)
        }
        if (activity is FragmentActivity) {
            activity.supportFragmentManager
                .registerFragmentLifecycleCallbacks(
                    object : FragmentManager.FragmentLifecycleCallbacks() {
                        override fun onFragmentCreated(
                            fm: FragmentManager,
                            f: Fragment,
                            savedInstanceState: Bundle?
                        ) {
                            if (f is Injectable) {
                                AndroidSupportInjection.inject(f)
                            }
                        }
                    }, true
                )
        }
    }
}

class MyApplication : Application(), HasActivityInjector {
    @Inject
    lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>

    override fun onCreate() {
        super.onCreate()
        AppInjector.init(this)
    }

    override fun activityInjector() = dispatchingAndroidInjector
}

【讨论】:

    猜你喜欢
    • 2018-11-12
    • 1970-01-01
    • 1970-01-01
    • 2010-11-16
    • 2014-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-03
    相关资源
    最近更新 更多