Android 14 新特性:语法性别 Grammatical Gender

news2024/9/23 13:23:23

在这里插入图片描述

背景

如同汉语里的他、她、它,英语里的 He、She、it,很多语言都存在依据性别、对象不同而造成的语法差异,甚至不仅限于名词,还涉及到形容词、动词等,复杂得多。

而这部分语言所涉及到的人群多达 30 亿之众,如果文本只使用通用的、中性的表述,则显得不够准确。假使不加区分,甚至对女性使用男性化的表述方式,则体验更为糟糕。

所以如果 App 的界面语言能正确反映用户的语法性别,则就可以提高用户好感度、互动度,达到更个性化、更自然的用户体验。

这便是 Android 14 推出的重要新特性:语法性别 Grammatical Gender

语法性别管理 API

首先,Android 14 推出了针对语法性别的 API:GrammaticalInflectionManager,其提供了针对单个 App 获取、设置性别偏好的入口。

  • getApplicationGrammaticalGender():获取语法性别偏好,返回的是 Configuration 类中的 int 常量,有这么几种类型:

    • GRAMMATICAL_GENDER_NOT_SPECIFIED, 0:尚未指定性别偏好,将用默认的资源文本
    • GRAMMATICAL_GENDER_NEUTRAL, 1:指定中性、客观的资源文本
    • GRAMMATICAL_GENDER_FEMININE, 2:指定针对女性的资源文本
    • GRAMMATICAL_GENDER_MASCULINE, 3:指定针对男性的资源文本
  • setRequestedApplicationGrammaticalGender():相对应的将上述常量类型动态设置到性别偏好

设置性别资源

反映语法性别的变化还得有依据语法性别配置的文本才行。而法语针对语法性别的差异比较典型,我们选择法语文本进行示例说明。

比如我们添加 res/values-fr-feminine 目录,在其 strings.xml 里添加针对女性的表述方式。

 <resources>
     ...
     <string name="example_string">Vous êtes abonnée à...</string>
 </resources>

并添加 res/values-fr-masculine 目录,添加针对男性的表述方式。

 <resources>
     ...
     <string name="example_string">Vous êtes abonné à...</string>
 </resources>

在 res/values-fr 下的 strings.xml 里添加针对中性、客观的表述方式。

 <resources>
     ...
     <string name="example_string">Abonnement à...activé</string>
 </resources>

另外在 values/strings.xml 添加默认的英文表述。

 <resources>
     <string name="example_string">You are subscribed to our store service</string>
 </resources>

动态设置性别偏好

然后我们添加个 TextView 来展示语法性别变化的效果,首先看一下默认 Gender 即 NOT_SPECIFIED 时的文本表述。

Screenshot_20230616_174557.png

可以看到使用的是 values 下默认的英文表述。

然后,在 Button 点击里模拟各种性别偏好的动态更新。

 class GenderActivity : AppCompatActivity() {
     private lateinit var gIM: GrammaticalInflectionManager
     private lateinit var binding: GenderLayoutBinding
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         Log.d("Gender", "onCreate()")
 
         binding = GenderLayoutBinding.inflate(layoutInflater)
         setContentView(binding.root)
 
         gIM = getSystemService(GrammaticalInflectionManager::class.java)
         updateCurrentGender()
 
         binding.changeGender.setOnClickListener {
             Log.d("Gender", "change Gender button tapped")
 
             gIM.setRequestedApplicationGrammaticalGender(
                 gIM.applicationGrammaticalGender.nextGender()
             )
 
             updateCurrentGender()
         }
     }
 
     private fun updateCurrentGender() {
         gIM.applicationGrammaticalGender.genderToString().let {
             Log.d("Gender", "current gender: $it")
             binding.changeGender.text = "Grammatical gender:$it"
         }
     }
 
     private fun Int.nextGender() =
         when (this) {
             Configuration.GRAMMATICAL_GENDER_NEUTRAL -> Configuration.GRAMMATICAL_GENDER_MASCULINE
             Configuration.GRAMMATICAL_GENDER_MASCULINE -> Configuration.GRAMMATICAL_GENDER_FEMININE
             Configuration.GRAMMATICAL_GENDER_FEMININE -> Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED
             Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED -> Configuration.GRAMMATICAL_GENDER_NEUTRAL
             else -> Configuration.GRAMMATICAL_GENDER_NEUTRAL
         }
 }

运行下看下变化效果,可以看到 Gender 在 NOT_SPECIFIED、NEUTRAL、MASCULINE 和 FEMININE 配置之间切换,TextView 的表述也相应地进行了更新。

update-gender-recreate.gif

Log 也展示了当前 Gender 和变化的记录:

 ellisonchan@bogon AndroidUDemo % adb logcat -s Gender
 06-16 17:47:33.160  D Gender  : onCreate()
 06-16 17:47:33.228  D Gender  : current gender: Not specified
 06-16 17:47:49.103  D Gender  : change Gender button tapped
 06-16 17:47:49.238  D Gender  : onCreate()
 06-16 17:47:49.261  D Gender  : current gender: Neutral
 06-16 17:47:49.325  D Gender  : current gender: Neutral
 06-16 17:47:55.771  D Gender  : change Gender button tapped
 06-16 17:47:55.845  D Gender  : onCreate()
 06-16 17:47:55.863  D Gender  : current gender: Masculine
 06-16 17:47:55.904  D Gender  : current gender: Masculine
 06-16 17:47:59.634  D Gender  : change Gender button tapped
 06-16 17:47:59.666  D Gender  : onCreate()
 06-16 17:47:59.683  D Gender  : current gender: Feminine
 06-16 17:47:59.742  D Gender  : current gender: Feminine
 06-16 17:48:01.735  D Gender  : change Gender button tapped
 06-16 17:48:01.773  D Gender  : onCreate()
 06-16 17:48:01.788  D Gender  : current gender: Not specified
 06-16 17:48:01.846  D Gender  : current gender: Not specified

需要留意的是,上述效果需要将设备或 App 偏好语言设置成法语才可以看到效果。

还有个细节要注意,调用完 setRequestedApplicationGrammaticalGender 更新 Gender 后,通过 getApplicationGrammaticalGender() 的处理要稍微延迟一下,才能看到新的偏好,也可以理解,因为这个设置是 GrammaticalInflectionManager 系统服务通知的 App Context,这个过程是异步的。

 class GenderActivity : AppCompatActivity() {
     ...
     override fun onCreate(savedInstanceState: Bundle?) {
         ...
         binding.changeGender.setOnClickListener {
             ...
 
             gIM.setRequestedApplicationGrammaticalGender(
                 gIM.applicationGrammaticalGender.nextGender()
             )
 
             // 延迟一下再去获取最新 Gender 偏好
             GlobalScope.launch(Dispatchers.Main) {
                 delay(50)
                 updateCurrentGender()
             }
         }
     }
     ...
 }

语法性别变更的重绘防止

上面的录屏、log 都可以看到 Gender 偏好变化之后 Activity 会发生重绘,因为它本质上也属于 Configuration 的范畴。和其他 Configuration change 一样,如有需要防止画面重启,可以在 Manifest 中配置。

 <?xml version="1.0" encoding="utf-8"?>
 <manifest ...>
     ...
     <application...>
         <activity
             ...
             android:configChanges="grammaticalGender">
         </activity>
     </application>
 </manifest>

可想而知,Activity 不自动刷新,改了 Gender TextView 也不会有效果了。

update-gender-not-recreate.gif

但好在该 Gender 偏好随着 onConfigurationChanged() 被传递了过来。

 06-16 18:05:31.021  D Gender  : onCreate()
 06-16 18:05:31.021  D Gender  : current gender: Not specified
 
 06-16 18:06:33.023  D Gender  : change Gender button tapped
 06-16 18:06:33.229  D Gender  : GenderActivity# onConfigurationChanged() new gender:Neutral
 
 06-16 18:06:34.541  D Gender  : change Gender button tapped
 06-16 18:06:34.578  D Gender  : GenderActivity# onConfigurationChanged() new gender:Masculine
 ...

我们可以选择使用 ConfigurationgetGrammaticalGender() 来获取新的 Gender 偏好,也可以使用上述的 GrammaticalInflectionManager 获取 API,两者得到的性别偏好结果是一致的。

 class GenderActivity : AppCompatActivity() {
     ...
     override fun onConfigurationChanged(newConfig: Configuration) {
         super.onConfigurationChanged(newConfig)
         Log.d("Gender", "GenderActivity# onConfigurationChanged()" +
                 " new gender:${newConfig.grammaticalGender.genderToString()}"
         )
     }
 }

既然可以拿到新的 Gender,那么让 TextView 被动刷新即可,而刷新的关键使用新的 Resources 获取当前 Gender Configuration 下的 text 去更新。

 class GenderActivity : AppCompatActivity() {
     ...
     override fun onConfigurationChanged(newConfig: Configuration) {
         ...
 
         // Resources will be updated with new configuration
         val newText = resources.getString(R.string.example_string)
         Log.d("Gender", "onConfigurationChanged()" +
                 " new text:${resources.getString(R.string.example_string)}"
         )
 
         binding.textview.text = newText
     }
 }

可以看到这次只是 TextView 局部刷新,不会有全体的重绘、闪烁。

update-gender-not-recreate-update.gif

需要留意,如下两个方法是无效成功更新 Gender 效果的:

  • invalidate(),因为它只是触发重新测量、布局和描画,text 内容并无变化
  • dispatchConfigurationChanged(),因为 TextView 的 onConfigurationChanged() 只针对 Locale、Typeface 进行了配置刷新,没有针对 Gender 做更新

注意

即便在最新的 Release 版 AS 上,都是无法识别上述语法性别资源目录的,会发生编译失败:

AndroidUDemo/app/src/main/res/values-fr-feminine: Error: Invalid resource directory name

得升级到 Android Studio Giraffe Canary 7 或更高的版本,才能支持。

另外还得升级到最新的 AGP,笔者使用的版本组合是:Android Studio Hedgehog | 2023.1.1 Canary 7 + AGP 8.1.0-alpha07,供大家参考。

DEMO 源码

https://github.com/ellisonchan/AndroidUDemo

参考

  • https://developer.android.com/about/versions/14/features/grammatical-inflection
  • https://developer.android.com/studio/preview/features?hl=zh-cn#grammatical-inflection-api
  • https://developer.android.google.cn/reference/android/app/GrammaticalInflectionManager
  • https://androidstudio.googleblog.com/2023/02/android-studio-giraffe-canary-7-now.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/658819.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【树形DP+可重集排列】至至子的公司排队

好屌的题 F-至至子的公司排队_牛客小白月赛55 (nowcoder.com) 题意&#xff1a; 思路&#xff1a; 其实题目问的就是&#xff0c;森林的拓扑序有几种 那么我们先去考虑一棵树的拓扑序有几种 这个可以用树形DP来解决 设dp[u]为&#xff0c;以u为根的子树的拓扑序的种类数&…

【Java】项目中大批量数据查询导致OOM

文章目录 背景内存溢出的具体原因错误模拟问题复现解决办法流式查询和分页查询的使用场景查询数据的建议 背景 项目中有时候一次性将大批量数据都查出来到内存中导致内存占用过多很可能会导致内存溢出 内存溢出的具体原因 在JVM内存结构中分为以下几个模块 程序计数器虚拟机…

SSL协议,一文带你了解

SSL简介 SSL&#xff08;Secure Sockets Layer&#xff09;是一种安全协议&#xff0c;用于保护互联网上的数据传输安全。SSL协议最初由网景公司开发&#xff0c;现在已经被TLS&#xff08;Transport Layer Security&#xff09;协议所取代。SSL协议和TLS协议都是为了保护数据传…

一文带你弄懂【时间复杂度】

文章目录 算法时间复杂度时间复杂度计算常见的时间复杂度时间复杂度的差异 总结 算法 算法&#xff08;Algorithm&#xff09;是求解一个问题需要遵循的&#xff0c;被清楚指定的简单指令的集合。 一个算法的评价主要从时间复杂度和空间复杂度来考虑。而时间复杂度是一个函数…

Netty核心技术四--Netty概述

1. 原生NIO存在的问题 NIO 的类库和 API 繁杂&#xff0c;使用麻烦&#xff1a;需要熟练掌握Selector、ServerSocketChannel、SocketChannel、ByteBuffer 等。需要具备其他的额外技能&#xff1a;要熟悉 Java 多线程编程&#xff0c;因为NIO编程涉及到Reactor模式&#xff0c;…

从tomcat说起全面理解Java web开发原理

从tomcat说起全面理解Java web开发原理 简介&#xff1a;Java开发分为Java ME&#xff0c;Java SE&#xff0c;Java EE。回顾过去这些的开发工作基本上都是围绕着Java EE的&#xff0c;在开发经历中分别经历了Java EE开发框架从jsp servlet一路经历了ssh&#xff0c; ss…

存储笔记8 ipsan

Module Objectives IP SAN的组件 IP SAN的好处 描述SAN中的IP融合及其影响 描述的基本架构 –iSCSI –FCIP –FCoE 讨论IP SAN技术的市场驱动因素 列出IP SAN技术 列出iSCSI的组件和连接选项 描述iSCSI体系结构和拓扑结构 解释iSNS操作 描述FCIP的体系结构 IP SAN互联…

Springboot整合第三方登录

文章目录 Springboot整合第三方登录为什么采用第三方登录整合第三方登录创建应用导入依赖创建controller类 Springboot整合第三方登录 为什么采用第三方登录 ​ 采用第三方登录可以避免重新注册账号的繁琐&#xff0c;也不需要再为密码和昵称发愁&#xff0c;而第三方登录有一…

Linux命令——top相关之Load Average平均负载

Linux 平均负载 Load Average 详解_系统1f分钟负载_欧晨eli的博客-CSDN博客 一、什么是Load Average&#xff1f; 系统负载&#xff08;System Load&#xff09;是系统CPU繁忙程度的度量&#xff0c;即有多少进程在等待被CPU调度&#xff08;进程等待队列的长度&#xff09;。…

2-JVM运行流程

JVM 是 Java 运行的基础&#xff0c;也是实现一次编译到处执行的关键&#xff0c;那么 JVM 是如何执行的呢&#xff1f; 程序在执行之前先要把java源代码&#xff08;.java&#xff09;转换成字节码文件&#xff08;.class&#xff09;。JVM 首先需要通过一定的方式类加载器&a…

如何做好前端性能优化

前端推荐官网: http://luckycola.com.cn/ 前言: 前端性能优化一直是一个前端开发人员必须关注的经典话题,虽然现在随着技术的不断发展,网页容器(浏览器、webview)性能也越来越强大,但是网站应用的功能也不断丰富,体积不可避免的增加,当网络环境等因素不好时,仍然会存在白屏时…

【后端面经】MySQL主键、唯一索引、联合索引的区别和作用

【后端面经】MySQL主键、唯一索引、联合索引的区别和作用 0. 简介1. 主键2. 唯一索引3. 联合索引4. 索引对数据库操作的影响5. 其他索引5.1 普通索引5.2 全文索引5.3 前缀索引 6. 总结7. 参考资料 0. 简介 索引是一类特殊的文件&#xff0c;用来存储检索信息&#xff0c;使数据…

数值天气预报期末复习

数值天气预报期末复习 文章目录 数值天气预报期末复习&#xff08;零&#xff09;重点需要掌握知识点&#xff08;一&#xff09;什么是数值天气预报&#xff08;二&#xff09;数值模式的分类&#xff08;三&#xff09;各坐标系下的大气运动方程组3.1 局地直角坐标系3.2 球坐…

绩效跃升地图读书笔记20130618

绩效跃升地图&#xff0c;从5月份开始看&#xff0c;每天中午吃完饭休息的时候&#xff0c;坐在工位上&#xff0c;把看手机刷视频看八卦的时间&#xff0c;换成看书的时间&#xff0c;直到6月15日看完一本书。发现其实利用好碎片时间&#xff0c;还是可以读不少书的。 “绩效…

网络端口地址转换 NAPT 配置

你是某公司的网络管理员&#xff0c;公司办公网需要接入互联网&#xff0c;公司只向 ISP 申请了一条专线&#xff0c;该专线分配了一个公司 IP 地址&#xff0c;配置实现全公司的主机都能访问外网。 技术原理 NAT 将网络划分为内部网络和外部网络两部分&#xff0c;局域网主机…

Java集合详解

目录 友情提醒第一章、集合体系概述1.1&#xff09;集合是什么&#xff1f;与数组的区别在哪1.2&#xff09;集合体系与分类 第二章、集合体系中的Collection和List接口/Set接口2.0&#xff09;List接口/Set接口两者区别2.1&#xff09;Collection接口中的常用方法2.2&#xff…

【系统开发】尚硅谷 - 谷粒商城项目笔记(一):项目准备工作

文章目录 项目准备工作人人开源搭建后台管理系统数据库搭建前端项目搭建后端模块代码生成 项目准备工作 人人开源搭建后台管理系统 码云搜索人人开源 renren-fast-vue&#xff1a;前端 renren-generator&#xff1a;代码生成器 renren-fast&#xff1a;后台管理系统 用git…

系统设计蓝图:终极指南

系统设计蓝图&#xff1a;终极指南 设计开发一个健壮的、可扩展的、高效的系统可以是令人望而生畏. 但是&#xff0c;了解关键概念和组件可以使流程更易于管理。在这篇博文中&#xff0c;我们将探索基本的系统设计组件&#xff0c;例如 DNS、负载平衡、API 网关等&#xff0c;以…

python详解(7)——进阶(1):排序算法

目录 &#x1f3c6;一、前言 &#x1f3c6;二、什么是算法&#xff08;简单&#xff09; &#x1f6a9;1、算法 &#x1f6a9;2、排序算法 &#x1f3c6;三、冒泡排序&#xff08;中等&#xff09; &#x1f3c6;四、快速排序&#xff08;困难&#xff09; &#x1f3c6;五&…

Android Studio 提高SDK下载速度

我们在下载Android SDK的时候&#xff0c;经常会出现下载失败的情况&#xff0c; 报android sdk manager not installing components之类的错误。 要如何加快SDK的下载速度呢 ? 我们可以通过修改Host来实现 关闭Android Studio的代理 首先&#xff0c;我们要关闭Android Stu…