翻译自 https://alexzh.com/regional-preferences-in-android-14/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9YLBwPZs-1687502002096)(/Users/ellisonchan/Nutstore Files/ellison-wiki/docs/文章输出/原创/locale/android14-base-locale.png)]
目录:
-
背景
-
获取区域偏好设置
2.1 获取温度单位
2.2 获取一周首日
2.3 获取小时周期
2.4 获取日历类型
-
示例
-
结语
1. 背景
Android 14 的 Settings 中新增了区域偏好的设置画面,让用户可以设置具体的区域习惯,包括:
- 温度单位
- 一周首日
本篇文章基于 Android 14 Beta 2。
这项特性很适合那些使用某区域习惯而居住的地方是另一套习惯的人群,比如习惯了温度单位为华氏的外国人居住在中国,他希望天气、地图 App 能展示华氏单位,而非系统默认的摄氏单位。
利用这项特性,可以设置区别于系统语言的特定温度单位、一周首日以及小时周期等区域偏好。
具体的,可以在 Settings > System > Languages 中可以看到 Regional Preferences 的菜单入口。
2. 获取区域偏好设置
我们可以使用全新的 LocalePreferences
API 获取如下偏好数据:
- 温度单位
- 一周首日
- 小时周期
- 日历类型
这个 API 存在于 AndroidX 包中,想要使用的话,需要集成 androidx.core:core-ktx
的依赖,版本在 1.12.0-alpha01
及以上。
如下链接可以找到 core-ktx 的所有版本:
- https://developer.android.com/jetpack/androidx/releases/core?ref=alexzh.com
dependencies {
...
implementation "androidx.core:core:1.12.0-alpha04"
}
2.1 获取温度单位
利用 LocalePreferences 提供的 getTemperatureUnit()
可以返回代表当前选择的温度单位的 String 类型:
- “celsius” (°C)
- “fahrenhe” (°F)
同时也提供了其他函数来获取指定区域的温度单位:
getTemperatureUnit(Locale locale)
getTemperatureUnit(Locale locale, boolean resolved)
拿到温度单位的字符串之后,还可以和 SDK 提供的温度单位 Class TemperatureUnit
中的常(比如华氏的 FAHRENHEIT
)量进行 mapping、对比。下面的链接可以看到所有的常量定义:
- https://developer.android.com/reference/androidx/core/text/util/LocalePreferences.TemperatureUnit?ref=alexzh.com
2.2 获取一周首日
getFirstDayOfWeek()
则返回代表当前选择的一周首日偏好:
- “sun” - Sunday
- “mon” - Monday
- “tue” - Tuesday
- “wed” - Wednesday
- “thu” - Thursday
- “fri” - Friday
- “sat” - Saturday
获取指定区域的一周首日偏好的函数:
getFirstDayOfWeek(Locale locale)
getFirstDayOfWeek(Locale locale, boolean resolved)
可以和 SDK 提供的 FirstDayOfWeek
class 中的常量(比如 MONDAY,周一)进行 mapping、对比。下面的链接可以看到所有的常量定义:
- https://developer.android.com/reference/androidx/core/text/util/LocalePreferences.FirstDayOfWeek?ref=alexzh.com
2.3 获取小时周期
getHourCycle()
则用来获取当前区域的小时周期偏好,具体包括如下几种字符串:
- “h11” - 12 Hour System (0-11)
- “h12” - 12 Hour System (1-12)
- “h23” - 24 Hour System (0-23)
- “h24” - 24 Hour System (1-24)
一样的,如下函数可以获取指定区域的小时周期偏好:
getHourCycle(Locale locale)
getHourCycle(Locale locale, boolean resolved)
可以用 HourCycle
class 包含的常量和上述字符串进行对比。下面的链接可以看到所有的常量定义:
- https://developer.android.com/reference/androidx/core/text/util/LocalePreferences.HourCycle?ref=alexzh.com
2.4 获取日历类型
getCalendarType()
则用来获取当前区域的日历类型偏好:
- “chinese” - Chinese Calendar
- “dangi” - Dangi Calendar (Korea Calendar)
- “gregorian” - Gregorian Calendar
- “hebrew” - Hebrew Calendar
- “indian” - Indian National Calendar
- “islamic” - Islamic Calendar
- “islamic-civil” - Islamic Calendar (tabular, civil epoch)
- “islamic-rgsa” - Islamic Calendar (Saudi Arabia, sighting)
- “islamic-tbla” - Islamic Calendar (tabular, astronomical epoch)
- “islamic-umalqura” - Islamic Calendar (Umm al-Qura)
- “persian” - Persian Calendar
获取指定区域的日历类型的函数:
-
getCalendarType(Locale locale)
-
getCalendarType(Locale locale, boolean resolved)
相同的,CalendarType
类中的常量可以用来和字符串进行对比。下面的链接可以看到所有的常量定义:
- https://developer.android.com/reference/androidx/core/text/util/LocalePreferences.CalendarType?ref=alexzh.com
3. 示例
比较不同区域偏好值的最简单办法是创建一个 BroadcastReceiver
,当监听到区域变更(从 Settings > System > Languages > System Languages 中操作)的时候,通过 LocalePreferences
API 来打印新区域的偏好值。
class LocaleReceiver : BroadcastReceiver() {
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
override fun onReceive(context: Context, intent: Intent) {
val localePreferenceData = """
getTemperatureUnit: ${LocalePreferences.getTemperatureUnit()}
getFirstDayOfWeek: ${LocalePreferences.getFirstDayOfWeek()}
getHourCycle: ${LocalePreferences.getHourCycle()}
getCalendarType: ${LocalePreferences.getCalendarType()}
""".trimIndent()
Log.d("New locale prefs values", localePreferenceData)
}
}
下一步是在 AndroidManifest.xml
文件里声明上述 LocaleReceiver
。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
...
<application
...>
<receiver
android:name=".LocaleReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.LOCALE_CHANGED" />
</intent-filter>
</receiver>
...
</application>
</manifest>
来看一下同是英语,但在两个不同区域(美国和荷兰)上的偏好差异:
区域偏好 | English (United States) | English (Netherlands) |
---|---|---|
Temperature Unit | fahrenhe | celsius |
First Day of Week | sun | mon |
Hour Cycle | h12 | h23 |
Calendar Type | gregorian | gregorian |
我们再来回顾一下这些数据有用的案例:
温度单位
很多需要展示天气数据的 App 通常会提供设置温度单位的入口,那么这个默认数据可来源于系统的“区域偏好”。App 便可以进行设置的转换和展示特定的温度单位。
一周首日
相似的,很多 App 也会提供日期选择组件来设置日期,此刻可能需要设置一周首日,即从周日还是周一开始。如果能够从系统的“一周首日”偏好中同步设置,便能给用户提供更佳的体验。
小时周期
通常来讲,在一些 App 上执行创建笔记、支付、查阅快递信息等操作的时候,会展示执行的时间。如果能够能和系统的“小时周期”偏好保持一致,数据的展示将更加精准。
4. 结语
Android 14 开始,Settings 会展示区域偏好的设置界面,供用户在系统语言以外独立设置区域偏好,开发者还可以使用相应 API 来获取该偏好。
我们可以使用如下两个函数来获取温度单位偏好和一周首日偏好:
LocalePreferences.getTemperatureUnit()
LocalePreferences.getFirstDayOfWeek()
此外,我们还可以从当前区域获得小时周期和日历类型偏好。
LocalePreferences.getHourCycle()
LocalePreferences.getCalendarType()
但其实,我不太相信 Locale Preferences API 很快能得到广泛使用,原因在于很多 App 早已自行实现了区域之类的偏好配置,而且也不依赖 OS 版本。
话虽如此,还是有相当部分的 App 并没有提供区域偏好的设置,而且官方的 API 兼容性更好、能够给用户提供一致的设置体验,那么相信在未来这个 API 肯定能渐渐普及开来。
参考
- https://developer.android.com/reference/kotlin/androidx/core/text/util/LocalePreferences