使用 Clean Architecture、MVVM 和 Koin 向数据源提供上下文的正确方法是什么?

Joe*_*oeM 8 android mvvm kotlin clean-architecture koin

我正在使用 Kotlin 开发一个 Android 应用程序,我需要在其中获取移动设备的当前位置。我已经在各种示例中找到了一种方法,但我不知道如何根据 Clean Architecture 与 MVVM 集成此逻辑。

在我的架构中,我有以下几层:表示层、用例层、数据层、域层和框架层。我用 MVVM 模式组织了表示层。我还使用 Koin 进行依赖注入。

我从框架层中的数据源获取应用程序所需的所有数据。例如,远程获取的数据或从数据库获取的数据,或设备(位置)提供的数据。

以下是从 ViewModel 获取位置所涉及的文件示例:

ConfigurationViewModel(表示层):

class ConfigurationViewModel(private val useCase: GetLocationUseCase) : ViewModel() {

    fun onSearchLocationButtonClicked() = liveData<Resource<Location>>(Dispatchers.IO) {
        emit(Resource.loading())
        try {
            emit(Resource.success(data = useCase.invoke(UseCase.None())))
        } catch (exception: Exception) {
            emit(Resource.error(message = exception.message))
        }
    }
Run Code Online (Sandbox Code Playgroud)

GetLocationUseCase(用例层):

class GetLocationUseCase(private val locationRepository: LocationRepository) :
    UseCase<Location, UseCase.None>() {

    override suspend fun invoke(params: None): Location = locationRepository.getLocation()
}
Run Code Online (Sandbox Code Playgroud)

LocationRepositoryImpl(数据层):

class LocationRepositoryImpl(private val locationDeviceDataSource: LocationDeviceDataSource) :
    LocationRepository {
    override suspend fun getLocation(): Location = locationDeviceDataSource.getLocation()
}
Run Code Online (Sandbox Code Playgroud)

LocationDeviceDataSourceImpl(框架层):

class LocationDeviceDataSourceImpl(private val context: Context) : LocationDeviceDataSource {

    override suspend fun getLocation(): Location =
        LocationServices.getFusedLocationProviderClient(context).lastLocation.await()
}
Run Code Online (Sandbox Code Playgroud)

如您所见,在LocationDeviceDataSourceImpl中,我需要上下文来获取最后一个位置。我不知道向数据源提供上下文的最佳方式是什么。我看过几个例子,但我想了解最好的方法是什么。

我看到了以下选项:

  • 使用AndroidViewModel,将应用程序的上下文提供给UseCase,将其提供给Repository,最后将其提供给DataSource。但我不确定这样是否合适,是否安全,是否保持建筑感。根据亚历克斯的回答

  • 我看到的另一个选项是通过 Koin 将 androidContext 注入到 DataSource,这是提供应用程序上下文的另一种方式。通过这种方式,上下文就不需要经过 ViewModel、UseCase 或 Repository。基于马斯利克的回答

根据我的架构集成此逻辑的适当方法是什么?为什么?或者这个问题是因为我的架构?

非常感谢您抽出时间。

Pav*_*sha 0

正确的方法是根本不在那里传递上下文。LocationDeviceDataSourceImpl 根本不应该了解上下文。不过它应该知道 FusedLocationProviderClient - 因此将已经准备好的位置客户端传递给 LocationDeviceDataSourceImpl。

并且 FusedLocationProvider 应该了解 Context,因为没有它它就无法存在 - 在您声明(或注入)所有上下文相关内容的地方声明并初始化它。这里的经验法则是仅在对象存在需要时才使用上下文。

我通常有一个包含上下文的模块,并将其提供给所有需要它的 Android 系统服务,并且我将这些对象提供给需要它们的所有其他模块,从而排除了上下文传递。