rxjava+LiveData VS 协程+flow, +Retrofit+Okhttp3,两种方案的不同使用.

1.前提

作者最近在学习kotlin,刚看到协程,又看到了flow.发现这两个东西是可以完成取代rxjava和LiveData的。然后我就来找不同,一起体验一下两种东西加在一起的不同. 当然了,如果你使用的是JAVA,就老老实实用RXJAVA+LiveData把。 协程是Android里面kotlin特有的。

rxjava+LiveData VS 协程+flow, +Retrofit+Okhttp3,两种方案的不同使用._第1张图片

2.对比

是骡子是马,拉出来遛一遛,咋们来稍微对比一下这两种不同东西.
基础的概念我就不放了,大家可以先去了解一下,我这里只提一些重要的。

RXJAVA:链式编程,切换线程贼方便.实现异步操作,
存在的缺点:学习成本较高,操作符比较多,回调多,但比较灵活

协程:线程中的“线程”,实现异步操作,切换线程也方便,结构式并发.

LiveData:响应式编程,跟随生命周期。
存在的缺点:无法在io线程中setvalue,而postvalue则会存在丢数据的情景

Flow:冷流一对一,statteflow热流和liveData相似,但仍然可以在io线程中发送数据.有背压功能

3.分析

如果你仍然在用Java开发Android请尽情进行改变吧,kotlin可太香了!学到了kotlin,那么特有的协程和Flow你不用它,是不是有点浪费了.
我们可以看到,我们常用RXJAVA中的异步操作,链式编程,切换线程,在协程中也是可以完美实现的,在写代码的时候让人方便阅读(可以往下面看).
而LiveData中最大的坑postValue可以通过stateflow弥补,那么我们使用Flow可没有什么太大的问题.
别说那么多,上代码就更直观的看到问题出现在哪里了.
rxjava+LiveData VS 协程+flow, +Retrofit+Okhttp3,两种方案的不同使用._第2张图片

4.代码对比

我们来用RXJAVA写一段异步操作并且在Fragment中进行监听响应是什么样的一个效果.
0.Fragment

  override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    val retrofitViewModel = ViewModelProvider(requireActivity()).get(retrofitViewModel::class.java)
  retrofitViewModel.TextLiveData.observe(this,{
            Log.d(TAG, "onCreate: $it")
        })
 retrofitViewModel.viewModelScope.launch {
            retrofitViewModel.TextFlow.collect {
                Log.d(TAG, "onCreate:我们来看一下订阅后的情况: $it")
                //Add ViewMethod
            }
        }
}

1.RXJAVA+LiveData+viewModel

class retrofitViewModel : ViewModel() {
	val TextLiveData by lazy {
        MutableLiveData<Int>().also {
            Observable.create(ObservableOnSubscribe<Int?> { emitter ->
                emitter.onNext(1)
                emitter.onComplete()
            }).subscribeOn(Schedulers.io())
                    .subscribe(object : Observer<Int?> {
                        override fun onSubscribe(d: Disposable) {
                            println("onSubscribe=$d")
                        }


                        override fun onError(e: Throwable) {
                            println("onError=$e")
                        }

                        override fun onComplete() {
                            println("onComplete")
                        }

                        override fun onNext(value: Int?) {
                            //it.value = value 这样是不行的
                            it.postvalue(value)
                        }
                    })

        }
    }
}

2.协程+StateFlow
class retrofitViewModel : ViewModel() {

  val TextFlow by lazy {
        MutableStateFlow(0).also {
            viewModelScope.launch(Dispatchers.IO) {
                it.value = 1
            }
        }
    }

我们来看一下结果
rxjava+LiveData VS 协程+flow, +Retrofit+Okhttp3,两种方案的不同使用._第3张图片
可以明显的看到,两个东西实现了同一个功能,异步设置某值使得Fragment可以监听到值的改变并且进行响应.但是在代码量上的区可大了.而且StateFlow是肯定有初始值的

我们再来看一下在协程和Rxjava中并发中的不同

RXJAVA使用flapMap进行并发:

fun RxJavaParallel(){
        val list = Arrays.asList(1,2,3)
        Observable.fromIterable(list).flatMap{integer->
            Log.d(TAG, "RxJavaParallel: TASK_$integer Start:"+System.currentTimeMillis())

            getObservable(integer)
        }.subscribe(object : Observer<String?> {
            override fun onSubscribe(d: Disposable) {
                println("onSubscribafgsdfgre=$d")
            }


            override fun onError(e: Throwable) {
            }

            override fun onComplete() {

            }

            override fun onNext(value: String?) {
                //TODO("Not yet implemented")
                Log.d(TAG, "onNext: 接收发送的任务:$value")
            }
        })
    }

    fun getObservable(integer: Int): Observable<String?>? {
        return Observable.create(ObservableOnSubscribe<String?> { emitter ->
            emitter.onNext("第" + integer + "圆球的第1个棱形任务")
            Thread.sleep((1 * 1000).toLong())
            emitter.onComplete()
            Log.d(TAG, "RxJavaParallel: TASK_ finish:"+System.currentTimeMillis())

        }).subscribeOn(Schedulers.newThread())
    }

协程并发:
(结构化并发的话使用async),这里的并发只是不需要等待返回值所以直接使用launch
结构化并发是当其中任何一个失败后, 应该取消另一个协程的计算. 这就是所谓的


    fun CoroutineParallel(){
        viewModelScope.launch {
            launch {
                Log.d(TAG, "CoroutineParallel: TASK_1 Start:"+System.currentTimeMillis())
                delay(1000)
                Log.d(TAG, "CoroutineParallel: TASK_1 Finish:"+System.currentTimeMillis())
            }
            launch {
                Log.d(TAG, "CoroutineParallel: TASK_2 Start:"+System.currentTimeMillis())
                delay(1000)
                Log.d(TAG, "CoroutineParallel: TASK_2 Finish:"+System.currentTimeMillis())
            }

        }
    }

结果:
rxjava+LiveData VS 协程+flow, +Retrofit+Okhttp3,两种方案的不同使用._第4张图片
可以看到的是大家干的都是一件事,延时1秒(阻塞)然后输出,但是在概念理解和代码阅读上,协程确实有不少的优势.

5.增加Retrofit+Okhttp3(终极版)

Rxjava+Retrofit是我们常用的网络请求框架了…
当协程出来的时候,Retrofit也很快的支持了协程…
然后我们来看一下这两个不同之处…

构建okhttp客户端和retrofit.

 fun createGithubApi(): NormalInterface {
                val logger = HttpLoggingInterceptor()
                logger.level = HttpLoggingInterceptor.Level.BASIC

                val client = OkHttpClient.Builder()
                        .addInterceptor(logger)
                        .connectTimeout(30 * 1000, TimeUnit.MILLISECONDS)//连接超时
                        .readTimeout(20 * 1000, TimeUnit.MILLISECONDS)//读取超时,是否能读取到内容
                        .retryOnConnectionFailure(true)//重连
                        .build()
                return Retrofit.Builder()
                        .baseUrl(BASE_URL)
                        .client(client)
                        .addConverterFactory(GsonConverterFactory.create())
                        .build()
                        .create(NormalInterface::class.java)
            }

定义API接口,注意的是retrofit返回的是Observable.而协程是RepoSearchResponse

interface NormalInterface :BaseApi{
   //这是RXJAVA
    @GET("search/repositories?sort=stars")
    fun searchRepos_X(
            @Query("q") query: String,
            @Query("page") page: Int,
            @Query("per_page") itemsPerPage: Int
    ): Observable<RepoSearchResponse>

    //这是协程
    @GET("search/repositories?sort=stars")
    suspend fun searchRepos(
            @Query("q") query: String,
            @Query("page") page: Int,
            @Query("per_page") itemsPerPage: Int
    ): RepoSearchResponse
data class RepoSearchResponse(
        @SerializedName("total_count") val total: Int = 0,
)
}

重点来了,我们在viewModel中启用协程加入到StateFlow中

  val TextFlow_Retrofit by lazy {
        MutableStateFlow(RepoSearchResponse()).also {
            viewModelScope.launch(Dispatchers.IO) {
                it.value = retrofitUse.createGithubApi().searchRepos("Android", 0, 20)

            }
        }
    }

另外一个重点,viewModel中的LiveData使用Rxjava+Retrofit发送网络请求

    //Rxjava+LiveData+retrofit+okhttp
    val TextLiveData_Retrofit by lazy {
        MutableLiveData<RepoSearchResponse>().also {

            retrofitUse.createGithubApi_X().searchRepos_X("Android", 0, 20).
            subscribeOn(Schedulers.io())
                    .subscribe(object:Observer<RepoSearchResponse>{
                        override fun onSubscribe(d: Disposable?) {
                           // TODO("Not yet implemented")
                        }
                        override fun onNext(value: RepoSearchResponse?) {
                            //TODO("Not yet implemented")
                            it.value = value
                        }
                        override fun onError(e: Throwable?) {
                           // TODO("Not yet implemented")
                        }
                        override fun onComplete() {
                           // TODO("Not yet implemented")
                        }
                    })
        }
    }

看代码大家应该也明白的差不多了…我发现网上还是感觉比较少这种比较出来的,虽然很基础,但是这样也让人更加的直观的发现这两种不同的情况.
总结一下:
RXJAVA+Retrofit 的网络请求确实也是好用的,RxJava中的操作符和学习难度是比较大的,而且封装起来也比较麻烦一些,但是代码层面上感觉阅读起来没有协程那么舒服.kotlin香也确实挺香的.
关于LiveData和Flow中的使用,学习之后是感觉在Kotlin中是比较适合Flow的.
好了,虽然官方是kotlin First,里面的高阶函数 ,协程,Flow都是比较基础也重要的特性,希望自己再接再厉,继续学习下去吧
rxjava+LiveData VS 协程+flow, +Retrofit+Okhttp3,两种方案的不同使用._第5张图片

你可能感兴趣的:(Android知识,Android_demo,android,java)