Android协程
MainScope
在Android中使用协程框架,除了要引入协程框架的核心模块以外,还需要 引入以下依赖:org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3,它提供了Dispatchers.Main在Android上的实现。
需要把协程与UI的生命 周期关联起来,避免内存泄露。框架中还有一个函数MainScope,它可以创建一个基于UI调度器的主从作用域:
class ScopedActivity: AppCompatActivity(){
private val mainScope by lazy { MainScope() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_scoped)
button.setOnClickListener {
mainScope.launch {
...// 调度到UI线程
}
}
}
override fun onDestroy() {
super.onDestroy()
//用完销毁
mainScope.cancel()
}
}
作用域的好处就是可以方便地绑定到UI组件的生命 周期上,在Activity销毁的时候直接取消,所有该作用域启动的协程 就会被取消。
lifecycleScope
KTX为Jetpack的Lifecycle相关组件都提供了已经绑定了UI生命周期的作用域供直接使用,添加Lifecycle相应的基础组件之后,再添加以下组件: androidx.lifecycle:lifecycle-runtime-ktx:2.2.0,lifecycle-runtime-ktx提供了LifecycleCoroutineScope类及其获得方式,可以直接在Activity中使用lifecycleScope来获取这个实例:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener {
lifecycleScope.launch {
...// 执行协程体
}
}
}
}
这是因为MainActivity的父类实现了LifecycleOwner接口,而lifecycleScope则是它的扩展成员。
viewModelScope
在ViewModel中使用作用域,需要再添加以下依赖: androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0:
class MainViewModel : ViewModel() {
fun fetchData() {
viewModelScope.launch {
... // 执行协程体
}
}
}
ViewModel的作用域会在它的clear函数调用时取消。
repeatOnLifecycle
lifecycleScope虽然解决了内存泄漏问题, 但是 lifecycleScope.launch 会立即启动协程,之后一直运行直到协程销毁,无法像 LiveData 仅当 UI 处于前台才执行,对资源的浪费比较大。
repeatOnLifecycle 则确保协程仅在目标生命周期状态(如 STARTED 或 RESUMED)时运行,并在退出该状态时自动取消,避免资源浪费。
核心特性
- 生命周期感知:仅当
Lifecycle至少处于指定状态(如STARTED)时执行代码块;低于该状态时自动取消。 - 可重启行为:每次进入目标状态都会启动新协程,退出时彻底取消,适合需要“重新开始”的场景(如网络请求、数据库订阅)。
- 结构化并发:作为挂起函数,天然支持协程取消传播,父协程取消时子协程也会被取消。
- 线程安全:内部使用
Dispatchers.Main.immediate,适合在主线程操作 UI。
https://developer.aliyun.com/article/940765
ORM框架Room中的协程扩展
Room是Jetpack中的ORM框架,它提供了对事务的支持及DAO的生成 机制等能力,主要用来简化Android中对SQLite的访问。
@Entity(tableName = "user", primaryKeys = ["id"])
data class User(
@ColumnInfo(name="id") val id: Long,
@ColumnInfo(name="name") val name: String,
@ColumnInfo(name="age") val age: Int)
定义一个User类来对应数据库的user表,再定义一个UserDao 接口来提供操作数据库的能力。
@Dao
interface UserDao {
@Insert
suspend fun insert(user: User)
@Query("SELECT * from user")
fun listUsers(): List<User>
}
UserDao的实现类不需要开发者自己定义,编译时Room会使用注解 处理器自动生成。由于数据库读写是I/O操作,可能会阻塞,因此 UserDao的函数不能在UI线程上运行。Room支持挂起函数,对于可挂起的接口函数,生成的实现与普通函数是不同的。
网络框架Retrofit中的协程扩展
Retrofit(https://gihub.com/square/retrofit)是最早一批开始支持Kotlin协程的框架。
协程风格的对话框
切换线程一定产生异步,但不切换线程切换函数调用栈也可以产生异步。对话框作为一个UI组件必须运行在UI线程上,却因为需要等待用户操作而提供了取消、确认等回调,这些同样可以用协程来简化。
suspend fun Context.alert(title: String, message: String): Boolean =
suspendCancellableCoroutine {continuation ->
AlertDialog.Builder(this)
.setNegativeButton("No"){ dialog, which ->
dialog.dismiss()
continuation.resume(false)
}.setPositiveButton("Yes"){
dialog, which ->
dialog.dismiss()
continuation.resume(true)
}.setTitle(title)
.setMessage(message)
.setOnCancelListener {
continuation.resume(false)
}.create()
.also { dialog ->
continuation.invokeOnCancellation {
dialog.dismiss()
}
}.show()
}
协程版的对话框的使用
lifecycleScope.launch {
val myChoice = alert("Warning!", "Do you want this?")
toast("My choice is: $myChoice")
}
lifecycleScope.launch {
val myChoice = alert("Warning!", "Do you want this?")
toast("My choice is: $myChoice")
}
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)