More Related Content Similar to 炎炎夏日學 Android 課程 - Part3: Android app 實作 (20) More from Johnny Sung (20) 炎炎夏日學 Android 課程 - Part3: Android app 實作2. Mobile device developer
Johnny Sung
https://fb.com/j796160836
https://blog.jks.coffee/
https://www.slideshare.net/j796160836
https://github.com/j796160836
14. 所需⼯工具
• Method Draw 線上編輯圖片⼯工具
https://editor.method.ac/
• App Icon Generator 線上 App icon 產⽣生⼯工具
https://appicon.co/
• JSON Editor Online 線上 JSON 編輯⼯工具
https://jsoneditoronline.org/
26. dependencies {
// ...
implementation 'org.immutables:gson:2.7.1'
implementation 'com.squareup.okhttp3:okhttp:3.12.0'
implementation "org.jdeferred.v2:jdeferred-core:2.0.0-beta1"
implementation "org.jdeferred.v2:jdeferred-android:2.0.0-beta1"
// ...
}
加入套件參參考
31. class SunsetResponse {
var results: SunsetResult? = null
var status: String? = null
}
class SunsetResult {
var sunset: String? = null
}
33. class ExampleUnitTest {
@Test
fun addition_isCorrect() {
// Arrange
val expected = 4
// Act
val actual = 2 + 2
// Assert
assertEquals(expected, actual)
}
}
Arrange 準備
Act 執⾏行行
Aessrt 驗證
34. object SunsetDateUtil {
val dateFormater = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX", Locale.US)
.apply {
timeZone = TimeZone.getTimeZone("UTC")
}
}
35. Arrange 準備
Act 執⾏行行
Aessrt 驗證
@Test
fun testJSON() {
// Arrange
val json =
"{"results":{"sunrise":"2019-06-28T21:17:03+00:00","sunset":"2019-06-29T10:47:28+00:00","solar_noon":
"2019-06-29T04:02:16+00:00","day_length":48625,"civil_twilight_begin":"2019-06-28T20:52:00+00:00","civil_twilight_end":
"2019-06-29T11:12:31+00:00","nautical_twilight_begin":"2019-06-28T20:22:00+00:00","nautical_twilight_end":
"2019-06-29T11:42:31+00:00","astronomical_twilight_begin":"2019-06-28T19:50:46+00:00","astronomical_twilight_end":
"2019-06-29T12:13:46+00:00"},"status":"OK"}"
val excepted = "2019-06-29T10:47:28+00:00"
// Act
val gson = Gson()
val obj = gson.fromJson(json, SunsetResponse::class.java)
// Assert
Assert.assertEquals(excepted, obj.results?.sunset)
}
}
36. Arrange 準備
Act 執⾏行行
Aessrt 驗證
輸入的資料
期待成功的資料
class SunsetUnitTest {
@Test
fun testFormatter() {
val sunsetTime = "2019-06-24T10:46:49+00:00"
val expected = Date(1561373209000)
val result = SunsetDateUtil.dateFormater.parse(sunsetTime)
assertEquals(expected.time, result.time)
}
}
37. class NetworkManager {
companion object {
val instance: NetworkManager by lazy {
NetworkManager()
}
}
val mainHandler = Handler(Looper.getMainLooper())
inline fun <reified T> requestAsync(request: Request, typeToken: Type): Promise<T, Exception, Double> {
val okHttpClient = OkHttpClient()
val gson = GsonBuilder().create()
val deferred = DeferredObject<T, Exception, Double>()
okHttpClient.newCall(request).promise().then { okhttpResponse ->
val strResult = okhttpResponse.body()?.string()
try {
val result = gson.fromJson<T>(strResult, typeToken)
if (okhttpResponse.isSuccessful) {
mainHandler.post {
deferred.resolve(result)
}
} else {
mainHandler.post {
deferred.reject(Exception(strResult))
}
}
} catch (e: Exception) {
mainHandler.post {
deferred.reject(e)
}
}
}.fail {
deferred.reject(it)
}
return deferred.promise()
}
}
fun Call.promise(): Promise<Response, Exception, Double> {
val deferred = DeferredObject<Response, Exception, Double>()
this.enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
deferred.resolve(response)
}
override fun onFailure(call: Call, e: IOException) {
deferred.reject(e)
}
})
return deferred.promise()
}
補檔案 NetworkManager.kt
40. object NetworkAPI {
fun getSunsetDataAsync(): Promise<SunsetResponse, Exception, Double> {
val okhttpRequest = Request.Builder()
.url("https://api.sunrise-sunset.org/json?lat=22.604098&lng=120.3001811&date=today&formatted=0")
.method("GET", null)
.build()
val type = object : TypeToken<SunsetResponse>() {}.type
return NetworkManager.instance.requestAsync(okhttpRequest, type)
}
}