将 DAO 注入 Activity
Issue injecting DAO to an Activity
我正在尝试集成 Room、dagger 2 和 rxjava
io.reactivex.exceptions.OnErrorNotImplementedException: lateinit property userDao has not been initialized
我遇到上面的错误,我如何在 activity 中 init/access 我的 DAO 在将它注入 activity 之后?
我的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 --- //
User.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())
}
您应该先创建一个组件才能创建图形:
@Component(modules = [
AndroidInjectionModule::class,
AndroidSupportInjectionModule::class
AppModule::class,
ActivityBuilder::class])
interface ApplicationComponent : AndroidInjector<App> {
@Component.Builder
abstract class Builder : AndroidInjector.Builder<App>()
}
这里ActivityBuilder是一个映射我们所有activity的模块,那么Dagger在编译时就会知道我们的activity。
@Module
abstract class ActivityBuilder {
@ContributesAndroidInjector
abstract fun bindMainActivity(): MainActivity
}
您的应用程序应扩展 DaggerApplication class(或实施 HasActivityInjector)并覆盖 applicationInjector
方法,如下所示:
override fun applicationInjector(): AndroidInjector<App>
= DaggerApplicationComponent.builder().create(this)
最后 MainActivity
应该扩展 DaggerAppCompatActivity(或实现 HasSupportFragmentInjector
,检查在这种情况下如何做)并且应该注入所有内容。
让我知道它是否有效,也许我漏掉了什么。
创建组件:
@Component(modules=[AppModule::class])
class AppComponent{
inject(mainActivity: MainActivity)
}
然后您的应用程序 class 可以调用 onCreate()
appComponent=DaggerAppComponent.builder().appModule(AppModule(this)).build()
然后你的 activity 必须通过 getter:
获取组件
(application as MyApplication).appComponent.inject(this)
您可以使用 Gonzalo Acosta 的建议来更好地设置 Android 注入,但它比这个最小设置更复杂。另请阅读 this 以了解有关 Android 注入的更多信息。
我正在尝试集成 Room、dagger 2 和 rxjava
io.reactivex.exceptions.OnErrorNotImplementedException: lateinit property userDao has not been initialized
我遇到上面的错误,我如何在 activity 中 init/access 我的 DAO 在将它注入 activity 之后?
我的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 --- //
User.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())
}
您应该先创建一个组件才能创建图形:
@Component(modules = [
AndroidInjectionModule::class,
AndroidSupportInjectionModule::class
AppModule::class,
ActivityBuilder::class])
interface ApplicationComponent : AndroidInjector<App> {
@Component.Builder
abstract class Builder : AndroidInjector.Builder<App>()
}
这里ActivityBuilder是一个映射我们所有activity的模块,那么Dagger在编译时就会知道我们的activity。
@Module
abstract class ActivityBuilder {
@ContributesAndroidInjector
abstract fun bindMainActivity(): MainActivity
}
您的应用程序应扩展 DaggerApplication class(或实施 HasActivityInjector)并覆盖 applicationInjector
方法,如下所示:
override fun applicationInjector(): AndroidInjector<App>
= DaggerApplicationComponent.builder().create(this)
最后 MainActivity
应该扩展 DaggerAppCompatActivity(或实现 HasSupportFragmentInjector
,检查在这种情况下如何做)并且应该注入所有内容。
让我知道它是否有效,也许我漏掉了什么。
创建组件:
@Component(modules=[AppModule::class])
class AppComponent{
inject(mainActivity: MainActivity)
}
然后您的应用程序 class 可以调用 onCreate()
appComponent=DaggerAppComponent.builder().appModule(AppModule(this)).build()
然后你的 activity 必须通过 getter:
获取组件(application as MyApplication).appComponent.inject(this)
您可以使用 Gonzalo Acosta 的建议来更好地设置 Android 注入,但它比这个最小设置更复杂。另请阅读 this 以了解有关 Android 注入的更多信息。