安卓端如何优雅的使用Retrofit配合协程示例代码
val code: Int,// 状态码val message: String,// 提示信息// 具体数据(泛型参数,类型灵活变化)data class WeatherData(val main: Main,// 温度等核心信息val weather: List<Weather>, // 天气描述// 温度等信息val temp: Double,// 温度。
·
1.基础的数据类
data class BaseResponse<T>(
val code: Int, // 状态码
val message: String, // 提示信息
val data: T? // 具体数据(泛型参数,类型灵活变化)
)
data class WeatherData(val main: Main, // 温度等核心信息
val weather: List<Weather>, // 天气描述
val name: String )
// 温度等信息
data class Main(
val temp: Double, // 温度
val humidity: Int // 湿度
)
// 天气描述
data class Weather(
val description: String // 描述(如"晴朗")
)
2.请求类
RequestApiClient
object RequestApiClient {
// 基础 URL(根据实际接口修改)
private const val BASE_URL = "https://api.openweatherma.org/data/2.5/"
// OkHttpClient 实例(全局单例)
private val okHttpClient: OkHttpClient by lazy {
// 日志拦截器(开发环境启用)
val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.addInterceptor(loggingInterceptor) // 添加拦截器
.build()
}
// Retrofit 实例(全局单例)
val retrofit: Retrofit by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient) // 关联 OkHttpClient
.addConverterFactory(GsonConverterFactory.create()) // Gson 解析
.build()
}
}
3.ApiService
interface ApiService {
@GET("weather")
suspend fun getWeather(
@Query("q") city: String,
@Query("appid") apiKey: String
): BaseResponse<WeatherData>
}
4.请求结果密封类
sealed class Result<out T> {
// 加载中状态(适用于需要展示加载动画的场景)
object Loading : Result<Nothing>()
// 成功状态(携带数据)
data class Success<out T>(val data: T) : Result<T>()
// 失败状态(细分异常类型)
sealed class Failure : Result<Nothing>() {
// 网络异常
data class NetworkError(val exception: Exception) : Failure()
// 解析异常(如JSON格式错误)
data class ParseError(val exception: Exception) : Failure()
// 业务错误(如服务器返回的错误码:401未授权、404不存在)
data class BusinessError(val code: Int, val message: String) : Failure()
// 其他未知错误
data class UnknownError(val exception: Exception) : Failure()
data class NoDataError(val noData: String) : Failure()
}
/**
* 判断当前结果是否为成功状态
*/
val isSuccess: Boolean
get() = this is Success
/**
* 判断当前结果是否为失败状态
*/
val isFailure: Boolean
get() = this is Failure
/**
* 判断当前结果是否为加载中状态
*/
val isLoading: Boolean
get() = this is Loading
}
// 扩展函数:安全获取成功数据(失败时返回null)
fun <T> Result<T>.getDataOrNull(): T? {
return (this as? Result.Success<T>)?.data
}
// 扩展函数:获取失败信息(非失败状态返回null)
fun Result<*>.getErrorMsgOrNull(): String? {
return when (this) {
is Result.Failure.NetworkError -> "网络异常:${exception.message}"
is Result.Failure.ParseError -> "数据解析错误:${exception.message}"
is Result.Failure.BusinessError -> "业务错误($code):$message"
is Result.Failure.UnknownError -> "未知错误:${exception.message}"
is Result.Failure.NoDataError -> "数据为空"
else -> null
}
}
/**
* Result 扩展函数:处理失败状态
*/
fun Result<*>.handleFailure(context: Context) {
if (this is Result.Failure) {
val errorMsg = when (this) {
is Result.Failure.NetworkError -> "网络异常"+exception.message
is Result.Failure.ParseError -> "数据解析错误,请稍后重试"
is Result.Failure.BusinessError -> "操作失败:${message}(错误码:${code})"
is Result.Failure.UnknownError -> "未知错误:${exception.message ?: "请联系客服"}"
is Result.Failure.NoDataError -> "数据为空"
}
Toast.makeText(context, errorMsg, Toast.LENGTH_SHORT).show()
}
}
5.请求仓库Repository
class WeatherRepository(private val weatherApi: ApiService) {
// 获取天气数据(suspend 函数,在协程中调用)
suspend fun fetchWeather(city: String, apiKey: String): Result<WeatherData> {
return try {
// 调用接口(通过单例的 weatherApi)
val response = weatherApi.getWeather(city, apiKey)
// 根据接口返回的 code 处理结果
if (response.code == 0) {
response.data?.let {
Result.Success(it) // 成功:返回具体数据
} ?: Result.Failure.NoDataError("数据为空")
} else {
// 业务错误(如 code 非 200)
Result.Failure.BusinessError(code = response.code, message = response.message)
}
} catch (e: Exception) {
// 捕获异常(网络错误、解析错误等)
when(e){
is JsonParseException -> {
Result.Failure.ParseError(e)
}
is IOException -> {
Result.Failure.NetworkError(e)
}
else -> {
Result.Failure.UnknownError(e)
}
}
}
}
}
6.ViewModel
class MainActivityViewModel: ViewModel() {
// 创建接口实例
val apiService: ApiService = RequestApiClient.retrofit.create(ApiService::class.java)
val repository = WeatherRepository(apiService)
private val _weatherState = MutableStateFlow<Result<WeatherData>>(Result.Loading)
val weatherState: StateFlow<Result<WeatherData>> = _weatherState
fun loadWeather(city: String, apiKey: String) {
viewModelScope.launch {
_weatherState.value = Result.Loading
val result = repository.fetchWeather(city, apiKey)
_weatherState.value = result
}
}
}
7.Activity
class MainActivity : AppCompatActivity() {
private val viewModel: MainActivityViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
observeResult()
viewModel.loadWeather("1","2")
}
fun observeResult(){
lifecycleScope.launch {
viewModel.weatherState.collect { result ->
when (result) {
is Result.Loading -> {
// 显示加载动画
//progressBar.visibility = View.VISIBLE
}
is Result.Success<WeatherData> -> {
// 隐藏加载,展示数据
//progressBar.visibility = View.GONE
val weatherData = result.data
//updateUi(weatherData)
}
//统一处理错误
is Result.Failure -> {
//Toast.makeText(this@MainActivity,result.getErrorMsgOrNull(), Toast.LENGTH_SHORT).show()
result.handleFailure(this@MainActivity);
}
}
}
}
}
}
完整下载链接: RetrofitDemo: Retrofit使用案例
更多推荐

所有评论(0)