我已经使用Clean Architecture构建了应用程序,现在我计划将网络层验证添加到其中.

下面是我如何在我的应用程序中实现这一点的代码.

interface JokeApi {
    @GET("joke/Any")
    suspend fun getJoke(): Response<JokeResponseDto>
}
class JokeRepositoryImpl @Inject constructor(private val jokeApi: JokeApi) : JokeRepository {
    override suspend fun getJoke(): NetworkResponse<JokeResponse> {
        return handleApiResponse { jokeApi.getJoke() }
    }
}
  • HandleApiResponse函数返回类型为NetworkResponse<JokeResponseDto>
suspend fun <T> handleApiResponse(execute: suspend () -> Response<T>): NetworkResponse<T> {
    return try {
        val response = execute()
        val body = response.body()
        if (response.isSuccessful && body != null) {
            NetworkResponse.Success(data = body)
        } else {
            NetworkResponse.Error(errorMessage = response.message())
        }
    } catch (exception: HttpException) {
        NetworkResponse.Error(errorMessage = exception.localizedMessage)
    } catch (throwable: Throwable) {
        NetworkResponse.Exception(throwable = throwable)
    }
}
sealed class NetworkResponse<T>(
    val data: T? = null,
    val errorMessage: String? = null,
    val exception: Throwable? = null,
) {
    class Success<T>(data: T) : NetworkResponse<T>(data = data)
    class Error<T>(errorMessage: String?) : NetworkResponse<T>(errorMessage = errorMessage)
    class Exception<T>(throwable: Throwable) : NetworkResponse<T>(exception = throwable)
}

在这种情况下,问题是改进返回JokeResponseDto响应对象,其中JokeRepositoryImpl预期JokeResponse的AS getJoke函数在此代码mapping中的情况下是有效的.

我try 在handleApiResponse方法中添加映射,因为它是泛型类型,所以没有过多考虑实现.

下面是我如何try 将响应转换为另一个仅具有必要细节的对象.

class JokeResponseMapper : Mapper<JokeResponseDto, JokeResponse> {
    override fun mapFrom(from: JokeResponseDto): JokeResponse {
        return JokeResponse(
            error = from.error,
            type = from.type.orEmpty(),
            setUp = from.type,
            joke = from.joke,
        )
    }
}
interface Mapper<F, T> {
    fun mapFrom(from: F): T
}

任何代码方面的帮助都将不胜感激.

推荐答案

您可以创建将响应对象映射到域模型的接口:

interface DtoModel<T> {
     fun mapToDomain(): T
}

然后按如下方式更改handleApiResponse:

 suspend fun <R: DtoModel<T>, T: Any> handleApiResponse(execute: suspend () -> Response<R>): NetworkResponse<T> {
    return try {
        val response = execute()
        val body = response.body()
        if (response.isSuccessful && body != null) {
            NetworkResponse.Success(data = body.mapToDomain())
        } else {
            NetworkResponse.Error(errorMessage = response.message())
        }
    } catch (exception: HttpException) {
        NetworkResponse.Error(errorMessage = exception.localizedMessage)
    } catch (throwable: Throwable) {
        NetworkResponse.Exception(throwable = throwable)
    }
}

并这样称呼它:

return handleApiResponse { jokeApi.getJoke() }

现在,JokeResponseDto必须实现该接口,而您必须在其中实现mapToDomain函数.

例如:

class JokeResponseDto(
    ....
    .... 
): DtoModel<JokeResponse> {
     override fun mapToDomain(): JokeResponse {
          return JokeResponse(
              ...
          )
     }
 }

Android相关问答推荐

RippleTheme在作曲material 1.7.0中被废弃

ENV变量在gradle进程中没有更新

理解修饰符<;方法>;与修饰符<;方法>;:效果和行为解释(Android开发者Jetpack Compose)

懒惰的垂直网格中盒子的重量-Jetpack组合

译码BLE血糖仪特征值

请求标头为空/无法通过拦截器获取

如何将Unicode符号作为文本居中放置在布局中的按钮(Android XML)中?

在androidStudio中,如何使用带有ResolutionStrategy的ResolutionSelector而不是setTargetResolve()?

从 Jetpack Compose 中的图像中删除默认高度

Spinner - onItemLongClick 从未执行

当我想使用例如 material3 时,为什么我需要添加对 material 的依赖?底部导航?

如何在 Jetpack Compose 中处理水平滚动手势和变换手势

如何使用滑行加载媒体的专辑封面?

需要在按钮 onclick 上从 string.xml 获取值. @Composable 调用只能在@Composable 函数的上下文中发生

java.lang.ExceptionInInitializerError -- 原因:java.lang.NullPointerException

在jetpack compose中将图像添加到脚手架顶部栏

如何在 MAUI 项目中包含每个平台的现有 C++ 库?

Android - 水平(从右到左)圆形背景 colored颜色 过渡

如何在 kotlin 的 android room DB 中设置一对多关系

如何获取 Android Preferences DataStore 的所有键