【问题标题】:Issue injecting DAO to an Activity将 DAO 注入 Activity 的问题
【发布时间】:2018-02-10 01:50:49
【问题描述】:

我正在尝试整合 Room、dagger 2 和 rxjava

io.reactivex.exceptions.OnErrorNotImplementedException:lateinit 属性 userDao 尚未初始化

我遇到上述错误,在将 DAO 注入活动后,如何在活动中初始化/访问它?

我的 build.gradle

// --- Room --- //
implementation "android.arch.persistence.room:runtime:1.1.0-alpha1"
implementation "android.arch.persistence.room:rxjava2:1.1.0-alpha1"
kapt "android.arch.persistence.room:compiler:1.1.0-alpha1"
// --- Room --- //

// --- dagger --- //
implementation "com.google.dagger:dagger:2.14.1"
implementation "com.google.dagger:dagger-android:2.14.1"
implementation "com.google.dagger:dagger-android-support:2.14.1"
kapt "com.google.dagger:dagger-android-processor:2.14.1"
kapt "com.google.dagger:dagger-compiler:2.14.1"

//implementation 'com.google.dagger:dagger:2.14.1'
//kapt 'com.google.dagger:dagger-compiler:2.14.1'
// --- dagger --- //

// --- RxJava2 --- //
implementation "io.reactivex.rxjava2:rxandroid:2.0.1"
implementation "io.reactivex.rxjava2:rxkotlin:2.2.0"
// --- RxJava2 --- //

用户.kt

import android.arch.persistence.room.ColumnInfo
import android.arch.persistence.room.Entity
import android.arch.persistence.room.PrimaryKey

@Entity(tableName = "users")
data class User(
    @PrimaryKey
    @ColumnInfo(name = "email") val email: String,
    @ColumnInfo(name = "firstName") val first: String,
    @ColumnInfo(name = "lastName") val last: String
)

UserDao.kt

import android.arch.persistence.room.Dao
import android.arch.persistence.room.Insert
import android.arch.persistence.room.OnConflictStrategy
import android.arch.persistence.room.Query
import io.reactivex.Flowable

@Dao interface UserDao {
    @Query("SELECT * FROM users")
    fun getUsers(): Flowable<List<User>>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insert(user: User)

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertAll(users: List<User>)
}

AppDatabase.kt

import android.arch.persistence.room.Database
import android.arch.persistence.room.RoomDatabase

@Database(entities = [(User::class)], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}

AppModule.kt

import android.arch.persistence.room.Room
import android.content.Context
import com.singpost.prototype.sam.database.AppDatabase
import dagger.Module
import dagger.Provides
import javax.inject.Singleton

@Module
class AppModule(private val context: Context) {

    @Provides
    @Singleton
    fun provideAppContext() = context

    @Provides
    @Singleton
    fun providesAppDatabase(context: Context): AppDatabase =
        Room.databaseBuilder(context, AppDatabase::class.java, "/data/data/com.lsy.prototype.sam/databases/userdb.db").build()

    @Provides
    fun providesUserDao(appDatabase: AppDatabase) = appDatabase.userDao()
}

MainActivity.kt

...
import com.singpost.prototype.sam.database.User
import com.singpost.prototype.sam.database.UserDao
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.activity_main.*
import javax.inject.Inject

class MainActivity : AppCompatActivity(),
        ... {
private val compositeDisposable = CompositeDisposable()

@Inject lateinit var userDao: UserDao

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val user = User("e@mail.com", "Jack", "Potato")

        compositeDisposable.add(Observable.fromCallable { userDao.insert(user) }
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe())

    }

【问题讨论】:

  • 在 MainActivity 中,您正在注入 UserDao,您可以在不使用时将其删除。
  • 那我该如何调用我的 Dao insert(user) 方法呢?

标签: android kotlin dagger-2 rx-java2 android-room


【解决方案1】:

您应该首先创建一个组件才能创建图表:

@Component(modules = [
        AndroidInjectionModule::class,
        AndroidSupportInjectionModule::class
        AppModule::class,
        ActivityBuilder::class])
interface ApplicationComponent : AndroidInjector<App> {
    @Component.Builder
    abstract class Builder : AndroidInjector.Builder<App>()
}

这里的ActivityBuilder是一个模块来映射我们所有的活动,然后Dagger会在编译时知道我们的活动。

@Module
abstract class ActivityBuilder {

    @ContributesAndroidInjector
    abstract fun bindMainActivity(): MainActivity
}

您的应用程序应该扩展 DaggerApplication 类(或实现 HasActivityInjector)并重写 applicationInjector 方法,如下所示:

override fun applicationInjector(): AndroidInjector<App>  
    = DaggerApplicationComponent.builder().create(this)

最后,MainActivity 应该扩展 DaggerAppCompatActivity(或实现 HasSupportFragmentInjector,在这种情况下检查如何执行)并且应该注入所有内容。

让我知道它是否有效,也许我错过了什么。

【讨论】:

    【解决方案2】:

    创建一个组件:

    @Component(modules=[AppModule::class])
    class AppComponent{
       inject(mainActivity: MainActivity)
    }
    

    那么你的Application类就可以调用onCreate()

    appComponent=DaggerAppComponent.builder().appModule(AppModule(this)).build()
    

    那么你的activity必须通过getter来获取组件:

    (application as MyApplication).appComponent.inject(this)
    

    您可以使用 Gonzalo Acosta 的建议来更好地设置 Android 注入,但它比这个最小设置更复杂。另请阅读this 了解有关 Android 注入的更多信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-04
      相关资源
      最近更新 更多