class Observer {
fun change(){
println(“我是观察者”)
}
}
创建一个被观察者
class Observable {
//观察者集合
private val observerList= mutableListOf()
//订阅方法
fun subscribe(observer: Observer){
observerList.add(observer)
}
//通知所有观察者
fun notifyObserver(){
observerList.forEach {
it.change()
}
}
}
等等,你这被观察者怎么一堆东西?
我们一会再说这个里面的东西
fun main() {
//创建一个被观察者
val observable = Observable()
//创建一个观察者
val observer=Observer()
//被观察者订阅观察者
observable.subscribe(observer)
//被观察者通知观察者事情发生了改变
observable.notifyObserver()
}
看着观察者模式好像很深奥的样子,其实就是被观察者中有一个观察者的集合,订阅其实就是将观察者添加到这个集合中。
当有新消息的时候,被观察者遍历观察者集合,然后调用他们的方法即可。
RxJava中的观察者模式更简单,上面所说的可能会出现一堆的观察者,而RxJava模式中的观察者与被观察者是一对一的。怎么样,是不是更进一步降低了难度?
为了更好地理解事件驱动,我们可以用上游和下游来代替被观察者和观察者。
什么是上游和下游?
简单的来讲就是两个水管,这两个水管以一定的方式连接了起来,水管里的水从上面的水管流到了下面的水管。
也就是说上面的水管负责流水,下面的水管负责接水。水就是事件
我们一般是这么使用的
//创建上面的水管
Observable.create { emitter ->
//让水流出去
emitter.onNext(10)
} //连接两个水管
.subscribe (
//创建下面的水管
{ item ->
//上面的水流下来了,打印出来
println(item)
}
)
这是一般的使用方式,即创建一个上游,然后上游发送事件,下游去接收。
还有其他的使用方式,比如切换线程,或者对数据进行其他操作。
Observable.create { emitter ->
emitter.onNext(10)
}
.map{} //对数据进行转换
.subscribeOn()//改变上游发送的线程
.subscribe{}
这就是RxJava引以为傲的操作符,本质上这些操作符都是在上游和下游之间进行的一些操作。看完本篇你就明白操作符的本质,甚至可以自己写一些操作符了。
所以话不多说,我们开始彻底解剖RxJava,看看RxJava本质上到底是如何操作的。不用怕,没有源码,我只会用最简单的代码来实现一个具有完整功能的RxJava,让你彻彻底底的明白RxJava操作符,以及RxJava的线程切换。
从最基础开始走起,我们知道RxJava首先需要两个类,一个观察者,一个被观察者。
我们来定义这两个类
定义被观察者和观察者
//被观察者
class MlxObservable{}
//观察者
interface MlxObserver{}
有喜欢搞事的小伙伴可能会发现,这不对啊,你是不是骗我,你这个观察者不是类,而是个接口啊。
哎呀,行骗被发现了,赶紧逃~
其实也没有骗你,你想想,我们平常在使用RxJava的时候,是怎么使用的?Java中是不是需要new一个匿名内部类,Kotlin中则需要定义一个object实现接口。没错,观察者就是采用接口的。
为什么要这么做?
你想,观察者收到被观察者的通知以后是不是需要做一些改变,RxJava根本不知道你要做哪些改变啊,所以做成接口,你自己来实现。
又有人会问了,那你的意思被观察者也得做成一个接口啊,因为RxJava也不知道我要发送哪些数据啊。就像你上面的代码,被观察者不也是自己实现了一个接口?
恭喜你,都会抢答了!
没错,被观察者也应该做成接口,让开发者自己去实现发送哪些数据。RxJava也正是这样做的,不过为了感官上的统一,RxJava并没有把这个接口的名字叫做Observable
,而是叫成了ObservableOnSubscribe
。
我个人更喜欢叫ObservableOnSubscribe
为真正的被观察者。
定义一个真正的被观察者:
//真正的被观察者
interface MlxObservableOnSubscribe{}
被观察者也有了,观察者也有了,接下来我们需要思考下一步该做什么?
首先我们可以肯定的是,光有接口是不行的,我们得需要定义方法,来确定每个接口应该做什么。
那么我们应该思考这两个接口的职责。
从被观察者开始,被观察者应该有向下游发送数据的能力。什么叫向下游发送数据的能力呢?
其实很多人都会讲的很玄而又玄,其实就是持有下游的引用,调用下游的方法,简而言之就是回调。
定义上游的方法
不妨我们先定义这么一个方法:
interface MlxObservableOnSubscribe{
fun setObserver(observer:MlxObserver)//设置下游
}
我们暂且不去考虑如何去将下游添加到上游去,现在开发者只需要实现了被观察者接口,那么就会有下游的引用了,就可以调用下游的方法了。
定义下游的方法
接下来该考虑,下游该有哪些方法。熟悉RxJava的小伙伴应该知道,我们在实现观察者的时候会重写四个方法:onSubscribe,onNext,onError,onComplete。好,我们今天模仿RxJava,也来定义这四个方法:
interface MlxObserver {
fun onSubscribe()
fun onNext(item:T)
fun onError(e:Throwable)
fun onComplete()
}
可能有小伙伴对这个<T>
不是很理解了。这个是泛型,onNext中发送的数据可能是String,也可能是Int,我们无法知道具体是哪个类型,所以我们定义一个泛型,相当于占位的,只需要调用的时候指定了是哪个类型,onNext就会收到哪个类型的数据。
既然下游定义了泛型,上游也得进行相应的修改了,需要增加泛型。
interface MlxObservableOnSubscribe{
fun setObserver(observer:MlxObserver)//设置下游
}
如此以来,实现了上游接口以后,就会得到下游的对象,调用下游的四个方法即可。其实可以看到,所谓的上游,下游其实很扯淡,就是设置了一个回调而已。也没什么难的。
现在上游也有了,下游也有了,那么我们该如何给上游设置一个下游呢?
还记得我们前面虚假的那个被观察者么,对对对,就是Observable
对象。我们可以利用它来完成被观察者观察者这么一路下来的神奇操作。
RxJava中是用静态方法来完成上游的创建的,所以我们也搞个静态的。
接收上游对象
class MlxObservable{
//静态方法创建一个真正的被观察者
companion object{
fun create (source:MlxObservableOnSubscribe):MlxObservable{
return MlxObservable()
}
}
}
仔细分析一下代码,我们这里创建了一个静态方法用于接收一个真正的被观察者。返回了一个虚假的被观察者。
为什么要返回一个虚假的被观察者呢?这是因为RxJava后续的方法都不再是静态的了,所以我们需要得到一个对象。但其实更重要的原因是因为RxJava使用了装饰者模式,能够完成更好的功能拓展,各种各样的操作符也正是拓展之一。至于装饰者模式是什么,以及如何实现装饰者模式,我就不过多讲解了,看完本篇你应该会有所了解。
现在我们继续分析,我们现在返回了一个虚假的被观察者以后,需要借助这个虚假的观察者作为平台,将下游设置给上游。
接收下游对象
所以我们不妨在给虚假的被观察者也设置一个方法,这里需要注意的是我们既然返回的是类对象,那就不能在定义静态方法了。
class MlxObservable{
…
//这里接收一个下游对象,
fun setObserver(downStream: MlxObserver){
}
}
问题来了,下游是有了,上游呢?
哎呀呀,这是个问题,上面create方法确实是设置了一个上游,可是咱没变量保存啊。所以我们需要定义一个变量去保存上游。
private var source:MlxObservableOnSubscribe?=null
同时,最好在构造方法中就获得到上游:
class MlxObservable constructor(){
//上游对象
private var source:MlxObservableOnSubscribe?=null
//次构造方法,用于接收上游对象
constructor(source:MlxObservableOnSubscribe):this(){
this.source=source
}
}
既然这样,我们create方法也应修改一下:
fun create (emitter:MlxObservableOnSubscribe):MlxObservable{
return MlxObservable(emitter)
}
连接上下游
这样以来,上游下游都有了,该怎么办?当然是盘它了!在接收下游对象的时候上游肯定已经创建了,所以我们直接在这里就可以进行上下游的连接了,其实也就是将下游设置给上游
class MlxObservable{
…
//这里接收一个下游对象,
fun setObserver(downStream: MlxObserver){
source?.setObserver(downStream)
}
}
如此以来,我们RxJava就已经完成了。
什么??已经完成了,你怕不是在骗我小猫咪。
不信?我们来跑一下
MlxObservable.create(object :MlxObservableOnSubscribe{
override fun setObserver(emitter: MlxObserver) {
println(“上游发送数据:10”)
emitter.onNext(10)
}
})
.setObserver(object :MlxObserver{
override fun onSubscribe() {
println(“onSubscribe”)
}
override fun onNext(item: Int) {
println(“下游接收到数据:$item”)
}
override fun onError(e: Throwable) {}
override fun onComplete() {}
})
结果是这样的:
如何?上面的代码风格是不是已经是RxJava的风格了?不过就是变量名有点丑,人家的是subscribe
方法名,我是setObserver方法名,不过不影响使用。我们后期再把它改过来,现在先这样为了能更好的理解。
有人会问,说你这个onSubscribe方法没调用啊。也是,不过这个方法见名思意就知道是在订阅的时候会调用,不管你发不发送数据,基于此,我们可以得出结论,我们应在设置之前调用下游的这个方法。也就是虚假的被观察者在收到下游之后,立马调用下游的这个onSubscribe方法:
class MlxObservable{
…
//这里接收一个下游对象,
fun setObserver(downStream: MlxObserver){
downStream.onSubscribe()
source?.setObserver(downStream)
}
}
如此一来就可以了。最简单的RxJava即宣告完成。
下面是简单的模型
流程步骤
-
使用虚假的被观察者的静态方法create创建一个真正的被观察者对象,然后设置到虚假的被观察者的sourece对象中
-
调用虚假的被观察者的setObserver方法创建一个观察者对象,并立马调用观察者的onSubscribe方法,然后将观察者设置给被观察者
-
真正的被观察者调用观察者的方法。
-
观察者收到数据
上图中真正的被观察者有两个矩形,其实是一个对象,我只不过把它抽出来更好的表示。
可是不对啊,RxJava明明那么强大,各种操作符,线程切换你这都不行啊。
没错,接下来我们先完成一个操作符再说。emmm,哪个操作符呢?
那就用我最常用的map把,比较有代表性。
自定义Map操作符
我们继续思考,如果我们定义Map操作符,它会作用于什么地方?
显而易见的是map操作符会作用与上游和下游之间,也就是他们的中间。其实这也正是装饰者模式要做的事情,即增强对象。
我们可以采用一种方式来进行这个操作,既然它在上下游之间,我们可不可以承接上游的水,然后做了想要的变换以后,再把变换之后的水放给下游呢?
在RxJava中,create方法调用之后即可调用map方法,map方法显而易见是一个类方法,不是静态方法,所以我们先定义map方法。但我们要考虑到的是,map方法结束之后仍然可以与下游进行通信,完完全全的保持不变,所以map方法返回的必定是一个虚假的被观察者对象。
有了这些方法我们就可以写出如下代码:
class MlxObservable{
fun map():MlxObservable{}
}
但是呢,MlxObservable也就是虚假的被观察者也是有泛型的。但是它应该是T类型吗?
答案不是,为什么呢?我们首先需要知道map的作用是什么,它是转换类型的,比如说一个string类型给你转换到下游之后就变成了Int类型。所以我们不能在使用T类型了,而要转换的类型我们也不知道,所以我们再次定义一个R类型。
于是,代码变成了这样:
class MlxObservable{
fun map():MlxObservable{}
}
方法是有了,我们该如何做变换呢?
RxJava当然不知道你想如何转换,所以RxJava也定义了一个接口,让你去实现接口,并且根据接口的返回类型作为下游的类型。
不明白?
就是说,你需要自己去定义转换的规则,根据你return的类型就能知道R是什么类型了。Java接口太麻烦了,我们可以使用Kotlin的高阶函数来实现这一点。
在map中我们传入一个高阶函数作为转换规则:
fun map(func:(T)->R):MlxObservable{
}
func:(T)->R
就是一个高阶函数,它本质上和Java
的单方法的接口是一样的。这个参数func是一个函数,函数的参数是一个T类型,返回值是R类型。就这么简单。
OK,转换规则有了,我们该如何应用转换,并将转换后的数据传给下游呢?
其实很简单,熟悉装饰者模式的小伙伴应该已经知道了,不知道的也没关系。
我们接下来要做的事情就是再定义一个map自己的真正的被观察者,用于承接上游和通知下游。不明白没关系,我们先这样做,你一会就明白了。
class MlxMapObservable <T, R>():MlxObservableOnSubscribe{}
这里可能小伙伴会不明白,为什么要定义两个泛型。还记得map方法中我们又定义了一个R类型吗?为什么要定义那个R类型呢?因为已经有个T类型了,还需要一个不确定的类型,所以定义成R了。
T类型就是上游发射的类型,R类型就是要转换之后的类型。
这个类继承了MlxObservableOnSubscribe
接口,这个接口就是真正的被观察者。这么做的目的是什么呢?
其实很简单,上面说了,map既然是在上下游之间,所以它既要承接上游,又要传递数据给下游。所以它自己做一个真正的被观察者,下游去观察它,它再去观察上游,上游发送数据以后,map首先收到数据,然后应用转换规则将转换后的数据在传递给下游,也就是调用下游的方法。
还不明白?
在之前的模型中,下游是直接将自己设置给了上游,而上游是直接调用下游的方法。
现在的模型中,是下游将自己设置给了map,map又将自己设置给了上游,上游依然是调用下游的方法,不过此时上游的下游不再是真正的下游了,而成为了map,当上游调用了下游的方法其实是调用了map的方法,map方法收到消息之后,应用转换,然后再次调用真正的下游。
说的太多你们可能也不大明白,我不如写出来,你们就能立马明白了。
既然MlxMapObservable实现了MlxObservableOnSubscribe接口,那么它应该是这样
class MlxMapObservable <T, R>():MlxObservableOnSubscribe{
override fun setObserver(downStream: MlxObserver){
//此时的downStream就是真正的下游
}
}
此时我们既然有了下游,我们是不是也应该获得上游和转换规则啊。
说的真对
我们此时就来把这两个写在构造方法中:
class MlxMapObservable <T, R>(
private val source:MlxObservableOnSubscribe,
private val func:((T)->R)
):MlxObservableOnSubscribe{
override fun setObserver(downStream: MlxObserver){
//此时的downStream就是真正的下游
}
}
此时,我们上游source,转换规则func,下游downStream都有了。我们该做一些事情了,在前面说到,map应该将自己设置给上游,可是map是一个被观察者啊,上游接收的是一个观察者。
所以我们需要在map自己定义一个观察者,用于接收上游传下来的数据。
class MlxMapObservable <T, R>(
private val source:MlxObservableOnSubscribe,
private val func:((T)->R)
):MlxObservableOnSubscribe{
override fun setObserver(downStream: MlxObserver){
//此时的downStream就是真正的下游
}
class MlxMapObserver<T,R>(
private val downStream:MlxObserver,
private val func:((T)->R)
):MlxObserver{
override fun onSubscribe() {
downStream.onSubscribe()//当接收到上游传来的订阅后,将事件传递给下游
}
override fun onNext(item: T) {
//应用转换规则,得到转换后的数据
val result=func.invoke(item)
//将转换后的数据传递给下游
downStream.onNext(result)
}
override fun onError(e: Throwable) {
//将错误传递给下游
downStream.onError(e)
}
override fun onComplete() {
//完成事件传递给下游
downStream.onComplete()
}
}
}
我们定义了一个只属于map自己的观察者对象MlxMapObserver,并且在它的构造方法中,将真正的下游传给了它,在map的观察者对象中,它的所有方法将会传递给真正的下游downStream。
需要特别注意的是在onNext方法中,map方法就是在这一步应用了func的转换,将T类型的数据转换为了R类型,并将R类型的数据传递给了真正的下游downStream。
接下来的事情就很简单了,就是在setObserver方法中去承接上游,将自己的观察者对象给上游
override fun subscribe(downStream: MlxObserver){
val map=MlxMapObserver(downStream,func)//创建自己的观察者对象
source.subscribe(map)//将自己传递给上游
}
如此map就创建完了。是不是很简单呢?
其实代码很简单,但是逻辑可能有点绕,总的来说,就是创建自己的观察者对象,然后将自己的观察者对象给上游,上游传消息给下游其实是传给了map,map在自己的观察者中在对数据进行进一步的操作之后,将操作之后的数据传递给真正的下游。
map的东西创建完了,我们继续回到map方法中,map方法中已知需要返回虚假的观察者对象,而虚假的观察者对象需要一个真正的观察者对象。map就是这个真正的观察者对象,所以我们直接new一个新的虚假的观察者,并且把上游和应用规则全部传递给map,最后将map传递给这个新的虚假的被观察者。
fun map(func:(T)->R):MlxObservable{
//source就是上游真正的被观察者。
val map=MlxMapObservable(this.source!!,func)
return MlxObservable(map)
}
空口无凭,我们来实践一下,看是不是RxJava中的效果。
MlxObservable.create(object :MlxObservableOnSubscribe{
override fun setObserver(emitter: MlxObserver) {
println(“上游发送数据:10”)
emitter.onNext(10)
}
})
.map{ item->
“这是map操作符转换后的数据:$item”
}
.setObserver(object :MlxObserver{
override fun onSubscribe() {}
override fun onNext(item: String) {
println(“下游接收到数据:$item”)
}
override fun onError(e: Throwable) {}
override fun onComplete() {}
})
这是结果:
怎么样,是不是一模一样啊。
可能有小伙伴没看懂,没关系,我们再看一次map的模型示意图。
也就是说,map方法之后返回了一个新的虚假的被观察者对象,这个新的虚假的被观察者对象包含的真正的被观察者是map所构造的被观察者。
也就是说map操作符构造的对象里面,既有被观察者,也有观察者,它的被观察者用于接收下游,它的观察者用于观察上游。
这样是不是很清晰易懂了呢?map操作符的原理就是这么简单,相信小伙伴可以根据map操作符自己实现其他的操作符啦~我就不再班门弄斧了。
接下来我们开始研究RxJava所谓最高深,最难的部分。也就是RxJava是如何切换线程的。
首先RxJava切换线程是使用了两个方法,分别指定上游的线程和下游的线程。
切换上游线程具体是切换了哪个方法的线程呢?用过的小伙伴应该知道,切换的是我们构造的真正的被观察者中所实现的方法。那么这个方法是在哪里被调用的?
没错,是虚假的被观察者调用的。也就是MlxObservable的setObserver方法中调用了上游的setObserver方法。
我们现在如果要改变上游的setObserver方法所在线程,我们只能在虚假的被观察者对象中去改变它。而既然最开始创建的那个虚假的被观察者对象的方法已经写死了,所以我们可以按照map操作符的思想,我们自己去构造一个虚假的被观察者对象,在里面就像map一样承接上游,改变线程。
什么?听不明白?
map是不是承接了上游?
是的。
map怎么承接的上游?
map自己去构造了一个真正的被观察者,然后调用了上游的setObserver方法,把自己设置进去了。
你看,你也知道,map里面调用了上游的setObserver方法把。我们之前讨论了,要改变的不就是这个方法所在线程么,所以我们再定义一个类似map的操作符,然后在别的线程承接上游不就完事了么?
OK,那我们看代码如何实现把。
我们定义一个改变上游线程的操作符,既然是模仿RxJava,那我们就模仿它的方法名subscribeOn把。
改变上游线程
仿照map定义一个类,去实现真正的被观察者接口,同时为了正常的传递数据给下游,也得定义一个自己的观察者对象。
class MlxSubscribeObservable (
val source:MlxObservableOnSubscribe):MlxObservableOnSubscribe{
override fun setObserver(downStream: MlxObserver){
val observer=MlxSubscribeObserver(downStream)
}
class MlxSubscribeObserver(val downStream:MlxObserver):MlxObserver{
…
}
}
再仿照map定义一个成员方法:
fun subscribeOn():MlxObservable{
val subscribe=MlxSubscribeObservable(this.source!!)
return MlxObservable(subscribe)
}
好了,一切都没问题了。可是这也没有改变上游线程啊,甚至setObserver方法中你都没有承接上游呢。
是这样的,我们需要思考线程的创建与销毁是十分消耗性能的。我们不能单纯的new一个Thread出来,那样性能开销十分大,所以针对线程问题,我们需要线程复用,而线程复用首先应该能想到我们要使用线程池。RxJava也正是这样做的。
那么问题来了,RxJava切换线程的时候可是有好几种线程呢,什么IO,什么computation的,还有Android主线程呢。
其实啊,除了Android主线程以外,其他的都是线程池里面抽出来的,区别只是线程池的策略不同而已。比如IO使用的是CachedThreadScheduler线程池,这个线程池是带缓存的,也就是说可以复用的线程池。简单这么理解就好,线程池和线程同步等等问题,我随后专门开出一个系列来讲,可以关注一下我到时候收看。
所以针对各种各样不同的线程操作,我们需要一个类来专门管理这些线程。RxJava也是这么做的,它取的名字叫Schedulers,所以我们也起这个名字
定义线程池管理类
class Schedulers(){}
光有这么一个类可不行,我们得管理线程池,既然要管理线程池那最起码得有线程池把。所以我们在这个里面定义一个线程池对象,线程池那么多,我们就只定义一个IO线程池把。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://i-blog.csdnimg.cn/blog_migrate/85d590a9cca0daa1967b30b362ba7cec.jpeg)
总结
现在新技术层出不穷,如果每次出新的技术,我们都深入的研究的话,很容易分散精力。新的技术可能很久之后我们才会在工作中用得上,当学的新技术无法学以致用,很容易被我们遗忘,到最后真的需要使用的时候,又要从头来过(虽然上手会更快)。
我觉得身为技术人,针对新技术应该是持拥抱态度的,入了这一行你就应该知道这是一个活到老学到老的行业,所以面对新技术,不要抵触,拥抱变化就好了。
Flutter 明显是一种全新的技术,而对于这个新技术在发布之初,花一个月的时间学习它,成本确实过高。但是周末花一天时间体验一下它的开发流程,了解一下它的优缺点、能干什么或者不能干什么。这个时间,并不是我们不能接受的。
如果有时间,其实通读一遍 Flutter 的文档,是最全面的一次对 Flutter 的了解过程。但是如果我们只有 8 小时的时间,我希望能关注一些最值得关注的点。
(跨平台开发(Flutter)、java基础与原理,自定义view、NDK、架构设计、性能优化、完整商业项目开发等)
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-DKLosmp9-1712423789634)]
[外链图片转存中…(img-RrP9tJ2z-1712423789635)]
[外链图片转存中…(img-aADL2QMd-1712423789635)]
[外链图片转存中…(img-sCVlkxox-1712423789635)]
[外链图片转存中…(img-YGE63Eyz-1712423789635)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://i-blog.csdnimg.cn/blog_migrate/85d590a9cca0daa1967b30b362ba7cec.jpeg)
总结
现在新技术层出不穷,如果每次出新的技术,我们都深入的研究的话,很容易分散精力。新的技术可能很久之后我们才会在工作中用得上,当学的新技术无法学以致用,很容易被我们遗忘,到最后真的需要使用的时候,又要从头来过(虽然上手会更快)。
我觉得身为技术人,针对新技术应该是持拥抱态度的,入了这一行你就应该知道这是一个活到老学到老的行业,所以面对新技术,不要抵触,拥抱变化就好了。
Flutter 明显是一种全新的技术,而对于这个新技术在发布之初,花一个月的时间学习它,成本确实过高。但是周末花一天时间体验一下它的开发流程,了解一下它的优缺点、能干什么或者不能干什么。这个时间,并不是我们不能接受的。
如果有时间,其实通读一遍 Flutter 的文档,是最全面的一次对 Flutter 的了解过程。但是如果我们只有 8 小时的时间,我希望能关注一些最值得关注的点。
(跨平台开发(Flutter)、java基础与原理,自定义view、NDK、架构设计、性能优化、完整商业项目开发等)
[外链图片转存中…(img-Bdxj2D9F-1712423789636)]