极简便签是一款简洁、高效、轻便、小而美的笔记应用。
more >>在 Android 开发中,我们有大量的应用场景需要启动一个 Activity 并接收其返回的结果来完成业务逻辑的执行。例如,你的应用可启动相机并接收拍摄的照片作为结果。或者,你可以启动“通讯录”以便用户选择联系人,然后接收联系人详细信息作为结果。
虽然所有 API 级别的 Activity 类均提供了底层 startActivityForResult 和 onActivityResult API,但 Google 强烈建议使用 registerForActivityResult 来替代它们。因为新的 API 可以极大程度的保证数据的类型安全、Activity 的生命周期安全,同时还能增加代码的复用性,详情参考「官方文档」。
1  | val intent = Intent(this, TargetActivity::class.java)  | 
1  | private val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult ->  | 
Jetpack 提供了多种预定义的合约类型,开箱即用:
| 合约类型 | 用途 | 返回值类型 | 
|---|---|---|
| StartActivityForResult() | 通用 Activity 启动 | ActivityResult | 
| TakePicture() | 拍照 | Bitmap? | 
| PickContact() | 选择联系人 | Uri? | 
| GetContent() | 选择文件(文本/图片等) | Uri? | 
| RequestPermission() | 请求单个权限 | Boolean | 
| OpenDocument() | 打开文档 | Uri? | 
| OpenDocumentTree() | 访问目录树 | Uri? | 
| StartIntentSenderForResult() | 处理 PendingIntent | ActivityResult | 
1  | private val launcher = registerForActivityResult(ActivityResultContracts.TakePicturePreview()) { bitmap: Bitmap? ->  | 
1  | private val launcher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->  | 
1  | private val launcher = registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri: Uri? ->  | 
虽然 ActivityResultContracts 包含一些预先构建的 ActivityResultContract 类供您使用,但您可以使用自己的协定,提供您所需要的精确类型安全 API。
每个 ActivityResultContract 都需要定义好的输入和输出类,如果您不需要任何输入,请使用 Void 作为输入类型(在 Kotlin 中,请使用 Void? 或 Unit)。
每个协定都必须实现 createIntent() 方法,该方法接受 Context 和输入内容作为参数,并构造将与 startActivityForResult() 配合使用的 Intent。
每个协定还必须实现 parseResult(),它会根据指定的 resultCode(如 Activity.RESULT_OK 或 Activity.RESULT_CANCELED)和 Intent 生成输出。
如果无需调用 createIntent()、启动另一个 activity 并借助 parseResult() 来构建结果即可确定指定输入内容的结果,协定可以选择性地实现 getSynchronousResult()。
以下示例展示了如何构造 ActivityResultContract:
1  | class PickRingtone : ActivityResultContract<Int, Uri?>() {  | 
| Windows | Mac | 描述 | 
|---|---|---|
| Ctrl + E | Cmd + E | 快速查看最近打开过的文件。 | 
| Ctrl + Shift + E | Cmd + Shift + E | 快速查看最近编辑过的文件。 | 
| Ctrl + P | Cmd + P | 查看方法的参数信息。 | 
| Ctrl + U | Cmd + U | 跳转到当前方法的父类实现,或者当前类的父类。 | 
| Ctrl + H | Cmd + H | 查看一个类的继承树。 | 
| Ctrl + Shift + H | Cmd + Shift + H | 打开方法层次结构。 | 
| Ctrl + Alt + H | Cmd + Option + H | 打开调用层次结构。 | 
| Ctrl + Alt + B | Cmd + Opt + B | 当光标位于接口名上时,按下快捷键可以快速找到该接口的所有实现类。 | 
| Ctrl + F12 | Cmd + F12 | 当光标位于类中时,按下快捷键可以显示当前文件的结构,包括所有方法和变量。 | 
| Ctrl + Shift + C | Cmd + Shift + C | 复制当前文件的路径。 | 
在特定的硬件项目开发中,受部分硬件支持库的限制,项目的目标 SDK 版本可能会设置为已经不受 Google 支持的版本。 如果在生成 APK 的过程中出现 ExpiredTargetSdkVersion 错误,那就标志着项目所设定的 targetSdk 已经过期,我们可能需要升级 API 级别或采取其他措施。错误信息如下:
1  | Error: Google Play requires that apps target API level 33 or higher. [ExpiredTargetSdkVersion]  | 
深色主题在 Android 9 及更早些时候,开发者需要通过 AppCompat 库的 DayNight 主题或自定义方案实现应用内深色模式,缺乏系统级联动。从 Android 10(API 级别 29)开始,官方提供了系统级的深色主题支持,并在 Android 11、12 中持续优化。以下是官方对深色主题支持的演进:
| 版本 | 时间 | 描述 | 
|---|---|---|
| Android 10 | 2019 | 引入全局深色主题,用户可在系统设置中一键切换,系统界面和应用(适配后)会跟随主题变化。 | 
| Android 11 | 2020 | 优化了深色主题的调度(如定时切换),并增强了对第三方应用图标和控件的适配。 | 
| Android 12 | 2021 | 引入 Material You 设计语言,支持更灵活的主题自定义(如动态取色),进一步统一深色体验。 | 
首先,SQLite 中没有单独的布尔数据类型,通常使用整数来存储布尔值。那么,我们可不可以在不先检索存储值的前提下,只使用一条 SQL 语句来切换这个值呢?
例如,我们有一个 people 表,内容如下:
| id | name | is_friend | 
|---|---|---|
| 1 | Peter | 0 | 
| 2 | Mary | 1 | 
| 3 | John | 0 | 
要切换 Mary 的 is_friend 属性,我们可以执行这条 SQL 语句:
1  | UPDATE `people` SET is_friend = ((is_friend | 1) - (is_friend & 1)) WHERE id = 2  | 
委托模式是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。Kotlin 直接支持委托模式,更加优雅,简洁,在 Kotlin 中,通过关键字 by 实现委托。
通过委托方式实现接口的方法,实际上是通过动态代理的方式创建一个接口的实现类对象,并委托给要实现这个接口的类,减少接口不需要的方法的重写。
类的委托即一个类中定义的方法实际是调用另一个类的对象的方法来实现的。以下实例中派生类 Leader 继承了接口 Work 所有方法,并且委托一个传入的 Clerk 类的对象来执行这些方法。
1  | // 创建接口  | 
在 Leader 的声明中,by 关键字表示,将 clerk 保存在 Leader 的对象实例内部,而且编译器将会生成继承自 Work 接口的所有方法, 并将调用转发给 clerk。
more >>这是篇过程复盘类的文章,一是想将问题的排查、解决过程梳理出来;二是要将排查过程中涉及到的一些琐碎的知识点记录下来。在开始复盘前,简单交代一下问题背景:我维护的项目基于【网易云信】实现了 IM 功能,与微信类似,用户收到消息后,手机会收到消息推送,状态栏和桌面 LOGO 的角标都会有消息提醒,最近有华为手机用户反馈没有消息提醒了,于是开始了下面的排查过程。
本次排查的问题为,华为手机用户在收到 IM 消息后,桌面 LOGO 的角标不发生动态更新,只有进入应用的消息列表页面,再重新切到桌面后角标数量才会更新。
桌面图标的角标数量不更新,我们第一时间想到的是用户的「桌面图标角标」权限是否开启?结果是开启的,那就证明问题不在角标权限这里。
more >>Chains 是一种特定类型的约束,它允许我们在链内的视图之间共享空间,并控制可用空间在它们之间的划分方式。与传统 Android 布局最相似的应该是 LinearLayout 中的权重比 weight 属性,但 Chains 能做到的要远远比 weight 多。
前面已经提到了 Chain 链是由多个 View 组成的,所以要创建一个 Chain 链就需要先选择多个想要链接到一起的 Views,然后再通过水平链或垂直链将其链到一起。Chain 链模式一共有三种,分别为:spread ,spread_inside 和 packed ,若想这些模式生效,在链头设置属性即可。
| 模式 | 说明 | 
|---|---|
| spread | Chain 链的默认模式就是 spread 模式,它将平分间隙让多个 Views 布局到剩余空间。 | 
| 图例 | |
         
     | 
|
tag:
            缺失模块。
1、请确保node版本大于6.2
2、在博客根目录(注意不是yilia根目录)执行以下命令:
 npm i hexo-generator-json-content --save
            3、在根目录_config.yml里添加配置:
  jsonContent:
    meta: false
    pages: false
    posts:
      title: true
      date: true
      path: true
      text: false
      raw: false
      content: false
      slug: false
      updated: false
      comments: false
      link: false
      permalink: false
      excerpt: false
      categories: false
      tags: true