概述
个人淘宝店铺需要的小伙伴可以点进来
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())
}
}
最后
以上就是可靠小蝴蝶为你收集整理的Kotlin开发Android App和Java的差异7----Kotlin中使用协程执行并发操作的全部内容,希望文章能够帮你解决Kotlin开发Android App和Java的差异7----Kotlin中使用协程执行并发操作所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复