SmileWeather之网络篇(Retrofit+LiveData)

SmileWeather之网络篇(Retrofit+LiveData)

前言

本系列文章将以SmileWeather为实例来记录一下如何开发一款简单的APP,麻雀虽小五脏俱全。项目地址

说两句

本项目的网络请求模块是采用的Retrofit+LiveData来实现的,第一版是采用的RxJava+Retrofit+LiveData,后面发现RxJava做的事情LiveData也可以来实现,干脆就直接把RxJava剔除了。

使用

  • 先添加对应的依赖,主要是retrofit的
 //retrofit
    api "com.squareup.retrofit2:retrofit:2.6.2"

    api 'com.squareup.retrofit2:converter-gson:2.5.0'
    //okhttp提供的请求日志拦截器
    api 'com.squareup.okhttp3:logging-interceptor:3.14.4'
  • 由于我们是采用的LiveData来承载解析后的数据,所以我们需要自定义adapter来与retrofit适配。
    编写LiveDataCallAdapterFactory类,这个类的主要作用是对网络请求后解析出来的数据进行判断,是否符合我们预期的数据。
class LiveDataCallAdapterFactory :CallAdapter.Factory() {
    override fun get(
        returnType: Type,
        annotations: Array<Annotation>,
        retrofit: Retrofit
    ): CallAdapter<*, *>? {
        if (getRawType(returnType) !=LiveData::class.java)
            return null
        //获取第一个泛型类型的数据
        val observableType = getParameterUpperBound(0, returnType as ParameterizedType)
        //获取泛型的class
        val rawType = getRawType(observableType)
        //判断是类型一致
        if (rawType != BaseResult::class.java) {
            throw IllegalArgumentException("type must be ApiResponse")
        }
        if (observableType !is ParameterizedType) {
            throw IllegalArgumentException("resource must be parameterized")
        }
        return LiveDataCallAdapter<Any>(observableType)
    }
}

然后编写LiveDataCallAdapter,这个主要是对数据类型进行分发。

class LiveDataCallAdapter<T>(private val responseType: Type) : CallAdapter<T, LiveData<T>> {
    override fun adapt(call: Call<T>): LiveData<T> {
        return object : LiveData<T>() {
            private val started = AtomicBoolean(false)
            override fun onActive() {
                super.onActive()
                if (started.compareAndSet(false, true)) {//确保执行一次
                    call.enqueue(object : Callback<T> {
                        override fun onFailure(call: Call<T>, t: Throwable) {
                            //失败了就给一个错误的数据
                            val value = BaseResult<T>("500","500", "", "",null,null,null,null) as T
                            postValue(value)
                        }

                        override fun onResponse(call: Call<T>, response: Response<T>) {
                            //成功了,将数据发送出去
                            postValue(response.body())
                        }
                    })
                }
            }
        }
    }

    override fun responseType() = responseType
}
  • BaseResult这个实体基类一般是根据后台返回的内容格式进行创建,泛型里面的内容才是我们最终需要的数据。
data class BaseResult<T>(
    var status:String,
    var code: String,
    var updateTime: String,
    var fxLink: String,
    var location: T?,
    var now: T?,
    var daily:T?,
    var hourly:T?
)
  • 接下来就是要对retrofit进行封装,由于我们采用了依赖注入的方式(hilt)所以可能和平时的有点不太一样,但是基本上都是和之前使用方式无差。依赖注入也会单独一篇记录。
    @Provides
    @Singleton
    fun providerOkHttpClient(): OkHttpClient {
        val builder = OkHttpClient.Builder()
        builder.addInterceptor(initLogInterceptor())
        return builder.build()
    }

在这里我们可以对okhttp设置我们需要的一些东西,比如说超时时间,网络拦截器等,我这里就只加了一个日志拦截器,供开发过程中查看网络请求的详细内容。
然后对Retrofit进行初始化,添加解析器和LiveData的适配器。

    @Provides
    @Singleton
    fun providerRetrofit(okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .baseUrl(Api.CITY_BASE_URL2)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(LiveDataCallAdapterFactory())
            .client(okHttpClient)
            .build()
    }
  • 最后差不多就是编写我们的Api接口了
/**
     * 获取实时天气
     */
    @GET("weather/now")
    fun getNoWData(@QueryMap map: Map<String, String>): LiveData<BaseResult<NowEntity>>
  • 对了还要写一个给外部提供API接口的方法(依赖注入的形式)
    @Provides
    @Singleton
    fun providerApiService2(@Named("retrofit2") retrofit: Retrofit): ApiService2 {
        return retrofit.create(ApiService2::class.java)
    }

使用起来就很简单了,因为我们的数据都是通过Repository去获取的,针对不同的类型数据去不同Repository获取,下面以当前实况天气为例:

class WeatherRepository @Inject constructor(private val weatherDao: CityWeatherDao,
                    private val apiService: ApiService2
):Repository{

    fun getNowWeatherInfo(map: Map<String, String>):LiveData<BaseResult<NowEntity>>{
        return apiService.getNoWData(map)
    }
    }
    
class WeatherViewModel @ViewModelInject constructor(private val weatherRepository: WeatherRepository) :BaseViewModel(){

    fun getWeatherNowInfo(id:String):LiveData<BaseResult<NowEntity>>{
       return weatherRepository.getNowWeatherInfo(getParams(id))

    }
    }

构造方法里面的参数都交给依赖注入框架给我们提供,WeatherViewModel负责去从WeatherRepository里面拿数据然后提供给UI层。以上差不多就是这个项目里面网络这一块的简单记录了。下一篇记录一下Databinding吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值