Kotlin for Android(四)Retrofit + RxJava

如果您之前学习 Android MVP ,很可能是从 AndroidMVPSample
(https://github.com/WuXiaolong/AndroidMVPSample )开始的,此Sample最初是 Android MVP 示例,后来融合 Retrofit 和 RxJava,分别演示了普通写法(Retrofit)、普通写法(Retrofit+Rxjava)、MVP+Retrofit+Rxjava,跟它一样,我写了 Kotlin 版 Retrofit +RxJava 来练手,还是以天气示例。

依赖

build.gradle

1
2
3
4
5
6
7
8
9
10
11
12
buildscript {
ext.kotlin_version = '1.1.2-4'
ext.retrofit_version = '2.0.2'
ext.rxkotlin_version = '0.60.0'
ext.rxandroid_version = '1.2.1'
dependencies {
classpath 'com.android.tools.build:gradle:2.3.1'
//编译 Kotlin 源代码和模块.
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

app/build.gradle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
android {
//……
}
dependencies {
//针对 JDK 7 或 JDK 8
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
//Retrofit
compile "com.squareup.retrofit2:retrofit:$retrofit_version"
compile "com.squareup.okhttp3:logging-interceptor:$logging_interceptor_version"
compile "com.squareup.retrofit2:converter-gson:$retrofit_version"
compile "com.squareup.retrofit2:adapter-rxjava:$retrofit_version"
//RxJava
compile "io.reactivex:rxkotlin:$rxkotlin_version"
compile "io.reactivex:rxandroid:$rxandroid_version"
}

网络权限

AndroidManifest.xml

1
<uses-permission android:name="android.permission.INTERNET" />

WeatherinfoModel

天气接口:http://www.weather.com.cn/adat/sk/101190201.html
当我们使用 Gson 来解析 json 到我们的类中,这些属性的名字必须要与json中的名字一样,哎,我又忘记这点,因此浪费了很多时间排错。

1
2
3
4
5
6
7
data class WeatherinfoModel constructor(val weatherinfo: WeatherinfoBean) {
data class WeatherinfoBean(
val city: String,
val cityid: String
)
}

ApiStores

网络请求 url 都放这里:

1
2
3
4
5
6
7
8
9
10
interface ApiStores {
companion object {
//baseUrl
val API_SERVER_URL = "http://www.weather.com.cn/"
}
//加载天气
@GET("adat/sk/{cityId}.html")
fun loadData(@Path("cityId") cityId: String): Observable<WeatherinfoModel>
}

ApiClient

Retrofit 初始化、配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//object声明单例模式
object ApiClient {
fun retrofit(): ApiStores {
val builder = OkHttpClient.Builder()
if (BuildConfig.DEBUG) {
// Log信息拦截器
val loggingInterceptor = HttpLoggingInterceptor()
loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
//设置 Debug Log 模式
builder.addInterceptor(loggingInterceptor)
}
val okHttpClient = builder.build()
val retrofit = Retrofit.Builder()
.baseUrl(ApiStores.API_SERVER_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(okHttpClient)
.build()
//ApiStores::class.java取得对象的 Java 类
return retrofit.create(ApiStores::class.java)
}
}

ApiCallback

还是做了回调:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
abstract class ApiCallback<M> : Subscriber<M>() {
abstract fun onSuccess(model: M)
abstract fun onFailure(msg: String?)
abstract fun onFinish()
override fun onCompleted() {
onFinish()
}
override fun onNext(m: M) {
onSuccess(m)
}
override fun onError(e: Throwable?) {
//这块应该可以优化
if (e is HttpException) {
val httpException = e
//httpException.response().errorBody().string()
val code = httpException.code()
var msg = httpException.message
Log.d("wxl", "code=" + code)
if (code == 504) {
msg = "网络不给力"
}
if (code == 502 || code == 404) {
msg = "服务器异常,请稍后再试"
}
onFailure(msg)
} else {
onFailure(e.toString())
}
onFinish()
}
}

BaseActivity

建了基类,可以把一些公用的方法放到这里,方便:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
open class BaseActivity : AppCompatActivity() {
val mCompositeSubscription: CompositeSubscription = CompositeSubscription()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onDestroy() {
if (mCompositeSubscription.hasSubscriptions()) {
//取消注册,以避免内存泄露
mCompositeSubscription.unsubscribe()
}
super.onDestroy()
}
open fun <M> addSubscription(observable: Observable<M>, subscriber: Subscriber<M>) {
mCompositeSubscription.add(
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber))
}
}

MainActivity

请求接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//冒号表示继承
class MainActivity : BaseActivity() {
//问号表示该变量可以为空
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//object为对象表达式
addSubscription(ApiClient.retrofit().loadData("101190201"), object : ApiCallback<WeatherinfoModel>() {
override fun onSuccess(model: WeatherinfoModel) {
Log.d("wxl", "city=" + model.weatherinfo.city + ",cityid=" + model.weatherinfo.cityid)//输出“city=无锡,cityid=101190201”
}
override fun onFailure(msg: String?) {
Log.d("wxl", "onFailure=" + msg)
}
override fun onFinish() {
Log.d("wxl", "onFinish")
}
})
}
}

参考

Keddit — Part 6: API — Retrofit & Kotlin

Kotlin for Android 实践



联系作者

我的微信公众号:吴小龙同学,欢迎关注交流,公号回复关键字「1024」有惊喜哦。