opoojkk

Be open to new experiences!

理解 Kotlin Flow:冷热流与背压处理

使用场景 # 1. 持续输出数据(如定时器、进度条) # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 fun timerFlow(): Flow<Int> = flow { for (i in 1..5) { delay(1000) emit(i) // 每秒发出一个进度 } } fun main() = runBlocking { timerFlow() .onEach { println("Progress: $it/5") } .onCompletion { println("Done!") } .collect() } // 输出: // Progress: 1/5 // Progress: 2/5 // Progress: 3/5 // Progress: 4/5 // Progress: 5/5 // Done! 2. 在不同线程中执行 # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 fun fetchData(): Flow<String> = flow { println("Running in thread: ${Thread.currentThread().name}") delay(1000) emit("Data from network") }.flowOn(Dispatchers.IO) // 在 IO 线程执行 fun main() = runBlocking { fetchData() .onEach { println("Collect on thread: ${Thread.currentThread().name}") } .collect { println("Received: $it") } } // 输出: // Running in thread: DefaultDispatcher-worker-1 // Collect on thread: main // Received: Data from network 3. 合并多个异步请求 # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 fun getUser(): Flow<String> = flow { delay(500) emit("User: Alice") } fun getMessagesCount(): Flow<Int> = flow { delay(800) emit(42) } fun main() = runBlocking { combine(getUser(), getMessagesCount()) { user, count -> "$user, Unread messages: $count" }.collect { println(it) } } // 输出: // User: Alice, Unread messages: 42 这些特性让人想起了 RxJava…

Kotlin 编译器插件(译)

原文:https://kt.academy/article/ak-compiler-plugin 这是《Advanced Kotlin》一书的一个章节。您可以在 LeanPub 或 Amazon 上找到它。 Kotlin 编译器是一个用于编译 Kotlin 代码的程序,同时也被 IDE 用于提供代码补全、警告等分析功能。与许多程序一样,Kotlin 编译器可以使用插件来改变其行为。我们通过扩展一个名为扩展(extension)的特殊类来定义 Kotlin 编译器插件,然后使用注册器(registrar)来注册它。每个扩展在编译器工作的特定阶段被调用,从而可能改变该阶段的结果。例如,你可以注册一个插件,当编译器为类生成父类型时被调用,从而向结果添加额外的父类型。当我们编写编译器插件时,我们受限于所支持的扩展允许我们做的事情。我们很快会讨论当前可用的扩展,但让我们先从一些关于编译器如何工作的基础知识开始。

Kotlin 协程:Job 与 SupervisorJob 的差异

我们都知道,在 Kotlin 协程中,可以使用 Job 或 SupervisorJob 来构建一个作用域(CoroutineScope): 1 2 3 4 5 6 7 8 9 10 11 // SupervisorJob val scope = CoroutineScope(SupervisorJob()) scope.launch { ... } // Job val scope = CoroutineScope(Job()) scope.launch { ... } 两者的区别似乎仅在于构造函数不同。点开源码一看,差别的确只有一个方法:

Paging3核心解析:Kotlin Flow 如何实现内存与数据双高效

Paging 库是什么? # Paging 库的核心作用是帮助 Android 应用高效地加载和展示大数据集。 人话解释: 它就像一个聪明的服务员,不会一次性把所有菜都端上来(避免内存爆炸),而是根据你的需求(分页)逐步、按需从本地数据库或网络获取一小部分数据。这样能显著降低内存压力,提供流畅的用户体验。

深入 Compose:从 setContent 到 LayoutNode 绘制原理

在之前,我一直以为 Compose 是深不可测、难以理解的东西,直到我打开一个 Compose 项目的 setContent 方法,才发现它其实并没有那么复杂。 Compose 和 XML 的不同,只是写 UI 的方式不同而已。而关键差别,就在 setContent 方法上。注意,这里的 setContent 与我们平时在 Activity 中调用的、传入一个 View 或布局 id 的 setContentView 并不是同一个方法。它只是名字相同,实际上完全是另一套实现:

Jetpack DataStore:Android应用中的现代数据存储方法

在学习 DataStore 之前,需要先了解 Kotlin 属性委托 的概念。 Kotlin 属性委托简介 # Kotlin 支持通过 属性委托 (by) 来委托属性的获取和设置逻辑。 基本规则是:如果一个对象实现了如下方法: 1 operator fun getValue(thisRef: Any?, property: KProperty<*>): A 那么就可以用 by 实例 的方式将属性委托给该对象。 示例:

Protocol Buffers编码原理

Protocol Buffers(简称 proto)是一种高效的二进制序列化协议。它的核心编码方式基于 Base-128 Varint(128 进制变长整数)。理解它的编码规则是掌握 proto 的关键。 基于 Base-128 的 Varint 编码 # Varint 是一种可变长度整数的编码方式。一个整数可以用 1~10 个字节存储,数值越小,占用的字节越少。

重新理解Android事件分发机制

在 Android 中,应用程序存在一个主线程(Main Thread),也被称为UI 线程。所有与界面相关的操作(如刷新 UI、响应点击)都必须在这个线程上完成。其实不仅是 Android,像 JavaScript 这样的前端运行环境也采取了类似的单线程设计。

WorkManager是怎样工作的

在 Android 开发中,WorkManager 是官方推荐的后台任务管理框架。它的特点是 任务可靠执行,即便应用退出或设备重启,也能保证任务最终执行。本文尝试从源码和运行机制角度梳理 WorkManager 的执行逻辑。 一个最简单的例子 # 1 2 3 4 5 6 7 8 9 10 11 12 class UploadWorker(appContext: Context, workerParams: WorkerParameters) : Worker(appContext, workerParams) { override fun doWork(): Result { // 任务逻辑 return Result.success() } } val uploadWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<UploadWorker>().build() WorkManager.getInstance(this).enqueue(uploadWorkRequest) UploadWorker:自定义任务。 enqueue():将任务加入队列。 WorkManager 是单例,内部依赖 Application 实例,并通过 Provider.Configuration 提供配置(线程池、协程上下文等)。 WorkManager 的关键点 # 基于队列思想:和常见任务队列类似,支持依赖、状态跟踪。 持久化任务信息:任务存储在数据库中,确保系统杀进程后还能恢复。 多种调度器实现:底层通过 JobScheduler、GCM 或 AlarmManager 触发执行。 任务入队:数据库层面 # 数据库核心表:WorkSpec

权力和权利

权力对应英文单词power,通过职位等方式获取到,能支配其他人,是有力量的。就比如警察差身份证。 权利对应right,法律、规定等规则授予的,在规则下能享受到的利益,像是选举权、被选举权、言论、出版、集会、结社、游行、示威、受教育(受教育总该有了吧)。