TransWikia.com

Чистая архитектура в Андроид

Stack Overflow на русском Asked on December 7, 2020

Решил добавить clean architecture в свой проект, разбил код на три модуля: domain, data, presentation (он же app). Разбросал весь код по этим трем модулям и у меня возникла проблема с даггером, при попытке собрать приложение пишет что не может получить доступ к WeatherDataApiService (это интерфейс в котором я делаю API запрос с помощью библиотеки retrofit) этот интерфейс я перенес в data модуль. В общем проблема в том что я не пойму как правильно организовать dependency injection чтоб классы имели доступ к друг-другу. Получается во время сборки Даггера доступ к data модулю закрыт. Проблема в том что нужно правильно распределить зависимости между модулями.На данный момент у меня зависимости между модулями выстроены таким образом – presentation(app) зависит от domain модуля, а domain модуль зависит от data модуля

Это интерфейс WeatherDataApiService

interface WeatherDataApiService {

@GET("/v2.0/forecast/daily")
fun getWeatherData(
    @Query("city") city: String,
    @Query("days") days: Int,
    @Query("units") degreeType: String
):Single<WeatherDataApiModel>


companion object {
    operator fun invoke(): WeatherDataApiService {
        val key = "40a7956799be42f49bc8b6ac4bb8e432"
        val requestInterceptor = Interceptor{chain->
            val url = chain.request()
                .url() // HttpUrl
                .newBuilder() // HttpUrl.Builder
                .addQueryParameter("key", key) // HttpUrl.Builder
                .build()
            val request = chain.request()
                .newBuilder() // Request.Builder
                .url(url) // Request.Builder
                .build() // Request
            return@Interceptor chain.proceed(request) // Response
        }

        val okHttpClient = OkHttpClient.Builder()
            .addInterceptor(requestInterceptor) // OkHttpClient.Builder()
            .build()

        return Retrofit.Builder()
            .client(okHttpClient)
            .baseUrl("https://api.weatherbit.io")
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
            .build()
            .create(WeatherDataApiService::class.java)
    }
}

}

Это репозиторий который находится в domain модуле

class WeatherDataRepositoryImpl @Inject constructor(
    private val weatherDataApiService : WeatherDataApiService,
    private val mapper : WeatherDataMapper
) : WeatherDataRepository {
    override fun getWeatherData(
        city: String,
        days: Int,
        degreeType: String
    ): Single<WeatherData> =
        weatherDataApiService.getWeatherData(city, days, degreeType)
            .map { mapper.mapWeather(it) }
}

Это код use case где я задействую репозиторий

class FetchWeatherDataUseCase @Inject constructor(private val weatherDataRepository: WeatherDataRepository) {

    fun fetchWeatherData(city: String,days: Int,degreeType: String): Single<WeatherData> {
       return weatherDataRepository.getWeatherData(city,days,degreeType)
    }
}

Это код Даггер модуля который находится в domain

@Module
class WeatherDataRepositoryModule {

    @Provides
    @Singleton
    fun providerWeatherDataRepository(
        mapper: WeatherDataMapper,
        weatherDataApiService: WeatherDataApiService
    ): WeatherDataRepository =
        WeatherDataRepositoryImpl(
            weatherDataApiService,
            mapper
        )

    @Provides
    @Singleton
    fun providerApiService() = WeatherDataApiService()

    @Provides
    fun providerMapper() = WeatherDataMapper()
}

Это код Даггер модуля который находится в presentation(app)

@Module
class WeatherDataModule {

    @Provides
    @Singleton
    fun provideFetchWeatherDataUseCase(weatherDataRepository: WeatherDataRepository) =
        FetchWeatherDataUseCase(weatherDataRepository)
}

Это код Даггер компонента который находится в presentation(app)

@Singleton
@Component(modules = [WeatherDataModule::class, WeatherDataRepositoryModule::class])
interface WeatherDataComponent {

  fun injectWeatherDataFragment(weatherDataFragment: WeatherDataFragment)

}

Здесь я создаю даггер, код находится в presentation(app)

class App : Application() {

    lateinit var weatherDataComponent: WeatherDataComponent

    override fun onCreate() {
        super.onCreate()
        weatherDataComponent = DaggerWeatherDataComponent.create()
    }
}

Текст ошибки – cannot access WeatherDataApiService

One Answer

Проблема решена. Проблема заключалась в зависимостях между модулями которые нужно было установить в build.gradle, нужно было правильно расставить зависимости. Как правило presentation(app) зависит от data и от domain, data зависит от domain, а domain не зависит ни от кого.

build.gradle(Module.app)

    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
     ...
    implementation project(path: ':domain')
    implementation project(path: ':data')
}

build.gradle(Module.data)

    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
     ...
    implementation project(path: ':domain')
}

Answered by Artem on December 7, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP