Android-Flow 使用和源码解析

Android面试指南—Kotlin Flow篇 在Kotlin官网中定义中是这么说的:在协程中,与仅返回单个值的挂起函数相反,Flow可按顺序发出多个值, 它以协程为基础构建,可提供多个值,从概念上来讲,Flow是可通过异步方式进行计算处理的一组数据序列,所发出值的类型必须相同。总结一下,我们可以将Flow定义为具有多个异步计算值的协程。它是可以异步计算的数据流,用于按顺序发送多个值。发出的数据必须是同一类型,并且也是按顺序发出的,Flow使用挂起的函数以异步方式消费和生产。 阅读详情

概述

数据流以协程为基础构建,可提供多个值。从概念上来讲,数据流是可通过异步方式进行计算处理的一组数据序列。所发出值的类型必须相同。例如,Flow 是发出整数值的数据流。

在协程中,与仅返回单个值的挂起函数相反,数据流可按顺序发出多个值。

数据流包含三个实体:

  • 提供方会生成添加到数据流中的数据。得益于协程,数据流还可以异步生成数据。
  • (可选)中介可以修改发送到数据流的值,或修正数据流本身。
  • 使用方则使用数据流中的值。

在这里插入图片描述

1.使用

1.1 创建数据流

创建数据流有两种常用方式: 第一就是试用数据流构建函数, 第二就是利用扩展方法将原有类型转换成Flow

使用数据构建函数

这里比较常用的函数是 flow() 和 flowOf()

val f = flow {
    emit(1)
}
val f2 = flowOf("abc")
val f3 = flowOf("A", "B", "C")

其实 flowof() 是简化版的 flow() 函数,内部帮我们调用了 emit()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JEWWqcWq-1670402003040)(/Users/apple/Downloads/job_files/flow/Xnip2022-11-20_00-25-28.jpg )]

注意:

使用 flow 构建器时,提供方不能提供来自不同 CoroutineContext 的 emit 值。因此,请勿通过创建新协程或使用 withContext 代码块,在不同 CoroutineContext 中调用 emit 可以使用 flowOn 或者 callbackFlow。

使用扩展方法

扩展方法是 kotlin 标准库中提供的 asFlow() . 目前基本上覆盖了基本数据类型、lambda、及挂起函数等

下面看一下具体如何使用:

普通lambda 表达式
fun testAsFlow1(blacking: () -> String) {
    val flow = blacking.asFlow()
}
挂起函数
suspend fun testAsFlow2(blacking: suspend () -> String) {
    val flow = blacking.asFlow()
}

或者以下方式:

suspend fun remoteCall(): String = withContext(Dispatchers.IO) {
    return@withContext "ABC"
}
fun remoteCallFlow(): Flow<String> = ::remoteCall.asFlow()
基本数据类型

kotlin 标准库中提供了基本数据类型相关扩展方法,其中 Map类型不能直接使用asFlow() 需要转换成其支持的类型,再使用 asFlow().

fun testAsFlow3() {

    // Range 类型
    val flow1 = IntRange(1, 100).asFlow()
    val flow2 = LongRange(1L, 1000L).asFlow()
    
    // Array 类型
    val flow3 = intArrayOf(1, 2, 3).asFlow()
    val flow4 = longArrayOf(1L, 2L, 3L).asFlow()
    val flow5 = arrayOf("A", "B", "C").asFlow()
    
    // Sequence 类型
    val flow6 = sequenceOf("X", "Y", "Z").asFlow()
    
    // Iterable 类型
    val flow7 = listOf(1, 2, 3).asFlow()
    val flow8 = setOf("E", "G", "C").asFlow()
    
    // Iterator 类型
    val flow9 = iterator<Int> {}.asFlow()
    
    // Map 类型
	val map = hashMapOf(Pair("A", 1), Pair("B", 2))
	
	val flow10 = map.asIterable().asFlow()
	val flow11 = map.asSequence().asFlow()
	val flow12 = map.iterator().asFlow()
}

1.2 修改数据流

可以利用中间运算符在不使用值的情况下修改数据流。中间运算符可以接连应用,形成链式运算,在数据项被发送到数据流时延迟执行。

其中操作符还分为三大类:

  1. 创建操作符
  2. 中间操作符
  3. 末端操作符

在这里插入图片描述
关于Flow 操作符可以查看这篇文章 Flow 操作符大全

1.3 收集数据

使用 collect 进行收集数据

val f = emptyFlow<Int>()
    .collect {
        // ignore 
    }

2. 冷流 与 热流

所谓 冷流 和 热流 是根据数据收集时是否出发提供方代码而定义的。

冷流: 即 收集数据时才触发提供方代码,即为冷流。我们使用 flow 或 flowOf 创建的 Flow 都是冷流。

热流: 数据收集时数据已经存在,不需要触发提供方代码,这样的流即为 热流。StateFlow 、SharedFlow 这两个都是热流。

StateFlow

StateFlow 是热数据流:从数据流收集数据不会触发任何提供方代码。StateFlow 始终处于活跃状态并存于内存中,而且只有在垃圾回收根中未涉及对它的其他引用时,它才符合垃圾回收条件。

StateFlow 是一个状态容器式可观察数据流,可以向其收集器发出当前状态更新和新状态更新。

在 Android 中,StateFlow 非常适合需要让可变状态保持可观察的类。

// StateFlow
private val _uiStateMutableStateFlow: MutableStateFlow<UIState> = MutableStateFlow(UIState.INITIAL)
val uiStateStateFlow: StateFlow<UIState> = _uiStateMutableStateFlow

StateFlow、Flow 和 LiveData

StateFlow 和 LiveData 具有相似之处。两者都是可观察的数据容器类,并且在应用架构中使用时,两者都遵循相似模式。

StateFlow 和 LiveData 的行为确实有所不同:

  1. StateFlow 需要将初始状态传递给构造函数,而 LiveData 不需要。
  2. 当 View 进入 STOPPED 状态时,LiveData.observe() 会自动取消注册使用方,而从 StateFlow 或任何其他数据流收集数据的操作并不会自动停止。

SharedFlow

SharedFlow 是 StateFlow 的可配置性极高的泛化数据流, StateFlow 本身继承于 SharedFlow。

private val _uiStateSharedFlow: MutableSharedFlow<UIState> = MutableSharedFlow(1, 3, BufferOverflow.DROP_OLDEST)
val uiStateSharedFlow: SharedFlow<UIState> = _uiStateSharedFlow

创建 SharedFlow 需要三个参数:

  • replay : 重新给订阅者发送之前值的数量,默认是 0
  • extraBufferCapacity : 缓冲区数量, 默认为 0 。不包含 replay 配置数量
  • onBufferOverflow : 缓冲区数据存满发送时策略,BufferOverflow 类型枚举,默认值 BufferOverflow.SUSPEND。

BufferOverflow 有三种策略:

  1. SUSPEND : 当缓冲区已满时,正在发送或发出值的上游被挂起。
  2. DROP_OLDEST : 缓冲区满时删除缓冲区中最旧的值,将新值添加到缓冲区,不进行挂起。
  3. DROP_LATEST :缓冲区满时删除立即添加到缓冲区的最新值(以便缓冲区内容保持不变),不进行挂起。

冷流和热流转换

shareIn

将普通flow 转化为 SharedFlow , 其有三个参数

  • scope: CoroutineScope 开始共享的协程范围
  • started: SharingStarted 控制何时开始和停止共享的策略
  • replay: Int = 0 发给 新的订阅者 的旧值数量

其中 started 有一些可选项:

  • Eagerly : 共享立即开始,永不停止
  • Lazily : 当第一个订阅者出现时, 永不停止
  • WhileSubscribed : 在第一个订阅者出现时开始共享,在最后一个订阅者消失时立即停止(默认情况下),永久保留重播缓存(默认情况下)

WhileSubscribed 具有以下可选参数:

  • stopTimeoutMillis — 配置最后一个订阅者消失到协程停止共享之间的延迟(以毫秒为单位)。 默认为零(立即停止)。
  • replayExpirationMillis - 共享的协程从停止到重新激活,这期间缓存的时效
val shareIn = flowOf(1, 2, 3)
    .shareIn(viewModelScope, SharingStarted.Eagerly, 10)
stateIn

将普通flow 转化为 StateFlow 。 其有三个参数:

  • scope - 开始共享的协程范围
  • started - 控制何时开始和停止共享的策略
  • initialValue - 状态流的初始值
val stateIn = flowOf(1)
    .stateIn(viewModelScope, SharingStarted.Lazily, 1)

3. Android 中使用Flow

由于 Flow 流的发送和接收只是在 协程生命周期中,而没有和 Android 的一些生命周期组件,如 Activity/Fragment 绑定,所以 Android 推出了与 Lifecycle 生命周期组件相关的库和扩展方法,以方便我们在合理的生命周期内收集数据。

repeatOnLifecycle

repeatOnLifecycle 是 Lifecycle 生命周期组件,扩展方法。用于在合适的生命周期期间接收 flow 数据 。

lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        uiStateFlow.collect { uiState ->
               updateUi(uiState)
          }
    }
}
源码分析
public suspend fun Lifecycle.repeatOnLifecycle(
    state: Lifecycle.State,
    block: suspend CoroutineScope.() -> Unit
) {
   // 如果 Lifecycle 组件处于 INITIALIZED 则直接抛出错误
    require(state !== Lifecycle.State.INITIALIZED) {
        "repeatOnLifecycle cannot start work with the INITIALIZED lifecycle state."
    }

    // 如果 Lifecycle 组件处于 DESTROYED 停止
    if (currentState === Lifecycle.State.DESTROYED) {
        return
    }

    // 开启一个协程,并切换到主线程中,后续所有代码均运行在此线程中
    coroutineScope {
        withContext(Dispatchers.Main.immediate) {
            // 再次检查当前生命周期状态,如果是 DESTROYED 则取消
            if (currentState === Lifecycle.State.DESTROYED) return@withContext

		    // 协程
            var launchedJob: Job? = null

            // 生命周期观察回调
            var observer: LifecycleEventObserver? = null
            try {
                // 创建一个协程,这个协程除非生命周期结束或者被取消,否则一直处于被挂起状态
                suspendCancellableCoroutine<Unit> { cont ->
                    // 检查生命周期执行区间
                    val startWorkEvent = Lifecycle.Event.upTo(state)
                    val cancelWorkEvent = Lifecycle.Event.downFrom(state)
                    
                    val mutex = Mutex()
                    // 创建 Lifecycle 生命周期观察者
                    observer = LifecycleEventObserver { _, event ->
                        if (event == startWorkEvent) {
                            // Launch the repeating work preserving the calling context
                            launchedJob = this@coroutineScope.launch {
                                // 重新开启协程执行,lambda 方法块
                                mutex.withLock {
                                    coroutineScope {
                                        block()
                                    }
                                }
                            }
                            return@LifecycleEventObserver
                        }
                        // 取消协程
                        if (event == cancelWorkEvent) {
                            launchedJob?.cancel()
                            launchedJob = null
                        }
                        // 关闭外部 协程,内部使用状态机
                        if (event == Lifecycle.Event.ON_DESTROY) {
                            cont.resume(Unit)
                        }
                    }
                    this@repeatOnLifecycle.addObserver(observer as LifecycleEventObserver)
                }
            } finally {   // 取消协程 & 移除观察者
                launchedJob?.cancel()
                observer?.let {
                    this@repeatOnLifecycle.removeObserver(it)
                }
            }
        }
    }
}

以上就是 repeatOnLifecycle 方法的源码,注释比较详细,总的来说,就两点:

  1. 开启协程,创建 Lifecycle 观察者,在符合生命周期期间进行执行外部代码块
  2. 生命周期结束之后,取消协程、移除观察者等

需要注意的是:

在调用 repeatOnLifecycle() 时 state 不能传入 Lifecycle.State.INITIALIZED 和 Lifecycle.State.DESTROYED

另外 LifecycleOwner 也有同名扩展方法,更加方便使用,其内部也是调用 Lifecycle的扩展方法。

public suspend fun LifecycleOwner.repeatOnLifecycle(
    state: Lifecycle.State,
    block: suspend CoroutineScope.() -> Unit
): Unit = lifecycle.repeatOnLifecycle(state, block)
flowWithLifecycle

flowWithLifecycle 是 Flow 的扩展方法,为方便Flow 使用,其内部也是通过 Lifecycle 的 repeatOnLifecycle() 实现,但还是有点区别。

使用:

lifecycleScope.launch {
    flow.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
    	 .filter {  }
         .map {  }
         .collect {
             // Consume flow emissions
     }
}

从使用上看 flowWithLifecycle() 更像是一个操作符,因为他返回的还是 Flow 。还可以继续使用其他操作符,最后再使用 末端操作符来接收值。

public fun <T> Flow<T>.flowWithLifecycle(
    lifecycle: Lifecycle,
    minActiveState: Lifecycle.State = Lifecycle.State.STARTED
): Flow<T> = callbackFlow {
    lifecycle.repeatOnLifecycle(minActiveState) {
        this@flowWithLifecycle.collect {
        	  // 将值重新发送到 flow 中
            send(it)
        }
    }
    // 关闭 flow 
    close()
}

flowWithLifecycle 的源码比较简单,内部创建一个 callbackFlow 用于将 ifecycle.repeatOnLifecycle() 收集结果,再发送至 Flow 中,这样下游依然能使用 collect 来收集上游的结果。最后在 协程关闭时将 flow 关闭掉 。

参考

https://developer.android.com/kotlin/flow?hl=zh-cn

https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/

https://kotlinlang.org/docs/flow.html

Android DataStore 使用详解 Jetpack DataStore 是一种数据存储解决方案,允许您使用协议缓冲区存储键值对或类型化对象。DataStore 使用 Kotlin 协程和 Flow 以异步、一致的事务方式存储数据。 阅读详情

相关推荐

Kotlin:Flow 全面详细指南,附带源码解析。,Android框架

其实很简单就下面这张图,含概了Android所有需要学的知识点,一共8大板块:架构师筑基必备技能Android框架体系架构(高级UI+FrameWork源码)360°Androidapp全方位性能调优设计思想解读开源框架NDK模块开发移动架构师专题项目实战环节移动架构师不可不学习微信小程序混合开发的flutterAndroid学习的资料我呢,把上面八大板块的分支都系统的做了一份学习系统的资料和视频,大概就下面这些,我就不全部写出来了,不然太长了影响大家的阅读。

2401_84123171的博客 1324

【Android】之 Flow 的使用和浅析

Google 推荐在 MVVM 架构中使用 Kotlin Flow,可见其发展前景是相当好的。Kotlin Flow 可以用于替换 Rxjava,也可以用于替换 LiveData,功能十分强大,它是 Kotlin 协程库提供的一部分功能,因此,如果我们项目中已经引用了 Kotlin 协程,则不需要额外引入 Flow 相关的依赖。在协程中,挂起函数最多仅能返回一个值,而数据流 Flow 可按顺序发出多个值,例如,我们可以通过数据流从数据库中实时接收更新。数据流使用挂起函数通过异步方式生成和使用值,也就是说,数

yang553566463的博客 1万+

Kotlin协程之flow工作原理

概述 最近想学习一下 Kotlin 中 flow 的用法, Google 上搜了搜发现很多比较 RxJava 和 flow 的文章,其实我在实际业务中从来没有用过 RxJava, 倒不是因为它不好,而是…我一直傻傻不太会用 RxJava 的操作符,看不太懂,又一直没花时间(懒惰)去研究它那些操作符的原理,就一直不怎么敢用。这次看到了 flow, 想着还是先去了解了解它内部几个操作符的原理吧,不然用起来总是不太踏实。 需要注意的是 Flow 需要在协程中使用, 因此配合协程,可以方便地切线程。分析 flow

bugmiao的博客 2661

Android—Kotlin-Flow异步流超详细讲解

前言 本来这一篇准备写Jetpack对应的paging的,但在整理资料的时候,发现Kotlin还有Flow未讲解,这个也是一大重点,因此本篇将对Flow进行详解!

qq_30382601的博客 6307

Retrofit+Flow网络请求与Android网络请求的演变

Retrofit网络请求我想大家都不陌生,今天我就来梳理一下技术是如何一步一步进步,逼格是如何一步一步变高的。

跟着哆啦学Android 699

在Android中使用Flow获取网络连接信息

如果你是一名Android开发者,你可能会对这个主题感到有趣。考虑到几乎每个应用程序都需要数据交换,例如刷新动态或上传/下载内容。而互联网连接对此至关重要。但是,当用户的设备离线时,数据如何进行交换呢?我们如何确定设备重新连接到互联网,以便我们可以提供他们请求的数据?本文将指导您了解如何读取和监听用户的网络状态。

虎哥LoveDroid 2414

Flow:Android UI 状态管理和导航框架

在构建复杂的移动应用时,管理 UI 状态和导航逻辑可能会变得非常复杂。Flow 是 Square 开源的一个框架,它旨在简化这一过程,让开发者能够更容易地命名、导航和管理 UI 状态。

Unity打怪升级 3177

Kotlin 协程之 Flow 的理解使用及源码解析

Kotlin Flow 冷热流对比与使用 本文对比了Kotlin中Channel(热流)和Flow(冷流)的核心特性与使用场景

喻志强的博客 1210

Kotlin协程之flow工作原理,想提高开发效率的必看

safeCollector.releaseIntercepted() } } public abstract suspend fun collectSafely(collector: FlowCollector) } 可以看到 collect 方法中通过 collector 封装了一个 SafeCollector 对象,并以其为参数执行了 SafeFlow.collectSafely 方法,而 collectSafely 方法只是执行了 block 代码块(collector.block()),它是一个扩展

m0_66264938的博客 828

C#实战:5分钟搞定Modbus RTU通讯(基于NModbus4库)

本文详细介绍了如何使用C#和NModbus4库快速实现Modbus RTU通讯,包括环境配置、核心功能实现、性能优化及常见问题排查。通过代码示例和实用技巧,帮助开发者高效完成工业自动化设备的数据采集与控制任务。

weixin_30689307的博客 468

直流有刷电机控制 - 驱动电路(二)

1.如图所示为最常见的推挽驱动电路,我附加了具有正反转功能的电机驱动控制,正反转是由两个继电器组成。使用推挽电路来驱动NMOS管时充电电流和放电电流都很大,因此NMOS管导通快,关断也快,而且NMOS温度不会很高。下面来介绍一下该电路的原理。(1)PWM_MCU是由单片机给出的PWM波信号,该信号是由一些列高低电平的方波构成。当信号为高电平的时候Q3导通,经过R47再到Q5的g极,此时mos导通,如果是K1闭合是正转那么K2闭合就是反转。(2)当PWM低电平时使得Q3关断,Q6导通。

u011030644的博客 4720

花式Kotlin协程用法 - Paging 3源码进阶

paging3

QG 779

鸿蒙读书笔记1:《鸿蒙操作系统设计原理与架构》

GUI、 语 音 控 制 方 式 的 VUI(Voice User Interface, 语 音 用 户 界。电话、多媒体、DFX、MSDP(Multimodal Sensor Data Platform,多。面)、手势/姿态控制的CVUI(Computer Vision User Interface,计算。KAL(Kernel Abstract Layer,内核抽象层)通过屏蔽多内核差异,JavaScript、C、C++等多语言的用户程序开发框架,以及UI框架、

jackyrongvip的专栏 2451

01-16-12 观察者模式 - LiveData与ContentObserver的观察者实现

本文分析了Android中的观察者模式实现,重点介绍了LiveData和ContentObserver两个典型案例。观察者模式通过Subject-Observer机制实现对象间的一对多通知,核心是解耦被观察者和观察者。LiveData源码展示了生命周期感知的观察者实现,包括注册观察者(observe/observeForever)、移除观察者(removeObserver)、值更新(setValue/postValue)和通知机制(dispatchingValue)。其特色在于通过LifecycleBoun

时代我西的博客 343

Gamma变换算法之Matlab&FPGA实现

Gamma映射原理 什么是Gamma曲线 人眼的感光与光强并不是呈线性关系的,而是呈非线性关系(指数型关系,如下图左-曲线。在低照度下,人眼更容易分辨出亮度的变化,随着照度的增加,人眼不易分辨出亮度的变化。而图像传感器与输入光强呈线性关系(如下图左-直线)。从图中可见,当传感器感光在20%左右时,人眼感光响应达到了50%,人眼对低照度的变化更为敏感。从下图右侧可见,Reference Tone为人眼感光50%的亮度,而传感器在感光50%时则相对暗的多(见Select,近似中性灰)。这种将原始图像通过映射操

CrazyBingo的博客 7407

Chrome下载B站视频字幕的插件

本文主要介绍了Chrome下载B站视频字幕的插件,希望能对使用Chrome的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 3万+

Kotlin:Flow 全面详细指南,附带源码解析。(1),7天拿到阿里Android岗位offer

外链图片转存中…(img-5oizPxgS-1712780839991)][外链图片转存中…(img-bOpaqlwS-1712780839992)][外链图片转存中…(img-uQJnVFsO-1712780839992)][外链图片转存中…(img-bFuO5Mv5-1712780839992)][外链图片转存中…(img-1J3vdJhZ-1712780839992)]

2401_84123094的博客 1041

Spring AI从入门到精通:构建智能Spring应用的全面指南

随着人工智能技术的快速发展,将大语言模型(LLM)与企业应用集成已成为趋势。Spring AI作为Spring官方推出的AI集成框架,为开发者提供了便捷、标准化的方式来构建智能应用。本文将从基础概念到高级应用,全面介绍Spring AI的核心功能与实践技巧。Spring AI 是 VMware 于 2023 年推出的开源框架,旨在简化大语言模型(LLM)与 Spring 应用的集成。它提供了统一的 API 抽象,支持多种 LLM 供应商,包括 OpenAI、Azure OpenAI、Hugging Face

qq_36929638的博客 1069

Kotlin Flow 深度教程 - 从入门到精通

Flow是 Kotlin 协程提供的一种冷流(Cold Stream),用于异步返回多个值。/*** Flow 接口的核心定义* 这是一个异步数据流,可以顺序地发射值*//*** collect 是 Flow 唯一的抽象方法* 接收一个 FlowCollector 来收集值* 这个方法是挂起的,会在所有值发射完成后返回*//*** FlowCollector 是值的接收者*//*** 收集/接收单个值* 这个方法也是挂起的*/Flow 本身只是一个接口,定义了如何收集数据。

qq_33942765的博客 1796

YOLOv8改进,YOLOv8添加DCNv4可变性卷积(windows系统成功编译),全网最详细教程

DCNv4通过两项关键增强解决了其前身DCNv3的局限性:1. 移除空间聚合中的softmax归一化,以增强其动态特性和表达能力;2. 优化内存访问以最小化冗余操作,从而加速计算。这些改进使得DCNv4相比DCNv3显著加快了收敛速度,并且处理速度大幅提升,前向传播速度超过三倍。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 6470

【Neo4j × Python】基于知识图谱的电影问答系统(含问题记录与解决)附:源代码(含Bug解决)

此前,曾介绍过Neo4j的一些基础知识,本篇将在PyCharm中与Neo4j建立关联,从0到1实现一个基于知识图谱的电影问答系统,实现过程中,没有一帆风顺,而是遇到了一些问题,因此也包含问题的记录与解决。

追光者♂:记录、分享、总结、提升,现象级专栏《Python从入门到人工智能》作者,无惧黑暗,坚信曙光 3167

「正确」的使用Kotlin Flow进行搜索优化(1)

我最近从朋友那里收集到了2020-2021BAT 面试真题解析Android 基础、Java 基础、Android 源码相关分析、常见的一些原理性问题等等,可以很好地帮助大家深刻理解Android相关知识点的原理以及面试相关知识。这份资料把大厂面试中常被问到的技术点整理成了PDF,包知识脉络 + 诸多细节;还有 高级架构技术进阶脑图 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。这里也分享给广大面试同胞们,希望每位程序猿们都能面试成功~点击直达GitHub。

m0_60388292的博客 1124

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Kotlin:Flow 全面详细指南,附带源码解析。(1)

感觉现在好多人都在说什么安卓快凉了,工作越来越难找了。又是说什么程序员中年危机啥的,为啥我这年近30的老农根本没有这种感觉,反倒觉得那些贩卖焦虑的都是瞎j8扯谈。当然,职业危机意识确实是要有的,但根本没到那种草木皆兵的地步好吗?Android凉了都是弱者的借口和说辞。虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。

2401_84121935的博客 718

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Kotlin协程之flow工作原理(1),Android开发经验的有效总结

首先看一下 Flow 接口的源码,内部只有一个 collect 方法:// 是一个 suspend 方法,意味着会挂起当前协程// 数据的发射方。

969

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

Android开发者快速上手Kotlin(八) 之 协程官方框架Channel、Select和Flow的使用

接《Android开发者快速上手Kotlin(七) 之 协程官方框架初步》文章继续。 14 协程官方框架Channel、Select和Flow 14.1 Channel Channel我们一般翻译成叫通道,用于多个协程之间进行数据相互传输,多个协程允许发送和接收同一个Channel的数据。它类似于线程任务队列BlockingQueue + 挂起函数的支持,因为如果通道支持缓存的话,那么它实质上就是一个队列。我们发消息和接收消息都是挂起函数,挂起取决于Channel的状态,如果Channel已经满了.

子云心的博客 2936

为什么你的Flow.collectOnLifecycle不生效?——Android开发者的5个盲点解析

解决Flow.collectOnLifecycle不生效的常见问题,深入剖析Kotlin Flow实践中的5大盲点。涵盖生命周期绑定、协程作用域管理等关键场景,揭示正确使用collectOnLifecycle的核心方法与最佳实践,提升UI数据流稳定性,值得收藏。

ProceNest的博客 863
上一篇: Jetpack-Lifecycle组件-SafeIterableMap解析
下一篇: Android Flow 操作符大全
Bumblebee1999
博客等级 码龄11年 5粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值