Android Kotlin 基础知识:8.1 从互联网获取数据

1. 欢迎

此 Codelab 是“Android Kotlin 基础知识”课程的一部分。如果您按顺序学习这些 Codelab,您将会充分发掘此课程的价值。“Android Kotlin 基础知识”Codelab 着陆页列出了所有课程 Codelab。

简介

您构建的几乎所有 Android 应用都需要在某个时候连接到互联网。在本 Codelab 以及后续 Codelab 中,您将构建一款应用,该应用会连接到网络服务,以检索和显示数据。此外,您还会用到在之前有关 ViewModelLiveDataRecyclerView 的 Codelab 中学到的内容。

在此 Codelab 中,您将使用社区开发的库构建网络层。这可以极大地简化数据和图片提取流程,还有助于应用遵循 Android 最佳实践,例如在后台线程上加载图片以及缓存已加载的图片。对于代码中的异步或非阻塞部分,例如与网络服务层通信,您将修改该应用以使用 Kotlin 的协程。如果互联网速度较慢或不可用,应用的界面也会更新;这样一来,用户即可及时获知因网络连接出现的任何应用问题。

您应当已掌握的内容

  • 如何创建和使用 fragment。
  • 如何在 fragment 之间导航,以及如何使用 safeArgs 在 fragment 之间传递数据。
  • 如何使用架构组件,包括 ViewModelViewModelProvider.FactoryLiveDataLiveData 转换。
  • 如何使用协程管理长时间运行的任务。

学习内容

  • 什么是 REST 网络服务。
  • 使用 Retrofit 库连接到互联网上的 REST 网络服务,并获取响应。
  • 使用 Moshi 库将 JSON 响应解析为数据对象。

您应执行的操作

  • 修改起始应用以发出网络服务 API 请求,并处理响应。
  • 使用 Retrofit 库为您的应用实现网络层。
  • 使用 Moshi 库将网络服务的 JSON 响应解析为应用的实时数据。
  • 使用 Retrofit 对协程的支持来简化代码。

2. 应用概览

在此 Codelab(和接下来的 Codelab)中,您将使用一款名为 MarsRealEstate 的初始应用,该应用会显示火星上的待售资源。此应用需要连接到网络服务才能检索和显示资源数据,包括价格以及资源是可出售还是可租赁等详细信息。代表各项资源的图片是由 NASA 的火星探测器拍摄的真实照片。

b31d2df6e0f5e858.png

您在此 Codelab 中构建的应用版本不会有很多视觉上的亮点;它侧重于应用的网络层部分,旨在连接到互联网并使用网络服务下载原始资源数据。为了确保正确检索和解析数据,只需在文本视图中输出火星上的资源数:

613d3568c44757d7.png

.

3.任务:探索 MarsRealEstate 初始应用

MarsRealEstate 应用的架构包含两大模块:

  • 概览 fragment,其中包含使用 RecyclerView 构建的缩略图资源图片网格。
  • 详情视图 fragment,其中包含每项资源的相关信息。

c5333bd8ad9bc1d5.png

对于每个 fragment,该应用都有一个 ViewModel。在此 Codelab 中,您将为网络服务创建一个层,ViewModel 将直接与该网络层进行通信。这类似于您在之前的 Codelab 中在 ViewModelRoom 数据库通信时执行的操作。

overview ViewModel 负责发出网络调用以获取火星地产信息。details ViewModel 用于保存在详情 fragment 中显示的单个火星地产资源的详细信息。对于每个 ViewModel,您会结合使用 LiveData 和生命周期感知型数据绑定,以在数据发生更改时更新应用界面。

您使用 Navigation 组件在两个 fragment 之间导航,并将选定属性作为参数传递。

在此任务中,您将下载并运行 MarsRealEstate 起始应用,并熟悉该项目的结构。

第 1 步:探索 fragment 和导航

  1. 下载 MarsRealEstate 起始应用,并在 Android Studio 中打开它。
  2. 检查 app/java/MainActivity.kt。该应用对两个屏幕都使用 fragment,因此 activity 的唯一任务就是加载 activity 的布局。
  3. 检查 app/res/layout/activity_main.xml。activity 布局是 nav_graph.xml 导航文件中定义的两个 fragment 的宿主。此布局会使用 nav_graph 资源实例化 NavHostFragment 及其关联的导航控制器。
  4. 打开 app/res/navigation/nav_graph.xml。在这里,您可以看到这两个 fragment 之间的导航关系。导航图 StartDestination 指向 overviewFragment。这意味着,应用启动时概览 fragment 会实例化。

第 2 步:探索 Kotlin 源文件和数据绑定

  1. Project 窗格中,展开 app > java。请注意,MarsRealEstate 应用有三个软件包文件夹:detailnetworkoverview。这些文件夹对应于应用的三大组件:概览 fragment 和详情 fragment,以及网络层代码。b0afdfe05eee4fd3.png
  2. 打开 app/java/overview/OverviewFragment.ktOverviewFragment 会延迟初始化 OverviewViewModel,也就是说,OverviewViewModel 会在第一次使用时创建。
  3. 检查 onCreateView() 方法。此方法使用数据绑定膨胀 fragment_overview 布局,将绑定生命周期所有者设置为自身 (this),并为其设置 binding 对象中的 viewModel 变量。由于我们设置了生命周期所有者,因此系统会自动观察数据绑定中使用的任何 LiveData 是否有任何更改,并相应地更新界面。
  4. 打开 app/java/overview/OverviewViewModel。由于响应为 LiveData,并且我们已为绑定变量设置了生命周期,因此对其所做的任何更改都将更新应用界面。
  5. 检查 init 代码块。在创建 ViewModel 后,它会调用 getMarsRealEstateProperties() 方法。
  6. 检查 getMarsRealEstateProperties() 方法。在此起始应用中,此方法包含占位符响应。此 Codelab 的目标是使用您从互联网获得的真实数据更新 ViewModel 中的 LiveData
  7. 打开 app/res/layout/fragment_overview.xml。这是您在此 Codelab 中使用的概览 fragment 的布局,它包含视图模型的数据绑定。它会导入 OverviewViewModel,然后将 ViewModel 的响应绑定到 TextView。在后续的 Codelab 中,您需要在 RecyclerView 中将文本视图替换为图片网格。
  8. 编译并运行应用。您在此应用的当前版本中只会看到初始响应:“Set the Mars API Response here!”

6422831b7bebd55.png

4.任务:使用 Retrofit 连接到网络服务

火星房地产数据存储在网络服务器上,可通过 REST 网络服务进行访问。基于 REST 架构的网络服务使用网络组件和协议构建而成。

您可通过 URI 以标准化方式向网络服务发出请求。

例如,在本节课的应用中,您将使用以下服务器 URI 检索所有数据:

https://android-kotlin-fun-mars-server.appspot.com

如果在浏览器中输入以下网址,您将看到火星上所有可用的地产资源列表!

https://android-kotlin-fun-mars-server.appspot.com/realestate

网络服务的响应通常会采用 JSON 格式,这是一种表示结构化数据的交换格式。您将在下一项任务中详细了解 JSON,但简而言之,JSON 对象是键值对集合,有时称为字典、哈希映射或关联数组。JSON 对象集合是一个 JSON 数组,它是作为网络服务的响应返回的数组。

如需将这些 JSON 数据传输到您的应用中,应用需要建立网络连接并与相应服务器通信,然后接收 JSON 响应数据并将其解析为应用可以使用的格式。在此 Codelab 中,您将使用名为 Retrofit 的 REST 客户端库建立此连接。

第 1 步:将 Retrofit 依赖项添加到 Gradle

  1. 打开 build.gradle (Module: app)
  2. dependencies 部分中,为 Retrofit 库添加以下代码行:
implementation "com.squareup.retrofit2:retrofit:$version_retrofit"
implementation "com.squareup.retrofit2:converter-scalars:$version_retrofit"

请注意,版本号是在项目 Gradle 文件中单独定义的。第一个依赖项用于 Retrofit 2 库本身,而第二个依赖项则用于 Retrofit 标量转换器。此转换器允许 Retrofit 将 JSON 结果作为 String 返回。这两个库协同工作。

  1. 点击 Sync Now,以使用新的依赖项重建项目。

第 2 步:添加对 Java 8 语言功能的支持

许多第三方库(包括 Retrofit2)都会使用 Java 8 语言功能。Android Gradle 插件提供对使用某些 Java 8 语言功能的内置支持。如需使用这些内置功能,请更新模块的 build.gradle 文件,如下所示:

android {
  ...

  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }

  kotlinOptions {
    jvmTarget = JavaVersion.VERSION_1_8.toString()
  }
}

点击 Sync Now,重建项目以使用这些新功能。

第 3 步:实现 MarsApiService

Retrofit 会根据网络服务的内容为应用创建网络 API。它从网络服务提取数据,并通过独立的转换器库来路由数据。该库知道如何解码数据,并以实用对象的形式返回这些数据。Retrofit 内置对 XML 和 JSON 等常用网络数据格式的支持。Retrofit 最终会为您创建大部分网络层,包括关键详细信息,例如在后台线程上运行请求。

MarsApiService 类用于保存应用的网络层;也就是说,您的 ViewModel 将使用相应 API 与网络服务通信。您将在该类中实现 Retrofit 服务 API。

  1. 打开 app/java/network/MarsApiService.kt。现在,该文件仅包含一项内容:网络服务的基准网址的一个常量。
private const val BASE_URL =
   "https://android-kotlin-fun-mars-server.appspot.com"
  1. 在该常量的正下方,使用 Retrofit 构建器创建一个 Retrofit 对象。在收到请求时,导入 retrofit2.Retrofitretrofit2.converter.scalars.ScalarsConverterFactory
private val retrofit = Retrofit.Builder()
   .addConverterFactory(ScalarsConverterFactory.create())
   .baseUrl(BASE_URL)
   .build()

Retrofit 至少需要以下两项内容才能构建网络服务 API:网络服务的基础 URI 和转换器工厂。转换器会告知 Retrofit 如何处理它从网络服务获取的数据。在这种情况下,您希望 Retrofit 从网络服务获取 JSON 响应,并将该响应作为 String 返回。Retrofit 包含一个 ScalarsConverter,它支持字符串和其他基元类型,因此,您可以使用 ScalarsConverterFactory 的实例对构建器调用 addConverterFactory()。最后,调用 build() 以创建 Retrofit 对象。

  1. 在对 Retrofit 构建器的调用的正下方,定义一个接口,该接口定义 Retrofit 如何使用 HTTP 请求与网络服务器通信。在收到请求时,导入 retrofit2.http.GETretrofit2.Call
interface MarsApiService {
    @GET("realestate")
    fun getProperties():
            Call<String>
}

现在的目标是从网络服务获取 JSON 响应字符串,而您只需要一种方法即可:getProperties()。如需告知 Retrofit 此方法应执行的操作,请使用 @GET 注解,并为该网络服务方法指定路径或端点。在本示例中,端点称为 realestate。调用 getProperties() 方法时,Retrofit 会将端点 realestate 附加到基准网址(由您在 Retrofit 构建器中定义),并创建一个 Call 对象。这个 Call 对象用于启动该请求。

  1. MarsApiService 接口下,定义一个名为 MarsApi 的公共对象,以初始化 Retrofit 服务。这是创建服务对象时使用的一种标准 Kotlin 代码模式。
object MarsApi {
    val retrofitService : MarsApiService by lazy {
       retrofit.create(MarsApiService::class.java) }
}

Retrofit create() 方法会通过 MarsApiService 接口本身创建 Retrofit 服务。由于此调用的计算开销很大,您可以延迟初始化 Retrofit 服务。由于该应用只需要一个 Retrofit 服务实例,因此您可以使用名为 MarsApi 的公共对象向应用的其余部分公开该服务。现在,所有设置均已完成,每次您的应用调用 MarsApi.retrofitService 时,它都会获得一个实现 MarsApiService 的单例 Retrofit 对象。

第 4 步:在 OverviewViewModel 中调用网络服务

  1. 打开 app/java/overview/OverviewViewModel.kt。向下滚动到 getMarsRealEstateProperties() 方法。
private fun getMarsRealEstateProperties() {
   _response.value = "Set the Mars API Response here!"
}

这将在该方法中调用 Retrofit 服务并处理返回的 JSON 字符串。目前,该响应中只有一个占位符字符串。

  1. 删除用于将响应设置为“Set the Mars API Response here!”的占位符行
  2. getMarsRealEstateProperties() 中,添加如下所示的代码。在收到请求时,导入 retrofit2.Callbackcom.example.android.marsrealestate.network.MarsApi

MarsApi.retrofitService.getProperties() 方法会返回一个 Call 对象。然后,您可以对该对象调用 enqueue(),以在后台线程上启动网络请求。

MarsApi.retrofitService.getProperties().enqueue(
   object: Callback<String> {
})
  1. 点击 object 一词(带有红色下划线)。依次选择 Code > Implement methods。从列表中选择 onResponse()onFailure()
    5515afc051c01d40.png

Android Studio 在每种方法中都添加了带有 TODO 的代码:

override fun onFailure(call: Call<String>, t: Throwable) {
       TODO("not implemented")
}

override fun onResponse(call: Call<String>,
   response: Response<String>) {
       TODO("not implemented")
}
  1. onFailure() 中,删除 TODO,并将 _response 设置为失败消息,如下所示。_response 是一个 LiveData 字符串,用于确定文本视图中显示的内容。每种状态都需要更新 _response LiveData

当网络服务响应失败时,系统会调用 onFailure() 回调。对于此响应,请将 _response 状态设置为 "Failure: ",并与 Throwable 参数中的消息串联起来。

override fun onFailure(call: Call<String>, t: Throwable) {
   _response.value = "Failure: " + t.message
}
  1. onResponse() 中,删除 TODO,并将 _response 设置为响应正文。当请求成功且网络服务返回响应时,系统会调用 onResponse() 回调。
override fun onResponse(call: Call<String>,
   response: Response<String>) {
      _response.value = response.body()
}

第 5 步:定义互联网权限

  1. 编译并运行 MarsRealEstate 应用。请注意,该应用会立即关闭并报错:

9c0cbe9dfe9a540d.png

  1. 点击 Android Studio 中的 Logcat 标签页,并记下日志中以如下所示的代码行开头的错误消息:
Process: com.example.android.marsrealestate, PID: 10646
java.lang.SecurityException: Permission denied (missing INTERNET permission?)

此错误消息表示应用可能缺少 INTERNET 权限。连接到互联网会引起安全问题,因此我们默认应用没有连接互联网。您需要明确告知 Android:该应用需要访问互联网。

  1. 打开 app/manifests/AndroidManifest.xml。将这行代码添加到 <application> 标签的前面:
<uses-permission android:name="android.permission.INTERNET" />
  1. 编译并再次运行应用。如果互联网连接一切正常,您就能看到包含火星资源数据的 JSON 文本。bc6c69295bbd1514.png
  2. 点按设备或模拟器中的返回按钮关闭应用。
  3. 将设备或模拟器设为飞行模式,然后从“最近”菜单中重新打开该应用,或从 Android Studio 中重启该应用。

b298e72b27ef0cf7.png

  1. 再次关闭飞行模式。

5. 任务:使用 Moshi 解析 JSON 响应

现在,您将从 Mars 网络服务获得 JSON 响应,这是一个不错的开始。但您实际上需要的是 Kotlin 对象,而不是大型 JSON 字符串。有一个名为 Moshi 的库,它是一个 Android JSON 解析器,可将 JSON 字符串转换为 Kotlin 对象。Retrofit 库具有可与 Moshi 配合使用的转换器,在这方面非常适用。

在此任务中,您将配合使用 Moshi 库和 Retrofit,将网络服务的 JSON 响应解析成有用的火星资源 Kotlin 对象。您需要更改应用,而不是显示原始 JSON,而该应用会显示返回的火星资源数。

第 1 步:添加 Moshi 库依赖项

  1. 打开 build.gradle (Module: app)
  2. 在依赖项部分中,添加如下所示的代码以包含 Moshi 依赖项。与 Retrofit 一样,$version_moshi 是在项目级 Gradle 文件中单独定义的。此依赖项添加了对包含 Kotlin 支持的 Moshi JSON 库的支持。
implementation "com.squareup.moshi:moshi-kotlin:$version_moshi"
  1. dependencies 代码块中,找到 Retrofit 标量转换器所在的代码行:
implementation "com.squareup.retrofit2:retrofit:$version_retrofit"
implementation "com.squareup.retrofit2:converter-scalars:$version_retrofit"
  1. 将以下行更改为使用 converter-moshi
implementation "com.squareup.retrofit2:converter-moshi:$version_retrofit"
  1. 点击 Sync Now,以使用新的依赖项重建项目。

第 2 步:实现 MarsProperty 数据类

您从网络服务中获取的 JSON 响应的示例条目类似于如下所示:

[{"price":450000,
"id":"424906",
"type":"rent",
"img_src":"http://mars.jpl.nasa.gov/msl-raw-images/msss/01000/mcam/1000ML0044631300305227E03_DXXX.jpg"},
...]

上面显示的 JSON 响应是一个数组(以英文方括号表示)。该数组包含 JSON 对象,这些对象括在英文花括号中。每个对象都包含一组名称值对,用英文冒号分隔。名称会用英文引号引起来。值可以是数字、字符串和布尔值,以及其他对象或数组。如果值是字符串,则它还会用英文引号引起来。例如,此资源的 price 为 $450,000,而 img_src 是一个网址,即图片文件在服务器上的位置。

在上面的示例中,请注意每项火星资源条目具有以下 JSON 键和值对:

  • price:火星资源的价格,用数字表示。
  • id:资源的 ID,用字符串表示。
  • type"rent""buy"
  • img_src:图片的网址,用字符串表示。

Moshi 会解析此 JSON 数据并将其转换为 Kotlin 对象。为此,它需要一个 Kotlin 数据类来存储解析后的结果,因此下一步是创建该类。

  1. 打开 app/java/network/MarsProperty.kt
  2. 将现有的 MarsProperty 类定义替换为以下代码:
data class MarsProperty(
   val id: String, val img_src: String,
   val type: String,
   val price: Double
)

请注意,MarsProperty 类中的每个变量都对应于 JSON 对象中的一个键名。为了匹配特定 JSON 响应中的类型,您可以为除 price(为 Double)以外的所有值使用 String 对象。请注意,Double 可用于表示任何 JSON 数值。

Moshi 解析 JSON 时,它会按名称匹配键,并用适当的值填充数据对象。

  1. img_src 键所在的代码行替换为如下所示的代码行。在收到请求时,导入 com.squareup.moshi.Json
@Json(name = "img_src") val imgSrcUrl: String,

有时,JSON 响应中的键名可能会使 Kotlin 属性混淆,或者可能与您的编码样式不匹配。例如,在 JSON 文件中,img_src 键使用下划线,而 Kotlin 属性通常使用大写和小写字母(“驼峰式大小写”)。

如需在数据类中使用与 JSON 响应中的键名不同的变量名称,请使用 @Json 注解。在此示例中,数据类中变量的名称为 imgSrcUrl。可以使用 @Json(name = "img_src") 将该变量映射到 JSON 属性 img_src

第 3 步:更新 MarsApiService 和 OverviewViewModel

添加 MarsProperty 数据类后,您现在可以更新网络 API 和 ViewModel,以包含 Moshi 数据。

  1. 打开 network/MarsApiService.kt。您可能会看到 ScalarsConverterFactory 出现类缺失错误。这是因为您在第 1 步中更改了 Retrofit 依赖项。您很快便可以修复这些错误。
  2. 在文件顶部,在 Retrofit 构建器的前面添加以下代码以创建 Moshi 实例。在收到请求时,导入 com.squareup.moshi.Moshicom.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
private val moshi = Moshi.Builder()
   .add(KotlinJsonAdapterFactory())
   .build()

与处理 Retrofit 的操作类似,在这里,您需要使用 Moshi 构建器创建一个 moshi 对象。为了让 Moshi 注解能够在 Kotlin 中正常使用,请添加 KotlinJsonAdapterFactory,然后调用 build()

  1. 将 Retrofit 构建器更改为使用 MoshiConverterFactory 而不是 ScalarConverterFactory,并传入您刚刚创建的 moshi 实例。在收到请求时,导入 retrofit2.converter.moshi.MoshiConverterFactory
private val retrofit = Retrofit.Builder()
   .addConverterFactory(MoshiConverterFactory.create(moshi))
   .baseUrl(BASE_URL)
   .build()
  1. 同时删除 ScalarConverterFactory 的导入作业。

要删除的代码:

import retrofit2.converter.scalars.ScalarsConverterFactory
  1. 更新 MarsApiService 界面,让 Retrofit 返回 MarsProperty 对象列表,而不是返回 Call<String>
interface MarsApiService {
   @GET("realestate")
   fun getProperties():
      Call<List<MarsProperty>>
}
  1. 打开 OverviewViewModel.kt。在 getMarsRealEstateProperties() 方法中,向下滚动到对 getProperties().enqueue() 的调用。
  2. enqueue() 的参数从 Callback<String> 更改为 Callback<List<MarsProperty>>。在收到请求时,导入 com.example.android.marsrealestate.network.MarsProperty
MarsApi.retrofitService.getProperties().enqueue(
   object: Callback<List<MarsProperty>> {
  1. onFailure() 中,将参数从 Call<String> 更改为 Call<List<MarsProperty>>
override fun onFailure(call: Call<List<MarsProperty>>, t: Throwable) {
  1. onResponse() 的两个参数进行同样的更改:
override fun onResponse(call: Call<List<MarsProperty>>,
   response: Response<List<MarsProperty>>) {
  1. onResponse() 的正文中,将现有的对 _response.value 的赋值替换为如下所示的赋值。由于 response.body() 现在是一个 MarsProperty 对象列表,因此该列表的大小就是已解析的资源数。此响应消息会输出相应资源数:
_response.value =
   "Success: ${response.body()?.size} Mars properties retrieved"
  1. 确保飞行模式已关闭。编译并运行应用。这一次,消息应显示网络服务返回的资源数:613d3568c44757d7.png

6. 任务:将协程与 Retrofit 一起使用

现在,Retrofit API 服务正在运行,但它所用的回调带有的两个回调方法必须由您实现。一种方法用于处理成功情况,另一方法用于处理失败情况,失败结果会报告异常。如果将协程与异常处理机制搭配使用(而不是使用回调),您的代码将变得更高效、更易读。在此任务中,您将转换网络服务和 ViewModel,以使用协程。

第 1 步:更新 MarsApiService 和 OverviewViewModel

  1. MarsApiService 中,将 getProperties() 设置为挂起函数。将 Call<List<MarsProperty>> 更改为 List<MarsProperty>getProperties() 方法如下所示:
@GET("realestate")
suspend fun getProperties(): List<MarsProperty>
  1. OverviewViewModel.kt 文件中,删除 getMarsRealEstateProperties() 内的所有代码。在这里,您将使用协程,而不是调用 enqueue() 以及 onFailure()onResponse() 回调。
  2. getMarsRealEstateProperties() 中,使用 viewModelScope. 启动协程
viewModelScope.launch {

}

ViewModelScope 是为应用中的每个 ViewModel 定义的内置协程作用域。在此作用域内启动的协程会在 ViewModel 被清除时自动取消。

  1. 在启动代码块内,添加一个 try/catch 代码块来处理异常:
try {

} catch (e: Exception) {

}
  1. try {} 代码块内,对 retrofitService 对象调用 getProperties()
val listResult = MarsApi.retrofitService.getProperties()

MarsApi 服务调用 getProperties() 会对后台线程创建和启动网络调用。

  1. 同样,在 try {} 代码块内,更新成功响应的响应消息:
_response.value =
   "Success: ${listResult.size} Mars properties retrieved"
  1. catch {} 代码块内,处理故障响应:
_response.value = "Failure: ${e.message}"

完整的 getMarsRealEstateProperties() 方法现在应如下所示

private fun getMarsRealEstateProperties() {
   viewModelScope.launch {
       try {
           val listResult = MarsApi.retrofitService.getProperties()
           _response.value = "Success: ${listResult.size} Mars properties retrieved"
       } catch (e: Exception) {
           _response.value = "Failure: ${e.message}"
       }
   }
}
  1. 编译并运行应用。这次的结果与上一个任务(报告资源数)相同,但代码和错误处理机制更为简单。

7. 解决方案代码

Android Studio 项目:MarsRealEstateNetwork

8. 总结

REST 网络服务

  • 网络服务是通过互联网提供的基于软件的功能,可让您的应用发出请求并获取返回的数据。
  • 常见网络服务使用的是 REST 架构。提供 REST 架构的网络服务称为 RESTful 服务。RESTful 网络服务是使用标准网络组件和协议构建的。
  • 您可通过 URI 以标准化方式向 REST 网络服务发出请求。
  • 要使用网络服务,应用必须建立网络连接,然后与该服务进行通信。然后,应用必须接收响应数据,并将该数据解析成应用可以使用的格式。
  • Retrofit 库是一个客户端库,可让应用向 REST 网络服务发出请求。
  • 使用转换器指示 Retrofit 如何处理它发送至网络服务的数据,以及它从网络服务获取的返回数据。例如,ScalarsConverter 转换器会将网络服务数据视为 String 或其他基元。
  • 如需让应用能够连接到互联网,请在 Android 清单中添加 "android.permission.INTERNET" 权限。

JSON 解析

  • 网络服务的响应通常会采用 JSON 格式,这是一种表示结构化数据的常用交换格式。
  • JSON 对象是键值对的集合。此集合有时称为字典、哈希映射或关联数组。
  • JSON 对象集合是一个 JSON 数组。作为网络服务的响应,您会得到一个 JSON 数组。
  • 键值对中的键会用英文引号引起来。值可以是数字或字符串。字符串也会用英文引号引起来。
  • Moshi 库是一种 Android JSON 解析器,可将 JSON 字符串转换为 Kotlin 对象。Retrofit 包含一个可配合 Moshi 使用的转换器。
  • Moshi 可将 JSON 响应中的键与具有相同名称的数据对象中的属性进行匹配。
  • 如需为键使用不同的属性名称,请使用 @Json 注解和 JSON 键名为该属性添加注解。

9. 了解详情

Udacity 课程:

Android 开发者文档:

Kotlin 文档:

其他:

10. 家庭作业

此部分列出了在由讲师主导的课程中,学生学习此 Codelab 后可能需要完成的家庭作业。讲师自行决定是否执行以下操作:

  • 根据需要布置作业。
  • 告知学生如何提交家庭作业。
  • 给家庭作业评分。

讲师可以酌情采纳这些建议,并且可以自由布置自己认为合适的任何其他家庭作业。

如果您是在自学此 Codelab,可随时通过这些家庭作业来检测您的知识掌握情况。

回答以下问题

问题 1

Retrofit 构建网络服务 API 需要具备哪两大关键工具?

▢ 网络服务的基础 URI 以及 GET 查询。

▢ 网络服务的基础 URI 以及转换器工厂。

▢ 与网络服务的网络连接和授权令牌。

▢ 转换器工厂和响应解析器。

问题 2

Moshi 库的用途是什么?

▢ 获取网络服务返回的数据。

▢ 与 Retrofit 交互以发出网络服务请求。

▢ 将网络服务的 JSON 响应解析为 Kotlin 数据对象。

▢ 重命名 Kotlin 对象以匹配 JSON 响应中的键。

11. 下一个 Codelab

开始学习下一课:

如需本课程中其他 Codelab 的链接,请查看“Android Kotlin 基础知识”Codelab 着陆页