IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Kotlin开发Android App和Java的差异7----Kotlin中使用协程执行并发操作 -> 正文阅读

[移动开发]Kotlin开发Android App和Java的差异7----Kotlin中使用协程执行并发操作

个人淘宝店铺需要的小伙伴可以点进来

1 依赖配置

如果在Android项目中使用协程,需要配置以下依赖

implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9")

2 实现协程的方式

在Kotlin中,实现协程的方式有很多,常见的方式包括async、lunch、withContext

其中,launch不存在返回值,async可以存在返回值,两者都不会阻塞主线程

2.1 launch的方式创建协程

Kotlin在Android中,通过launch创建协程比较常见,在官方文档中也是通过launch来举例子

数据接口

interface IWeatherDataSource {

    suspend fun getCurrentWeather(): Alarm
}

其中suspend代表了当前函数是一个耗时方法,只能在协程中或者其他suspend函数中调用,当协程中碰到suspend关键字,将会把协程挂起,不会阻塞线程

Repository

suspend fun getCurrentAlarm():Alarm{

    return iWeatherDataSource.getCurrentWeather()
    
	//2.保证主线程安全
	return withContext(Dispatchers.IO){
        return@withContext iWeatherDataSource.getCurrentWeather()
    }
}

Kotlin在Android存在多种协程Scope用来创建协程,例如ViewModel中的viewModelScope,或者Activity / Fragment中的lifecycleScope

fun getCurrentWeather() : MutableLiveData<Alarm>{

    val result:MutableLiveData<Alarm> = MutableLiveData<Alarm>()

    viewModelScope.launch {

        var currentAlarm = repository.getCurrentAlarm()
        result.postValue(currentAlarm)
    }
    return result
}

2.2 async的方式创建协程

通过async的方式创建的协程具备返回值,不需要像launch那样自定义一个返回值,需要配合await来取出返回值

suspend fun getCurrentWeather() : MutableLiveData<Alarm>{

    var result =  viewModelScope.async(Dispatchers.IO){

        var currentAlarm = repository.getCurrentAlarm()
        return@async MutableLiveData(currentAlarm)
    }

    return result.await()

}

2.3 保证主线程安全

使用suspend函数不会让kotlin在后台线程上运行,在主线程上运行suspend函数也很常见,因此如果为了保证主线程的安全,所有的suspend函数中都要使用withContext,保证了耗时操作一定是在IO或者Default线程中运行

suspend fun getCurrentAlarm():Alarm{
    
	//2.保证主线程安全
	return withContext(Dispatchers.IO){
        return@withContext iWeatherDataSource.getCurrentWeather()
    }
}

因为withContext是一个暂停函数,所以getCurrentAlarm也是一个暂停函数,这样在调用getCurrentAlarm的时候,就会挂起协程,等到withContext执行完成之后,恢复

3 协程中的异常处理

在Kotlin协程中,同样可以使用try-catch代码块包裹可能出现异常的代码块,但是和Java不同的时,个别情况下,try-catch代码能够捕获异常,但是app会崩溃,有的情况下则不会崩溃

3.1 supervisorScope 和 coroutineScope的使用方式

viewModelScope.launch {

   try {

       coroutineScope {

           var getUserError =  async { NewsDataSource.RetrofitBuilder.api.getUsersWithError().await() }

           var getUsers = async { NewsDataSource.RetrofitBuilder.api.getUsers().await() }


           var userErrorFromApi = try {

               getUserError.await()

           }catch (e:Exception){
               emptyList()
           }

           var userFromApi = try {

               getUsers.await()

           }catch (e:Exception){

               emptyList()

           }
//
           userList.postValue(userFromApi)
       }

   }catch (e:Exception){

       Log.e("TAG",e.message.toString())
   }
}

在coroutineScope协程块中,有两个异步处理,其中getUserError是会报错的(Http 404),这是异常的,通过try-catch能够捕获这个异常,另一个是正常的;

如果按照Java的理解,捕获到了异常并不会使得app崩溃,但是coroutineScope就是不管哪个异步方式报错,都会停止协程,而且app崩溃。

而使用supervisorScope协程块,虽然getUserError会报错,但是并不会影响第二个协程的执行,而且正常上传数据更新UI。

3.2 async 和 launch 抛出异常的区别

使用launch发生异常就会立即抛出,因此需要使用tyr-catch代码块包裹launch中可能会出现异常的代码;

viewModelScope.launch {

    try {

        var users1 = repository.getUsersWithError().await()
        users.postValue(users1)

    }catch (e:Exception){

        users.postValue(emptyList())
    }
}

使用async不会立刻抛出异常,而是在调用await的时候会抛出异常,因此需要将await使用try-catch代码包裹

viewModelScope.launch {

var dd =  async { repository.getUsers().await() }

try {

     var await = dd.await()

     users.postValue(await)

 }catch (e:Exception){

     users.postValue(emptyList())

 }
}

这种情况下,App会崩溃?为什么,官方文档中声明,async只有在await的时候,才会抛出异常吗,为什么已经捕获了异常,但是app还是崩溃了?

主要原因就是,async作为根协程的时候,才会在await的时候,抛出异常;其他情况下,很有可能在async中也抛出异常。

viewModelScope.launch(exeptionHandler) {

    try {

        var dd =  async { repository.getUsersWithError().await() }

        var await = dd.await()

        users.postValue(await)

    }catch (e:Exception){

        users.postValue(emptyList())

    }
}

这种将async也包裹起来,就能够阻止app崩溃;或者将根协程由launch改为async

viewModelScope.async(exeptionHandler) {

    var dd =  async { repository.getUsersWithError().await() }

    try {

        var await = dd.await()

        users.postValue(await)

    }catch (e:Exception){

        users.postValue(emptyList())

    }

}
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-12-09 11:48:03  更:2021-12-09 11:49:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:25:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码