当前位置:网站首页 > Java基础 > 正文

java零基础+kotlin



1.Flow流程中为什么是【冷】的

先看一段Flow的使用代码:

 

这是Flow的最简单的使用方式,通过调用达到我所期望的结果,那么在弄清楚Flow为什么是冷的之前先看一下Flow的创建流程:

 

flow是一个高阶函数,参数类型是,FlowCollector是它的扩展或者成员方法,没有参数也没有返回值,flow()函数的返回值是Flow,具体到返回类型是,是的子类。

 

从源码中可以知道它实现了接口,这里进一步知道了间接的实现了接口。这里深入了解一下做了哪些工作,通过上面三个注释进行解释:

  • 注释1:这个就是demo中的的调用。这里我做一个猜想:的调用会触发上游Lambda中的函数的执行,然后将数据传递给;
  • 注释2:这里主要就是进行了安全检查,只是把中的参数重新进行了封装,具体的安全检查是怎么样的稍后进行分析;
  • 注释3:这里调用了这个抽象方法,而这里的具体实现是在中的,然后调用了,这里其实就是调用了中的方法,或者说调用了4次函数。

到这里的创建就结束了,那么现在来总结一下为什么是冷的:FLow之所以是冷的是因为它的构造过程,在它的构造过程中构造了一个对象但并不会触发Lambda表达式的执行,只有当 被调用后Lambda表达式才开始执行所以它是冷的。

  • 是如何进行安全检查的
 
  • 注释1:这里的参数对应的就是Flow在构造时的匿名内部类,在AS中看到的就是它;
  • 注释2:这个函数其实就是demo中用来发送数据的,这里可以理解为Flow上游发送的数据最终会传递到这个中;
  • 注释3:这里的函数中多了两个参数,其中第一个是,它是一个高阶函数,是把挂起函数的暴露出来并作为参数进行传递,第二个则是上游发送过来的数据。这里还有一个异常捕获,异常被捕获后存储在,作用是:在下游发送异常以后可以让上游感知到。下面会有一个对比;
  • 注释4:这里对当前协程上下文与之前的协程上下文进行对比,如果两者不一致就会执行,在它里面做出进一步的判断和提示;
  • 注释5:这里调用的就是下游的,也就是中的函数,这里接收的那个就是上游的传递过来的,这里可能不太好理解,我将demo中的代码换个写法就明白了:
 

两种写法的到的结果是一模一样的,第一种写法其实就是第二种写法的简写方式。

  • 注释6:这是函数引用的语法,代表了它就是 的 方法,它的类型是,而这个Function3在前面了解挂起函数原理的时候将Kotlin代码反编译后有提过类似的,Function3代表的是三个参数的函数类型。

2.FlowCollector:上游与下游之间的桥梁

Flow创建的时候构造了一个对象,间接实现了接口,因此可以直接调用终止操作符,从而获取到中的发送出来的数据。

这里其实就验证了我上面的那个猜想:下游的调用会触发上游Lambda中的函数的执行,上游的将数据传递给下游的。

那么上游和下游又是如何进行连接的呢?

先来看一段源码

 

在Flow的构造过程中构造了对象并且间接的实现了Flow,Flow中的就是终止操作,而函数中的参数中的函数则是下游用来接收上游发送数据的。

这里再来回顾一下方法中所做的事情:首先终止符的调用会触发上游Lambda中的函数执行,它将数据发送出去,然后进入到中的函数,在这个函数中又将从上游数据发送到下游中的函数中,这样就完成了连接。所以说是上下游之间的桥梁。

3.中间操作符

在前面分析Kotlin协程—Flow时我们知道在Flow的上下游之间还可以添加一些操作符(中转站)的。

这里我用之前的代码进行分析:

 

由于上面我们已经知道了上下游之间调用过程,所以这里我先用一张图来表示有了中间操作符的过程。

kotlin flow替换rxjava_kotlin

从图中可以看到当Flow中出现中间操作符的时候,上下游之间就会多出2个中转站,对于每一个中转站都会有上游和下游,并且都是被下游触发执行,也会触发自己的上游,同时还会接收来自上游的数据并传递给自己的下游。为什么会是这样一个流程,我们对中间操作符进行分析:

  • filter
 
  • 注释1、2、3:返回值均为Flow,也就是说的返回值也是,这个过程只是一个Flow的再次被封装的过程;
  • 注释4:这里会变成一个普通的Flow匿名内部类对象;
  • 注释5:这里应该比较熟悉了,完整代码应该是,根据之前的分析很容易知道这就是触发上游Lambda代码的执行,也就是执行注释6、注释7;
  • 注释6:,这里是在调用上游 Flow 的 ,触发上游的 Lambda 执行了,也就是注释5触发的Lambda的执行,然后注释 7 就会被执行;
  • 注释7:这里的中的额就是上游传递下来的值,至于怎么传递下来的就要看注释8了;
  • 注释8:首先这里有一个条件,这个判断就是传入的这个条件,符合这个条件的才会继续执行,也就是通过函数向下游传递数据。
  • map
 
  • 可以看到和前面的是一模一样的流程。java零基础+kotlin

4.上下文保护

在前面分析Kotlin协程—Flow时有提到,当时仅仅是提到了使用会使代码变得丑陋,其实还有另一层原因——如果调用改变协程上下文的话,Flow上游与下游的协程上下文就会变得不一致。在默认情况下Flow下游的协程上下文最终会成为上游的执行环境,也会变成中间操作符的执行环境,所以才让Flow本身就支持协程的「结构化并发」的特性,例如结构化取消。而加入会使Flow上游与下游的协程上下文变得不一致,它们的整体结构也会被破坏,从而导致「结构化并发」的特性被破坏,所以不要轻易使用,而Flow本身是带有上下文保护的。

Flow 源码中对于上下文的检测,称之为上下文保护,前面分析时没有深入分析,这里继续来分析一下,上下文保护是怎样的流程。

 

所以,总的来说,Flow 不允许直接使用 withContext{} 的原因,是为了“结构化并发”,它并不是不允许切换线程,而是不允许随意破坏协程的上下文。Kotlin 提供的操作符 flowOn{},官方已经帮我们处理好了上下文的问题,所以我们可以放心地切换线程。

5.总结:

1.Flow的调用过程分为三个步骤:
  • 上游的Flow创建对象,下游的Flow的函数触发上游的函数执行开始发送数据;
  • 上游的发送的数据进入到,其实上游的函数调用的就是中的函数;
  • 在中调用其实就是调用了下游的函数将数据传递给下游。
2.中间操作符:

如果有中间操作符的话,每个操作符都会有上游和下游,并且都是被下游触发执行,也会触发自己的上游,同时还会接收来自上游的数据并传递给自己的下游;

3.上下文保护:

Flow的上游和中间操作符并不需要协程作用域,所以他们都是共用Flow下游的协程上下文,也正是因为这种设计所以Flow具有天然的『结构化并发』的特点,因此Kotlin官方也限制了开发者不能随意在上游与中转站阶段改变Flow的上下文。

版权声明


相关文章:

  • Java版高级火箭基础配件2024-11-06 10:42:02
  • java基础代码的意思2024-11-06 10:42:02
  • java基础知识大全.pdf2024-11-06 10:42:02
  • java回调基础2024-11-06 10:42:02
  • java基础数字输出2024-11-06 10:42:02
  • java到基础demo2024-11-06 10:42:02
  • java基础编写工具有哪些2024-11-06 10:42:02
  • java基础运维面试题2024-11-06 10:42:02
  • 原java常见面试基础问题整理2024-11-06 10:42:02
  • java中断基础知识2024-11-06 10:42:02