Android UI 日期時間選擇 DatePicker

簡介 Android 原生提供的日期時間選擇 UI。 官方推薦使用 Material Design 的 API MaterialDatePicker (Dialog) 日期區間選擇 DateRangePicker Kotlin 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import com.google.android.material.datepicker.MaterialDatePicker val datePicker = MaterialDatePicker.Builder.dateRangePicker() .setTitleText("選擇調查日期區間") .setSelection(Pair(startPeriod, endPeriod)) .build() datePicker.show(childFragmentManager, TAG_DATE_RANGE_PICKER) datePicker.addOnPositiveButtonClickListener { startPeriod = it.first endPeriod = it.second setTvStartAndEnd() } Java 1 2 3 4 5 6 7 8 9 10 11 12 import androidx.core.util.Pair; import com.google.android.material.datepicker.MaterialDatePicker; MaterialDatePicker<Pair<Long, Long>> dateRangePicker = MaterialDatePicker.Builder.dateRangePicker() .setTitleText(R.string.date_filter) .setSelection(Pair.create(startTime, endTime)) .build(); dateRangePicker.addOnPositiveButtonClickListener(selection -> mMainViewModel.setFilterPeriod(selection)); dateRangePicker.show(getChildFragmentManager(), TAG_DATE_PICKER); 使用 MaterialDatePicker.Builder.dateRangePicker 建立,可設定 UI 上的標題 (setTitleText()) 與預選的日期區間 (setSelection)。 dateRangePicker 是泛型 Pair<Long, Long>,Pair 中儲存的是開始日期與結束日期的 UNIX時間(milliseconds)。 ...

Published on October 31, 2023 · 2 min · 425 words · Daniel Huang

Android BuildConfig 消失了?

問題 最近開新專案的時候,發現寫 BuildConfig 都沒有出現 prompt,後來才發現是新的專案要另外開設定。 什麼是 BuildConfig BuildConfig 是 Gradle 在編譯時期自動建立的類別,裡面包含目前建製版本的相關資訊,開發者也可以自行加入客製化的欄位資料。 為什麼會有這個問題? 根據 解決 Android Studio 中的 BuildConfig 找不到問題 與 Fixing the “Build Type contains custom BuildConfig fields, but the feature is disabled” error w/ buildConfigField的資訊,可以知道 Gradle 8.0.0 後的版本,預設 BuildConfig 是關閉的。 解法 在 module 的 build.gradle 中新增以下程式碼,在重新 build project 即可。 1 2 3 4 5 6 7 8 9 10 // (app) build.gradle android { // 略... buildFeatures { // 開啟 buildConfig true } }

Published on June 30, 2023 · 1 min · 75 words · Daniel Huang

Android 定位結果的 `Location.getTime()` 不一定是衛星時間

Photo by SpaceX on Unsplash 前言 最近的專案需要取定位的時間,並用該時間判斷使用者是否有在指定時間完成任務,而業主就提出希望以定位所取得的時間做為判斷依據。 然後,就發現事情沒有想像中的那麼單純。 原來目前在 Android 的定位結果中所取得的時間,只有在定位來源為純 GPS 的情況下才會是衛星所回傳的時間。 來看看究竟是怎麼一回事吧… 先認識 Location 型別 不論是使用 Android 官方推薦的 Fused Location Provider 或是 LocationManager ,定位結果所回傳的型別都是 Location。這個型別除了基本的經緯度與海拔等資訊,其中也包含定位的時間。 通常開發上指的定位時間,我們會使用 Location.getTime() 取得 Unix epoch time,再將這串數字轉成人類可閱讀的時間格式。 Unix epoch time:從 UTC 1970 年 1 月 1 日 0 時 0 分 0 秒起至現在的總秒數,不考慮閏秒。 – Wikipedia Location.getTime() 會跟定位來源有關 從 Android Doc: Location.getTime() 的說明會發現,不同的定位結果所取得的時間來源不見得相同。 當定位結果是由 LocationManager.GPS_PROVIDER 提供的時候,時間會是由衛星所提供。如果是其他的 Provider,時間來源則不一定,不過通常會是使用裝置系統的 Unix epoch time。 There is no guarantee that different locations have times set from the same clock. Locations derived from the LocationManager#GPS_PROVIDER are guaranteed to have their time originate from the clock in use by the satellite constellation that provided the fix. Locations derived from other providers may use any clock to set their time, though it is most common to use the device’s Unix epoch time system clock (which may be incorrect). ...

Published on May 27, 2023 · 2 min · 257 words · Daniel Huang

比 Android 原生更方便的 Log 工具: Timber

本文同步發表在 HackMD & Medium Timber 是什麼 Timber 是一個以 Android Log 為基底所開發的 Logger Library,由 Jake Wharton 大神所開發。 Timber 為了解決什麼問題 1. 開發時可以留著,但發佈版本需要移除 Log 1 2 3 4 // 你可能很常看到類似這樣的寫法... if (BuildConfig.DEBUG) { Log.d(TAG, "Hello World!") } 一般來說在開發上,我們習慣使用 Android 的 Log class 來印出所需的資訊。但是當今天開發到一定的階段,程式必須發布上線時,為了資訊安全等需求,需要將這些 Log 給全部註解或移除,又或是加上 buildFlavor 或 buildType 判斷,這一切實在是太麻煩了… 2. 每次在新的類別中使用 Log 就要建一個該類別的 TAG String 1 2 3 4 5 val TAG: String = Hello::class.java.simple if (BuildConfig.DEBUG) { Log.d(TAG, "Hello World!") } 同步發表在 HackMD & Medium Timber 怎麼使用 1. Dependency 在 build.gradle 中加入以下的 Dependency。 ...

Published on May 27, 2023 · 1 min · 170 words · Daniel Huang

Android 取得即時定位 LocationManager

📢 除非有特殊需求,官方建議使用 Google Fused Location Provider API。 權限請求 AndroidManifest.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <!-- 宣告定位權限 --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <application> <!-- 略 --> </application> </manifest> 請求動態權限 因為定位屬於危險權限需要動態向使用者請求。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import android.Manifest import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts class MainActivity : AppCompatActivity() { // -----------------------Request Location Permission------------------------------ private val resultLauncherPermission = registerForActivityResult(ActivityResultContracts.RequestPermission()) { if (it) { initLocationManager() } else { Toast.makeText(this, "請允許權限以開啟定位", Toast.LENGTH_SHORT).show() finish() } } // -----------------------------LifeCycle Event------------------------------------- override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 啟動時請求權限 resultLauncherPermission.launch(Manifest.permission.ACCESS_FINE_LOCATION) } // -------------------------------------------------------------------------------- private fun initLocationManager() { Toast.makeText(this, "定位權限請求成功,準備初始化 LocationManager", Toast.LENGTH_SHORT).show() } } LocationManager 實例化 1 2 3 import android.location.LocationManager val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager 請求定位 Android S 以上支援 FUSED_PROVIDER,不過建議直接用 Android Fused Location Provider API,支援的系統版本比較廣。 ...

Published on May 24, 2023 · 2 min · 271 words · Daniel Huang