Endpoint

我们用到的 API endpoint 只有一个,就是用来取得港铁机场快綫、东涌綫、屯马綫及将军澳綫最多四班即将到站列车的抵达时间。车站清单我们会直接写死在 app 里面。API 的使用方法可以在资料一线通网站(香港政府 open data 的网站)内找到。这个 API 是不需要额外申请 API key,只是一个普通的 HTTP GET request,然後 response body 是一个 JSON object。

打开「数据字典」PDF 档,可以找到各车站及行车綫的代码和 response body JSON object 的说明。当中我们主要用到的 property 大致上是:

  • plat 月台编号
  • time 时间(留意它的格式并非按照 ISO 8601
  • dest 目的地车站代码
  • seq 次序(我们要按照这个顺序显示班次)

再看「港铁实时列车服务资讯 API 规范文件」PDF 档,它提供了几个 HTTP response status code 的意义和一些 response body 例子。例如当事故发生时那个 API 会提供一段文字让我们显示。

Response data class

一般而言,我们都不会直接用 Android SDK 入面的 org.json 套件(即是 JSONObject 那些 class)来将 API response 的 JSON 转成 Java/Kotlin object。因为要为每个 property 逐个写 code,费时失事,所以我们都会用其他 deserialization library 去做 JSON 和 Java/Kotlin object 转换。

在使用那些 library 之前,我们要准备 API response JSON 对应的 Kotlin data class。那个 data class 基本上就是要跟 JSON object 的结构相同,即是 response 的那个 property 是 string 就要在 data class 开对应的 string property。另外,我们只对整个 response 入面的某几个 property 感兴趣,所以在准备 data class 只针对那几个 property 而造,其余的东西我们就略过。

下面就是完成後的 data class,最尾的 companion object 放了几个 constant 方便之後处理。

data class EtaResponse(
    /**
     * system status code.
     */
    val status: Int = STATUS_ERROR_OR_ALERT,
    /**
     * Alert message.
     */
    val message: String = "",
    /**
     * URL for Special Train Services Arrangement case.
     */
    val url: String = "",
    /**
     * Indicate if the train is delayed.
     */
    val isDelay: String = IS_DELAY_FALSE,
    val data: Map<String, Data> = emptyMap()
) {
    data class Data(
        /**
         * Indicate the destinations of the train in the specific line (up trip).
         */
        val up: List<Eta> = emptyList(),
        /**
         * Indicate the destinations of the train in the specific line (down trip).
         */
        val down: List<Eta> = emptyList()
    )

    data class Eta(
        /**
         * Platform numbers for the departure / arrival train.
         */
        val plat: String = "1",
        /**
         * Estimated arrival time (or departure time) of the train.
         */
        val time: String = EMPTY_TIMESTAMP,
        /**
         * MTR Station Code in capital letters.
         */
        val dest: String = "",
        /**
         * The sequence of the 4 upcoming trains.
         */
        val seq: String = "0"
    )

    companion object {
        const val EMPTY_TIMESTAMP = "-"

        const val STATUS_NORMAL = 1
        const val STATUS_ERROR_OR_ALERT = 0
        const val IS_DELAY_TRUE = "Y"
        const val IS_DELAY_FALSE = "N"
    }
}

小结

我们已经准备好 response 的 data class。下一篇我们会介绍不同的 JSON deserialization library 并且将 EtaResponse 加上 deserialization library 的 annotation。


<<:  Day 3: 人工智慧在音乐领域的应用 (各层面的应用二)

>>:  03. Unit Test x PHPUnit x FizzBuzz

Day10 Android - Toast快显元件

今天讲的内容属於简单的元件使用,而我在前面几天已经先有拿来用几次来观察结果,但我一直没有好好提到,今...

[11] 建立进入页面和流程控制

这边你需要自己制作一个流程控制 不了解的话建可以画个图来确认现在在哪个流程 基本上都会回到主要操控介...

Ruby on Rails 继承(Inheritance)与开放类别

到目前为止的范例都是只有单一类别,但在真实的世界里其实是更复杂的,像是如果想要再加入一个小狗类别: ...

[Day17] 团队管理:Check-in & Check-out

Check-in Check-in让成员有不同面向了解彼此的机会 文化的塑造与累积是每一天都在进行的...

Day29:歪楼无极限(全英文笔记 - III)

虽然今天已经是最後一天,但如果明天系统仍然可以发文的话,会先继续发文,方便之後回顾整理系列文时,能够...