Android с использованием Dagger2 с несколькими проектными модулями - PullRequest
0 голосов
/ 11 января 2020

У меня есть два модуля проекта (под этим я подразумеваю два android модуля с их собственным gradle, manifest и т. Д. c. Не модуль Dagger). Я называю их MyAppCore и MyApp. MyAppCore имеет логику c вокруг доступа к базе данных и доступа к сети. MyApp имеет весь пользовательский интерфейс (действия, представления, модельные представления и т. Д. c).

Я использую кинжал 2 для внедрения зависимостей различных компонентов в мой проект, однако у меня возникают проблемы, чтобы связать оба модули вместе.

MyApp и MyAppCore имеют свой собственный AppComponent, где MyApp предоставляет фабрики ViewModel, а MyAppCore - фабрики для доступа к базе данных и сети (примеры ниже).

Я не уверен, как связать и AppComponent (или Приложения) так, чтобы доступ к базе данных и сети мог быть обеспечен в MyApp. Вот что у меня есть:

Модуль MyAppCore

CoreApp

open class CoreApp : Application() {

    val appComponent: AppComponent by lazy {
        initializeComponent()
    }

    open fun initializeComponent(): AppComponent {
        return DaggerAppComponent.builder()
            .build()
    }
}

AppComponent

@Singleton
@Component(modules = [AppModule::class])
interface AppComponent {

    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(application: Application): Builder
        fun build(): AppComponent
    }
}

AppModule

@Module
class AppModule {
    @Singleton
    @Provides
    fun provideDb(app: Application) = MyDb.getInstance(app)

    @Singleton
    @Provides
    fun provideCommentDao(db: MyDb) = db.commentDao()
}

CommentRep (для доступа к CommentDao)

@Singleton
class CommentRep @Inject constructor(private val dao: CommentDao)  {

    fun saveComment(comment: Comment){
        dao.insert(comment)
    }

}

MyAppCore также имеет реализацию базы данных Room под названием MyDb и интерфейс CommentDao (я не думаю, что мне нужно добавлять этот код в этом вопросе).

модуль MyApp

MyApp

open class MyApp : Application(), DaggerComponentProvider {
    override val appComponent: AppComponent by lazy {
        initializeComponent()
    }

    open fun initializeComponent(): AppComponent {
        return DaggerAppComponent.builder()
            .applicationContext(applicationContext)
            .build()
    }
}

DaggerComponentProvider

interface DaggerComponentProvider {
    val appComponent: AppComponent
}

val Activity.injector get() = (application as DaggerComponentProvider).appComponent

AppComponent

@Singleton
@Component
interface AppComponent{

    @Component.Builder
    interface Builder {
        @BindsInstance
        fun applicationContext(applicationContext: Context): Builder
        fun build(): AppComponent
    }

    fun commentsViewModelFactory(): ViewModelFactory<CommentsViewModel>
}

ViewModelFactory

class ViewModelFactory<VM : ViewModel> @Inject constructor(
    private val viewModel: Provider<VM>
) : ViewModelProvider.Factory {

    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel> create(modelClass: Class<T>) = viewModel.get() as T
}

CommentsViewModel

class CommentsViewModel @Inject constructor(private val repository: CommentRep) : ViewModel() {   
    fun saveComment(comment: Comment){
        repository.saveComment(comment)
    }
}

А затем мои действия, которые внедряют ВМ, но я не думаю, что они необходимы для включения их кода в это вопрос.

Конечно, если я скомпилирую свой проект как этот, график из MyAppCore не будет сгенерирован, и, следовательно, я получаю ошибку, которую мне нужно предоставить CommentDao, потому что это требуется для CommentRep, который используется на CommentsViewModel. Я предполагаю, что класс приложения MyAppCore переопределяется классом приложения MyApp, и, следовательно, AppComponent MyAppCore никогда не создается и, следовательно, никогда не добавлял все инъекции ядра в мой график. Как мне решить эту проблему? Заранее спасибо!

1 Ответ

1 голос
/ 11 января 2020

Просто используйте один компонент. Сначала добавьте модуль MyAppCore в зависимости от gradle MyApp. Затем пусть модуль MyApp предоставит компонент, который будет включать все модули кинжала в обоих модулях проекта.

Вы также можете изменить модуль MyAppCore на библиотечный модуль, поскольку вам нужен только один модуль приложения. В вашем файле build.gradle замените:

apply plugin: 'com.android.application'

на

apply plugin: 'com.android.library'

Чтобы добавить модуль MyAppCore в зависимости модуля MyApp, добавьте:

implementation project(":myappcore")

И для Ваш компонент в модуле MyApp:

@Singleton
@Component(modules=[MyAppCoreModule::class, MyAppModule::class])
interface AppComponent {
...
}

Таким образом, в основном вам нужно предоставить модули только в MyAppCore.

...