协程是一种并发设计模式,您可以在 Android 平台上使用它来简化异步执行的代码。协程是在版本 1.3 中添加到 Kotlin 的,它基于来自其他语言的既定概念。
在 Android 上,协程有助于管理长时间运行的任务,如果管理不当,这些任务可能会阻塞主线程并导致应用无响应。使用协程的专业开发者中有超过 50% 的人反映使用协程提高了工作效率。本主题介绍如何使用 Kotlin 协程解决以下问题,从而让您能够编写出更清晰、更简洁的应用代码。
2.特点协程是我们在 Android 上进行异步编程的推荐解决方案。值得关注的特点包括:
- 轻量:您可以在单个线程上运行多个协程,因为协程支持挂起,不会使正在运行协程的线程阻塞。挂起比阻塞节省内存,且支持多个并行 *** 作。
- 内存泄漏更少:使用结构化并发机制在一个作用域内执行多项 *** 作。
- 内置取消支持:取消 *** 作会自动在运行中的整个协程层次结构内传播。
- Jetpack 集成:许多 Jetpack 库都包含提供全面协程支持的扩展。某些库还提供自己的协程作用域,可供您用于结构化并发。
先导入依赖
//协程依赖
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0-RC-native-mt'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0-RC-native-mt'
//retrofit依赖
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'
//实体类
data class User(
val `data`: List,
val errorCode: Int,
val errorMsg: String
)
data class Data(
val category: String,
val icon: String,
val id: Int,
val link: String,
val name: String,
val order: Int,
val visible: Int
)
//Retrofit网络请求
val userServiceApi: UserServiceApi by lazy {
val retrofit = Retrofit.Builder()
.client(OkHttpClient.Builder().addInterceptor {
it.proceed(
it.request()
).apply {
Log.d("jason", "request:${code()}")
}
}.build()).baseUrl("https://www.wanandroid.com/friend/").addConverterFactory(MoshiConverterFactory.create())
.build()
retrofit.create(UserServiceApi::class.java)
}
interface UserServiceApi {
@GET("json")
//挂起
suspend fun User() :User
}
class MainActivity2 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
text.text="Jack"
button.also {
it.setOnClickListener {
// 协程构建器 主线程
GlobalScope.launch(Dispatchers.Main) {
//任务调度器 子线程
val user= withContext(Dispatchers.IO){
userServiceApi.User()
}
text.text="address:${user?.data?.get(0)?.category}"
}
}
}
}
}
到此这个例子结束了,接下来我们一 一解释。
2.协程的挂起与恢复常规函数基础 *** 作包括:invoke(或call)和return,协程新增了suspend和res
ume:
suspend 一也称为挂起或暂停,用于暂停执行当前协程,并保存所有局部变量;
resume 一用于让已暂停的协程从其暂停处继续执行。
class MainActivity3 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
text.text="Jack"
button.also {
it.setOnClickListener {
// 协程构建器 主线程
GlobalScope.launch(Dispatchers.Main) {
//挂起方法
getUser()
}
}
}
}
//挂起关键字
private suspend fun getUser(){
val user=get()
show(user)
}
private fun show(user:User){
text.text="address:${user?.data?.get(0)?.category}"
} //任务调度器 子线程
private suspend fun get()= withContext(Dispatchers.IO){
userServiceApi.User()
}
}
通过使用suspend 修改后的代码, 需要注意子方法用suspend 父方法也得加suspend 。还用suspend 关键字只能在协程内或其他挂起函数内使用.
3.挂起与阻塞class MainActivity4 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
text.text="Jack"
//挂起不会阻塞主线程,而且会把你所去要的任务记录下来并完成
button.also {
it.setOnClickListener {
// 协程构建器 主线程
GlobalScope.launch(Dispatchers.Main) {
//延迟 有挂起的作用
delay(10000)
Log.d("delay","${Thread.currentThread().name} after delay")
}
//sleep会阻塞主线程,
// Thread.sleep(10000)
// Log.d("delay","${Thread.currentThread().name} after sleep")
}
}
}
}
这里通过使用delay,你每点一次按钮都会开一个协程发起一次任务,过10秒后你点了多少下会打印多少次,而且并没有阻塞主线程。而底下的sleep会阻塞主线程,有ANR的危险。
4.协程的基础写法class MainActivity5 : AppCompatActivity() {
/**
*
*/
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
text.text="Jack"
//这个是协程底部基础函数
//协程体 也是挂起函数
val createCoroutine = suspend {
5 //传入的值
}.createCoroutine(object : Continuation {
//协程上下文
override val context: CoroutineContext = EmptyCoroutineContext
//协程执行完成的回调
override fun resumeWith(result: Result) {
//result 协程执行结果
Log.i("resumeWith", "$result ")
}
})
//启动协程
createCoroutine.resume(Unit)
}
}
5.协程的调度器
所有协程必须在调度器中运行。
Dispatchers.Main : Android上的主线程用来处理UI交互和一些轻量级任务
Dispatchers.IO : 非主线程专为磁盘和网络IO进行了
Dispatchers.Default : 非主线程转为CPU密集型任务进行了优化
6.任务泄露当某个协程任务丢失,无法追踪,会导致内存、CPI-R磁盘等资源浪费,甚至发
送一个无用的网络请求,这种情况称为任务泄漏。
为了能够避免协程泄漏,Kot|in引入了结构化并发机制。
使用结构化并发可以做到:
取消任务 :当某项任务不再需要时取消它。
追踪任务 :当任务正在执行是,追踪它。 发出错误信号:当协程失败时,发出错误信号表明有错误发生。
定义协程必须指定其CoroutineScope,它会跟踪所有协程,同样它还可以取消
由它所启动的所有协程。
常用的相关API有:
GlobalScope,生命周期是process级别的,即使Activity或Fragment已经被销毁,协程仍然在执行。
MainScope,在Activity中使用,可以在onDestroy()中取消协程。
viewModeIScope,只能在ViewM0de|中使用,绑定ViewM0de|的生命周期。
IifecycIeScope,只能在Activity、Fragment中使用,会绑定Activity和Fragment的生命周期。
class MainActivity6 : AppCompatActivity() {
private var nametext :TextView?=null;
private var mainScope = MainScope()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//text.text="Jack"
nametext=findViewById(R.id.text)
button.apply {
setOnClickListener {
mainScope.launch {
//User函数用了挂起所以他会自动启用一个子线程请求
val user = userServiceApi.User()
nametext?.text="address:${user?.data?.get(0)?.category}"
}
}
}
override fun onDestroy() {
super.onDestroy()
//取消mainScope的任务
mainScope.cancel()
}
}
还可以这么写
class MainActivity6 : AppCompatActivity(),CoroutineScope by MainScope() {
private var nametext :TextView?=null;
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
nametext=findViewById(R.id.text)
button.apply {
setOnClickListener {
launch {
//User函数用了挂起所以他会自动启用一个子线程请求
val user = userServiceApi.User()
nametext?.text = "address:${user?.data?.get(0)?.category}"
}
}
}
}
override fun onDestroy() {
super.onDestroy()
//取消mainScope的任务
cancel()
}
}
这是两种MainScope的两种写法
三.协程上手这里写一个例子使用:协程+Retrofit+ViewModel+LiveData+DataBinding
在先说明,数据类和Retrofit的封装类和第一个列子使用的使用一个.
先配置DataBinding与依赖
android {
dataBinding {
enabled = true
}
}
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'
implementation "androidx.activity:activity-ktx:1.1.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0-RC-native-mt'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0-RC-native-mt'
class UserRepository{
//挂起函数 返回数据
suspend fun getUser():User{
return userServiceApi.User()
}
}
class MainViewModel : ViewModel() {
val userLiveData= MediatorLiveData()
private val UserRepository=UserRepository()
fun getUser(){
//viewModelScope 绑定viewModel的生命周期
viewModelScope.launch {
userLiveData.value= UserRepository.getUser()
}
}
}
class MainActivity7 : AppCompatActivity() {
private val mainViewModel:MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding =
DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.lifecycleOwner=this;
binding.viewModel=mainViewModel
text.text="Jack"
binding.button.setOnClickListener {
mainViewModel.getUser()
}
}
}
演示:
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)