Upgrade to Pro — share decks privately, control downloads, hide ads and more …

炎炎夏日學 Android 課程 - Part3: Android app 實作

炎炎夏日學 Android 課程 - Part3: Android app 實作

炎炎夏日學 Android 課程 - Part3: Android app 實作
(Kotlin EveryWhere 活動)

8a6e58b272b266faf22d8a3b2927624f?s=128

Johnny Sung

June 30, 2019
Tweet

Transcript

  1. 炎炎夏⽇日學 Android Johnny Sung 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

  3. ⼩小試⾝身⼿手

  4. 震動 。

  5. 震動 <uses-permission android:name="android.permission.VIBRATE" /> val vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator

    vibrator.vibrate(10) AndroidManifest.xml
  6. 震動 vibrator.vibrate(longArrayOf(80, 150, 80, 150, 80, 150), -1) vibrator.cancel()

  7. None
  8. 休息⼀一下 ☕

  9. 軟體設計 • 企劃 • UI/UX 介⾯面設計(美術) • 程式 • 測試

  10. 所需材料 • 畫⾯面線框稿 (Wireframe) • API 接⼝口⽂文件 • 美術圖片

  11. 成功畫⾯面 載入中畫⾯面 錯誤畫⾯面

  12. 成功畫⾯面 載入中畫⾯面 錯誤畫⾯面 夕陽⼩小幫⼿手

  13. 成功畫⾯面 載入中畫⾯面 錯誤畫⾯面 夕陽⼩小幫⼿手

  14. 所需⼯工具 • Method Draw 線上編輯圖片⼯工具
 https://editor.method.ac/ • App Icon Generator

    線上 App icon 產⽣生⼯工具
 https://appicon.co/ • JSON Editor Online 線上 JSON 編輯⼯工具
 https://jsoneditoronline.org/
  15. None
  16. None
  17. https://sunrise-sunset.org/api

  18. 22.604098, 120.3001811 K Square 經度 (Latitude) 緯度 (Longitude) 地址:806⾼高雄市前鎮區復興四路路 20

    號 座標
  19. None
  20. None
  21. None
  22. https://api.sunrise-sunset.org/json?lat=22.604098&lng=120.3001811&date=today&formatted=0 今⽇日 K Square 夕陽時間

  23. None
  24. None
  25. 夕陽⼩小幫⼿手 使⽤用套件 • Gson 解析 JSON 資料 • OkHttp 網路路函式庫

    • jDeferred 架構函式庫
  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" // ... } 加入套件參參考
  27. None
  28. None
  29. None
  30. None
  31. class SunsetResponse { var results: SunsetResult? = null var status:

    String? = null } class SunsetResult { var sunset: String? = null }
  32. 單元測試原則 • Arrange – 準備,準備輸入資料與期待值 • Act – 執⾏行行,執⾏行行測試對象 •

    Assert – 驗證,驗證結果 3A 原則
  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
  38. https://github.com/jdeferred/jdeferred

  39. https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html

  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) } }
  41. https://square.github.io/okhttp/

  42. None
  43. 完成了了!

  44. Q & A

  45. 趕快去追夕陽吧

  46. None