2021 iThome 鐵人賽 Day 1:Intro

本篇文章是 2021 iThome 鐵人賽參賽題目「寫一個列車抵站時間 Android App」的第 1 篇,你可到 iThome 查看原文。 文章目錄 早陣子(2021 年 6 月 27 日)港鐵屯馬綫全綫通車,當日有電視台訪問了一名鐵路迷,他受訪時調寄家傳戶曉的英國民謠《綠䄂子》即興唱了一句自創歌詞「屯馬開通真的很興奮」。那我們就以港鐵實時列車抵站時間做例子,示範一些現在 Android 開發流行的東西。 App 會有兩頁:選擇車站頁和抵站時間頁。選擇車站頁就是列出某條行車綫的車站,讓用戶點選查閱該站的列車抵站時間;抵站時間頁就是顯示某行車綫及車站的列車抵站時間。 ...

September 16, 2021

文字末端 icon 排版

以前試過做一些 UI 是 TextView 旁邊有一個 icon,然後同一行最右邊會有另一個 Button。如果文字過長就加上省略號,但文字不夠長的話 icon 要緊貼那個文字而那個 Button 就固定在右邊。TextView 有 compound drawable,但如果想那個 icon 有 click listener 又用不了。所以最後都要分開 TextView 和 ImageView/ImageButton 兩個 view。 ...

April 10, 2021

Android SMS Verification APIs

SMS 驗證應該是一個在 Android app 頗為常見的需求。一般做法都是先讓用戶填寫電話號碼,然後 app 會把電話號碼交到 backend 再透過 SMS gateway 發送含有驗證碼短訊, 當用戶收到 SMS 後再把內文的驗證碼輸入到 app 中。如果想省卻用戶輪入文字的話有一些 app 會透過 READ_SMS 權限讀取 SMS 內容來抽取驗證碼,但 Google Play 已經限制非預設短訊 app 不可以有 READ_SMS 權限。 ...

March 14, 2021

Notification Channel 自訂音效

自從由 Android 8 開始,如果要顯示 notification 的話就一定要指定一個 notification channel,否則系統不會顯示。Notification channel 的目的是讓用戶能自行調節 app 的各式 notification 的提示方法,例如有沒有音效、會不會彈出 heads-up notification 之類。如果 app 想自訂 notification 的聲音亦都要經 notification channel 設定(但用戶可以之後自行變更 notification channel 的音效) ...

March 13, 2021

Jetpack DataStore 搭配 kotlinx.serialization Protobuf

上月 kotlinx.serialization 出了 1.0 版。除了支援 JSON 之外,還有支援 Protocol Buffers (Protobuf),而且還是跨平台支援。而在前一個月 Android 出了 Jetpack DataStore,它是一個用來取代 SharedPreferences 的 library。它有兩種用法: ...

November 14, 2020

Conventional Commits 和 commitlint

Conventional Commits 是一個簡單的 Git commit message 約定,用來規定 commit message 的寫法。Git 本身就沒有規定 commit message 的內容格式,所以不同人會有不同的做法。如果 repository 只是有一個或幾個人用的話,那問題就不大。但如果在開源軟件或者公司這類多人同時參與的 repository 時,不同風格的 commit message 會令人花額外的時間來了解 repository 的變動。如果再加上一部分的 commit message 內容空洞的時候(例如只寫「fix」、「commit」、「修正錯誤」等等),情況就會失控。 ...

August 24, 2020

Java 量度單位 (JSR 363 Units of Measurement API)

在日常生活中,我們都會用到不同的量度單位。例如重量有時會用公斤 (kg),有時會用磅 (lb),有時又會用斤之類。如果在 Java 上表示這些數值,用 int、float、double 的話有時會令人理解錯誤,就好像 UNIX timestamp 般一時會用秒一時會用毫秒。為防止人們誤解這個 variable 或 method 的時間單位,通常都要在名稱加上 millis 之類的後綴。知名例子有 System.currentTimeMillis。如果處理時間的話,現成的有 TimeUnit。不過如果去到之前的重量單位的話,JDK 就沒有現成的 class。 ...

August 13, 2020

Kotlin Annotation Processor

如果有做過 Android 開發的話應該都有用過 annotation processor(又稱 codegen),即是在 build.gradle 入面要用 annotationProcessor 或者 kapt 的那些 dependency。用法大概是在 code 上加上一些 @ 開頭的 annotation,然後 build 出來就會自動幫你生成相關的 class。簡單來說 annotation processor 就是用 code 來讓 Java compiler 生成 code。通常都是用來生成一些內容重覆的 code 來代替自己人手寫。 ...

April 27, 2020

Moshi Kotlin Codegen + R8 出現 parameter type is null

Moshi 是一個 JSON serialization/deserialization 的 library。和 Gson 不同的是它提供了 Kotlin Codegen,它可以生成 serialization/deserialization 的 adapter class,所以可以避免使用 reflection,而且 adapter 還會參照 Kotlin 的 non-null 和 default value。不過最近發現 production app 會出現 parameter type is null 的錯誤訊息。 ...

March 15, 2020

Firebase Crashlytics 的 CrashlyticsOrgIdException 解決方法

最近為自己的 app 加入 Firebase Crashlytics SDK beta(即是使用 Google 的 Firebase Crashlytics Gradle plugin 而不是用 Fabric 那個),但在 build release APK 時出現下面的錯誤: java.io.IOException: com.google.firebase.crashlytics.buildtools.exception.CrashlyticsOrgIdException: Could not fetch Crashlytics Org Id > com.google.firebase.crashlytics.buildtools.exception.CrashlyticsOrgIdException: Could not fetch Crashlytics Org Id > Could not fetch Crashlytics Org Id > Unable to fetch Crashlytics Org Id using app id 1:731121766578:android:4e799392a2e62811 我的 app 是在 Firebase 開了兩個 project,一個是開發時用的,另一個是 production 用的。但只有 production 才有這個錯誤。如果把 release build 設為不上載 ProGuard/R8 mapping file 的話就不會有這個錯誤。 ...

March 14, 2020