现在我们制作一个真正的 API 调用,证明我们的抽象 RxJava真实有效.之后在 App 中来显示一些真实的数据.
全部章节:
Kotlin — Part 0:关于这个系列
Kotlin — Part 1:配置 Android Studio
Kotlin — Part 2:语法,空安全,静态类型
Kotlin — Part 3:扩展函数、Android 扩展、委托属性
Kotlin — Part 4:RecyclerView— Kotlin 适配器委托&数据类
Kotlin — Part 5:Kotlin,RxJava&RxAndroid
Kotlin — Part 6:API-Retrofit&Kotlin)
Kotlin — Part 7:无限滑动:高阶函数& Lambdas
Kotlin — Part 8:方向改变(序列化&数据类)
Kotlin — Part 9:单元测试与 Kotlin(Mockito,RxJava)
Github 仓库:github.com/imuhao/Kedd…
Reddit API
让我们复习一下我们需要从 Reddit 加载的 API.我们的想法是从 Reddit 加载Top 新闻到我们的App 中.
请求 URL
我们需要去请求的 URL:
www.reddit.com/top.json?limit=10
你可以粘贴到你的浏览器,查看到像这样:
你可以查看到返回的数据是一个 JSON 格式,一个最好的方法区分析这个内容是医用一个 Json 解析,像 Json Editor Online,这是一个优秀的在线工具.
- childer:这是一个10个分类列表,每一个 children 是关于新闻的详情
- after:它允许你执行分页操作.” after”将使你得到下面10个items, 通过调用:”/top.json?after=t3_7b7zfo”
- befor:这是和” after”类似的运行你执行返回操作
一个 children 包含许多的信息.我们只是挑选一些我们需要的.
Retrofit
它是一个 Android 和 Java 中类型安全的 HTTP 客户端
Retrofit 是一个非常简单的第三方扩展,允许我们将 HTTP API 请求转变成一个 Java(Kotlin)结构.我们使用它来消费我们的 Reddit Api.
依赖
我们需要添加这个 Retrofit 依赖
compile "com.squareup.retrofit2:retrofit:2.0.0"
compile "com.squareup.retrofit2:converter-moshi:2.0.0"
API 模型: Kotlin 类
我们需要一些类来转换我们的 json 相应到Kotlin 类中.如果使用 Java 我们需要创建一个很大的类文件,但是我们将使用 Kotlin, 我们可以取得优势,使类非常简单.简单到在这里我可以粘贴出这个类的所有代码.
class RedditNewsResponse(val data: RedditDataResponse)
class RedditDataResponse(
val children: List<RedditChildrenResponse>,
val after: String?,
val before: String?
)
class RedditChildrenResponse(val data: RedditNewsDataResponse)
class RedditNewsDataResponse(
val author: String,
val title: String,
val num_comments: Int,
val created: Long,
val thumbnail: String,
val url: String
)
API 接口
我创建了一个 Kotlin 文件 RedditApi, 它看起来像这样:
interface RedditApi {
@GET("/top.json")
fun getTop(@Query("after") after: String, @Query("limit") limit: String)
: Call<RedditNewsResponse>
}
我们在这里定义个一个同步的 API 请求,它接受一个” after”和” limit”查询字符串.返回类型是” Call “, 这个 Call 允许我们执行请求,也可以知道这个请求是否成功,也将响应的数据转换成指定的类型.
Rest API
现在我们将在一个新的” RestApi.kt”文件中初始化 Retrofit.在 Kotlin 中我们使用 init 关键字初始化代码.
class RestApi {
private val redditApi: RedditApi
init {
val retrofit = Retrofit.Builder()
.baseUrl("https://www.reddit.com")
.addConverterFactory(MoshiConverterFactory.create())
.build()
redditApi = retrofit.create(RedditApi::class.java)
}
}
- init代码块: Kotlin 类的初始化代码块
- “.addConverterFactory(MoshiConverterFactory.create())”设置 Moshi 转换
- “RedditApi::class.java”这个语法运行你得到与 Java Class 实例相似的 KClass实例
getNews
我们也提供一个函数来消费新闻API
fun getNews(after: String, limit: String): Call<RedditNewsResponse>{
return redditApi.getTop(after, limit)
}
重要:
确认添加这个权限到AndroidManifes 文件
<uses-permission android:name="android.permission.INTERNET" />
NewsManager:调用这个 Api!!
我们使用默认参数来初始化我们的 RestApi:
class NewsManager(private val api: RestAPI = RestAPI()) {
...
}
更新我们的 Observable 来调用这个 Api 执行请求:
subscriber ->
val callResponse = api.getNews("", limit)
val response = callResponse.execute()
if (response.isSuccessful) {
val news = response.body().data.children.map {
val item = it.data
RedditNewsItem(item.author, item.title, item.num_comments,
item.created, item.thumbnail, item.url)
}
subscriber.onNext(news)
subscriber.onCompleted()
} else {
subscriber.onError(Throwable(response.message()))
}
- callResponse.execute():这个将执行一个同步请求
- resoinse.body().data.children.map{…}:这里我们使用的 List 函数” map” 将每一个子类转换成一个 RedditNewsItem
- it.data:it 是一个小的方法来访问 lambda 中单个参数.这个只有当你只有一个参数时有效.如果有多个参数你需要使用这种方式“x, y -> …”.
- subscriber.onError():我们创建了一个新的 Throwable 对象来接受服务端的错误消息.
Commit
我们的 app 现在从Reddit 获取10个新闻
总结
很好,现在我们越来越接近最终的 APP. Retrofit 是一个非常强大的扩展,可以肯定的是我们只使用了它的一部分功能.
在下一个部分我们将添加无限滑动从 Reddit得到更多的新闻.



