kotlin 协程一

2020-12-30  本文已影响0人  crossroads

前言

趁机学一下kotlin协程,笔记来自安卓官网。关于协程的一些理解,大家可以看 抛物线的视频,B站就有,讲的很透彻。这个主要对于官网学习网站的翻译,学习网站见后记。官网的是中文,就不写在这里了。写的有点乱,主要用于回顾。

理解

  1. 协程都要运行在CoroutineScope中,一个scope通过其工作控制协程的生命,当取消scope,就会取消在这个scope里的所有协程。
  2. 因为协程可以很容易的在任何时间切换线程,并且返回结果给源线程,所以在主线程开始一个UI关联的协程是个好方式。例如ROOM、retrofit这些库在使用协程时是主线程安全的,所以不需要使用者在网络或者数据库调用时去管理线程。
  3. viewmodelScope 是viewmodel的扩展,这个scope被绑定在Dispatchers.Main上,当viewmodel被清除时会自动cancel。

代码示例

  1. viewModelScope的调度器是Dispatchers.Main,这里运行在主线程



    最左边的箭头+波浪线的符号应该是用了协程的标志
    2.使用协程
    首先,使用suspend操作符告诉kotlin,这个方法和协程一起工作

suspend fun refreshTitle() {
    delay(500)
}
   viewModelScope.launch {
            try {
                _spinner.value = true
                repository.refreshTitle()
            } catch (error: TitleRefreshError) {
                _snackBar.value = error.message
            } finally {
                _spinner.value = false
            }
        }
  1. 切换线程
    1》之前主线程安全的方法,类似这样:
    fun refreshTitleWithCallbacks(titleRefreshCallback: TitleRefreshCallback) {
        Executors.newFixedThreadPool(2).submit {
            try {
                val result = network.fetchNextTitle().execute()
                if (result.isSuccessful) {
                    titleDao.insertTitle(Title(result.body()!!))
                    titleRefreshCallback.onCompleted()
                } else {
                    titleRefreshCallback.onError(
                            TitleRefreshError("Unable to refresh title", null))
                }
            } catch (cause: Throwable) {
                titleRefreshCallback.onError(
                        TitleRefreshError("Unable to refresh title", cause))
            }
        }
    }

那么协程中会如何做呢?

  suspend fun refreshTitleWithCallbacks() {
        withContext(Dispatchers.IO) {
            val result = try {
                network.fetchNextTitle().execute()
            } catch (cause: Throwable) {
                throw  TitleRefreshError("Unable to refresh title", null)
            }
            if (result.isSuccessful) {
                titleDao.insertTitle(Title(result.body()!!))
            } else {
                throw  TitleRefreshError("Unable to refresh title", null)
            }
        }
    }

注意:这里暂没有去做cancel操作,一般来说是需要在必要的时候明确cancel的。

  1. diapatcher 调度器介绍
    Main:主线程 ;IO: 从网络或者数据库读取数据;Default:CPU密集型工作
  2. 在room和retrofit中
    1>retrofit
interface MainNetwork {
 @GET("next_title.json")
//改变前   fun fetchNextTitle(): Call<String>
suspend fun fetchNextTitle(): String
}

2>room

  @Insert(onConflict = OnConflictStrategy.REPLACE)
    //改变前   fun insertTitle(title: Title)
suspend fun insertTitle(title: Title)

3>方法

    suspend fun refreshTitleWithCallbacks() {
        try {
            val result = network.fetchNextTitle()
            titleDao.insertTitle(Title(result))
        } catch (cause: Throwable) {
            throw  TitleRefreshError("Unable to refresh title", null)
        }
    }

如果设置5s请求超时

   suspend fun refreshTitleWithCallbacks() {
        try {
            val result = withTimeout(5000){
                network.fetchNextTitle()
            }
            titleDao.insertTitle(Title(result))
        } catch (cause: Throwable) {
            throw  TitleRefreshError("Unable to refresh title", null)
        }
    }
  1. 抽suspend方法当参数进行封装
    咱们使用2使用协程的代码来进行封装抽取
   fun launchDataLoad(block: suspend () -> Unit): Job {
        return viewModelScope.launch {
            try {
                _spinner.value = true
                block()
            } catch (error: TitleRefreshError) {
                _snackBar.value = error.message
            } finally {
                _spinner.value = false
            }
        }
    }
    fun refreshTitle() {
        launchDataLoad {
            repository.refreshTitle()
        }
    }

学习网站

官网
官网学习网站

后记

携程取消方式
进阶 Part 1: Coroutines, Part 2: Cancellation in coroutines, and Part 3: Exceptions in coroutines
在livedata中使用 及其他进阶后续再写。

上一篇下一篇

猜你喜欢

热点阅读