Android开发Kotlin语言协程的依赖及使用示例

 更新时间:2023年08月06日 09:09:18   作者:Rocky_ruan  
这篇文章主要为大家介绍了Android开发Kotlin语言协程的依赖及使用示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

一:协程的依赖

Kotlin 协程提供了一种全新处理并发的方式,你可以在 Android 平台上使用它来简化异步执行的代码。
如果是用于 Android 平台的话,可以只引用以下的 coroutines-android,当中已经包含了 coroutines-core

//协程依赖
 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4"
 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"

协程优势:

1.轻量:单个线程上可以运行多个协程,协程支持挂起,不会使正在运行的线程阻塞

2.内存泄漏更少:协程支持结构化并发,从而避免了内存泄漏

3.Jetpact集成:Jetpack库都包含提供全面协程的支持的扩展。

如:ViewModelSocpe,LifecycleScope,LiveData

二:协程使用

1.简单使用

//开启协程
    fun runCoroutine() {
        Log.i("SecondActivity", "协程开始执行")
        Log.i("SecondActivity", "thread=${Thread.currentThread().name}")
        CoroutineScope(Dispatchers.IO).launch {
            delay(2000)
            Log.i("SecondActivity", "协程内部")
            Log.i("SecondActivity", "thread11=${Thread.currentThread().name}")

        }
        Log.i("SecondActivity", "协程下面")
    }

结果:
协程开始执行
thread=main
协程下面
协程内部
thread11=DefaultDispatcher-worker-1

CoroutineContext

协程中使用 CoroutineScope(Dispatchers.IO)的Dispatchers.IO 是CoroutineContext的子类实现
CoroutineContext。即协程上下文,包含多种类型的配置参数。Dispatchers.IO 就是 CoroutineContext 这个抽象概念的一种实现,用于指定协程的运行载体,即用于指定协程要运行在哪类线程上

@Suppress("FunctionName")
public fun CoroutineScope(context: CoroutineContext): CoroutineScope =
    ContextScope(if (context[Job] != null) context else context + Job())

Kotlin 协程库提供了四个 Dispatcher 用于指定在哪一类线程中执行协程:

  • Dispatchers.Default。默认调度器,适合用于执行占用大量 CPU 资源的任务。例如:对列表排序和解析 JSON
  • Dispatchers.IO。适合用于执行磁盘或网络 I/O 的任务。例如:使用 Room 组件、读写磁盘文件,执行网络请求
  • Dispatchers.Unconfined。对执行协程的线程不做限制,可以直接在当前调度器所在线程上执行
  • Dispatchers.Main。使用此调度程序可用于在 Android 主线程上运行协程,只能用于与界面交互和执行快速工作,例如:更新 UI、调用 LiveData.setValue

CoroutineScope

CoroutineScope 即 协程作用域,用于对协程进行追踪。如果我们启动了多个协程但是没有一个可以对其进行统一管理的途径的话,就会导致我们的代码臃肿杂乱,甚至发生内存泄露或者任务泄露。为了确保所有的协程都会被追踪,Kotlin 不允许在没有 CoroutineScope 的情况下启动协程。CoroutineScope 可被看作是一个具有超能力的 ExecutorService 的轻量级版本。它能启动协程,同时这个协程还具备上文所说的 suspend 和 resume 的优势

suspend

suspend 是协程中很重的关键字,它用来修饰函数,表示此函数是一个会挂起的函数,并且 挂起函数只有在协程中使用或者被另一个挂起函数调用,可以暂停和进行恢复,什么情况下需要用到挂起函数

  • 线程切换,挂起本身是线程切换不同的协程去工作,所以当需要进行线程切换时可以使用挂起函数
  • 延迟,暂停往往代表在等待一些结果,当我们在等待一些返回结果时,协程可以通过挂起的方式等待,而不是阻塞线程

suspend只是对函数的一个标识别,它不像inline,refied等关键字一样会对代码造成影响,而是提醒使用者这是一个挂起函数,具体的挂起业务还是需要函数内部自己实现

withContext

withContext是一个挂起函数,表明它只能在协程或者其他suspend函数调用

public suspend fun <T> withContext(
    context: CoroutineContext,
    block: suspend CoroutineScope.() -> T
): T {
}

launch

lauch是最常见的启动一个协程的方法,可以通过GlobalScope.launch开启一个全局生命周期的协程,也可以通过CoroutineScope(CoroutineContext).launch 来开启一个在指定的 CoroutneContext 范围的协程。也可以记录这个Job并通过Job.cancel()随时取消

public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}
val apiService by lazy { RetrofitClient.instance.create() }
  //开启协程
    fun runCoroutine(name: String, password: String, resultListener: (String, String) -> Unit) {
        Log.i("SecondActivity", "协程开始执行")
        Log.i("SecondActivity", "thread=${Thread.currentThread().name}")
        CoroutineScope(Dispatchers.IO).launch {
            Log.i("SecondActivity", "协程内部")
            Log.i("SecondActivity", "thread11=${Thread.currentThread().name}")
            val request = HttpAccountLoginRequest(name, password, null)
            val block :suspend CoroutineScope.()->BaseResult<HttpAccountLoginResponse> ={
                apiService.requestAccountLogin(request,"android","3.5.4")
            }
            var result:BaseResult<HttpAccountLoginResponse> =block()
            if (result.code=="200"&&result.datas!=null){
                withContext(Dispatchers.Main){
                }
            }
        }
        Log.i("SecondActivity", "协程下面")
    }

launch

  • 不会阻塞直到结果返回
  • 不会阻塞线程
  • 并行执行

withContext:

  • 会阻塞当前协程直到函数返回
  • 从指定的Dispatcher执行函数
  • 当执行函数的时候不会阻塞线程
  • 串行执行

async

  • 当使用awiat函数时,会阻塞直到结果返回
  • 如果不使用await,其效果与launch一样
  • 适用于多个并行任务但需要等待结果返回情形
  • 并行执行

什么是 Job ?

Job 翻译作任务,Job 赋予协程可取消,赋予协程以生命周期,赋予协程以结构化并发的能力。其中平常使用中最为重要的是可取消、结构化并发的特点。尤其 在日常 Android 开发过程中,协程配合 Lifecycle 可以做到自动取消。

Job 的生命周期

Job 的生命周期分为 6 种状态,分为 New、Active、Completing、Cancelling、Cancelled、Completed,通常外界会持有 Job 接口会作为引用被协程调用者所持有,Job 接口提供 isActive、isCompleted、isCancelled 3 个变量使外界可以感知 Job 内部的状态,这3个变量和 Job 生命周期的6种状态的对应关系如下图所示

栗子:
 CoroutineScope(Dispatchers.IO).async {
        }
源码:
public fun <T> CoroutineScope.async(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T
): Deferred<T> {
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyDeferredCoroutine(newContext, block) else
        DeferredCoroutine<T>(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}
栗子:
CoroutineScope(Dispatchers.IO).launch {
}
源码:
public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}

一种是通过 launch 启动,一种是通过 async 启动,前者会返回一个 Job 类型的对象,后者会返回一个 Deferred 类型的对象

Job的接口定义

Job 顾名思义就是“工作”的意思,每个协程可以想象成是一个工作任务,启动一个协程就是启动一个工作任务,来看看 Job 接口的主要定义:

//Job 也是继承自 Element,所以它本身也是一个协程上下文 context
public interface Job : CoroutineContext.Element {
    //Key对象,如果你看到 context[Job] 的写法, 就知道其实指的是这里的这个伴生对象 Key
    public companion object Key : CoroutineContext.Key<Job> {
        init {
            CoroutineExceptionHandler
        }
    }
    //是否活动状态,必须满足几个条件:该协程已经启动、没有完成、没有被取消
    public val isActive: Boolean
    //是否完成状态
    public val isCompleted: Boolean
    //是否被取消状态
    public val isCancelled: Boolean   
    //启动协程,开始调度。如果已经启动了,则返回false。与线程的Thread.start()挺类似
    public fun start(): Boolean
    //挂起当前正在运行的协程,等待该 Job 执行完成。与线程的Thread.join()挺类似
    public suspend fun join()
    //取消该 Job
    public fun cancel(cause: CancellationException? = null)
    //该 Job 的子 Job
    public val children: Sequence<Job>
}

小知识:

Kotlin空指针检查

在Kotlin里,可以用“?”表示可以为空,也可以用“!!”表示不可以为空。

给变量加上?标识,会通告所有使用该变量的地方,必须给出为空的补救措施。

var info: String? = null
        println(info?.length)  //第一种补救:如果info为null,就不执行后面的.length代码
        println(info!!.length)  //第二种补救:这里如果为null,我自己负责info,会报出空指针,这种处理需慎用
        if (info != null) {   //第三种补救措施,如下这种同java写法
            println(info.length)
        }
      println(info?.length ?: "空数据")  //第四种补救措施,如果真的为null,则改为返回"空数据"

以上就是Android开发Kotlin语言协程的依赖及使用示例的详细内容,更多关于Android Kotlin协程依赖的资料请关注脚本之家其它相关文章!

相关文章

  • android studio logcat 无筛选 显示全部日志 无应用包名区分方式

    android studio logcat 无筛选 显示全部日志 无应用包名区分方式

    这篇文章主要介绍了android studio logcat 无筛选 显示全部日志 无应用包名区分方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-04-04
  • Android强制设定横屏时,SurfaceView一直黑屏

    Android强制设定横屏时,SurfaceView一直黑屏

    本文主要介绍了Android强制设定横屏时,SurfaceView一直黑屏的方法。具有一定的参考作用,下面跟着小编一起来看下吧
    2017-01-01
  • Android 4.4以上

    Android 4.4以上"沉浸式"状态栏效果的实现方法

    Android与ios效果互仿早已不是什么稀奇的事,我猜大概这个效果来自ios吧,有争议说这种效果不能叫做沉浸式,叫透明状态栏更合适,我也感觉这和沉浸式的含义不太一致。但是大家都这么叫了,那就这样呗。下面来一起看看关于Android 4.4以上"沉浸式"效果的实现方法。
    2016-09-09
  • Android Studio 3.0被调方法参数名提示的取消方法

    Android Studio 3.0被调方法参数名提示的取消方法

    这篇文章主要介绍了去掉android studio 3.0被调方法参数名提示的解决方法,在文章末尾给大家补充介绍了Android Studio 3.0 gradle提示太老的解决方法,非常不错,需要的朋友可以参考下
    2017-11-11
  • Android开发注解排列组合出启动任务ksp

    Android开发注解排列组合出启动任务ksp

    这篇文章主要为大家介绍了Android开发注解排列组合出启动任务ksp示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Android zip4j压缩、解压、加解密的示例代码

    Android zip4j压缩、解压、加解密的示例代码

    本篇文章主要介绍了Android zip4j压缩、解压、加解密的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12
  • studio碰到问题:java.lang.UnsatisfiedLinkError解决办法

    studio碰到问题:java.lang.UnsatisfiedLinkError解决办法

    这篇文章主要介绍了studio碰到问题:java.lang.UnsatisfiedLinkError解决办法的相关资料,需要的朋友可以参考下
    2017-02-02
  • Android 登录Web 时对cookie 处理

    Android 登录Web 时对cookie 处理

    本文主要介绍 Android登录web时对cookie的处理方法,这里cookie 的读写做了详细介绍,并附有代码进行讲解,希望能帮到有需要的同学
    2016-07-07
  • Flutter listview如何实现下拉刷新上拉加载更多功能

    Flutter listview如何实现下拉刷新上拉加载更多功能

    这篇文章主要给大家介绍了关于Flutter listview如何实现下拉刷新上拉加载更多功能的相关资料,对于新闻列表数据的更新和加载更多是必不可少的,而实现下拉刷新与上划加载更多的方式有很多种,需要的朋友可以参考下
    2021-08-08
  • Android入门教程之Picasso框架

    Android入门教程之Picasso框架

    本文会先介绍Picasso的基本使用方法,让您快速上手Picasso。后面我们分享实现ListView显示网络图片的实例,从源码角度详细分析它的实现,有需要的可以参考借鉴。
    2016-08-08

最新评论