Kotlin 协程(一)利用协程同步异步下载图片

394 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情

主要就是用来记录自己学习Kotlin协程的历程

1.添加kotlin 协程依赖
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.1"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.1"
2.runtime依赖库使用协程方便一些 里面有Android对kotlin写的扩展方法供我们使用
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
3.添加Okhttp网络库 下载需要用到网络 这个不可少
implementation 'com.squareup.okhttp3:okhttp:3.7.0'
implementation 'com.squareup.okio:okio:1.12.0'
4.使用Kotlin同步下载图片
private fun downSynchronization(){
    lifecycleScope.launch {
        var img = withContext(Dispatchers.IO){
            var okhttpClient = OkHttpClient()
            var request = Request.Builder()
                .url("https://img0.baidu.com/it/u=922902802,2128943538&fm=253&app=120&size=w931&n=0&f=JPEG&fmt=auto?sec=1664643600&t=27708f780616fd83ad134e135e152ec1")
                .method("GET",null)
                .build()
            var call = okhttpClient.newCall(request)
            var respone = call.execute()
            var bytes = respone.body().bytes()
            BitmapFactory.decodeByteArray(bytes,0,bytes.size)
        }
        ivImgSynchronization.setImageBitmap(img)
    }
}

lifecycleScope 就是runtime里面的扩展方法,launch里面能指定线程,不指定的话一般是Main主线程,咱都知道网络是耗时操作,肯定是要在子线程中进行下载操作的,所以使用withContext进行线程切换,这个函数的作用就是切换线程,然后执行完成后再把线程切换回运行函数的所在的线程,最后把结果转成byte数组,在转成bitmap图片展示。

5.使用Kotlin 异步下载图片
private fun downAsynchronous(){
        lifecycleScope.launch {
            var img = withContext(Dispatchers.IO){
                var okhttpClient = OkHttpClient()
                var request = Request.Builder()
                    .url("https://img0.baidu.com/it/u=922902802,2128943538&fm=253&app=120&size=w931&n=0&f=JPEG&fmt=auto?sec=1664643600&t=27708f780616fd83ad134e135e152ec1")
                    .method("GET",null)
                    .build()
                var call = okhttpClient.newCall(request)
//                suspendCoroutine<> {  }
                var response = suspendCancellableCoroutine<Response?> {
                    call.enqueue(object :Callback{
                        override fun onFailure(call: Call?, e: IOException?) {

                        }

                        override fun onResponse(call: Call?, response: Response?) {
                            it.resume(response)
                        }
                    })
                }

                var bytes = response?.body()?.bytes()
                bytes?.size?.let { BitmapFactory.decodeByteArray(bytes,0, it) }
            }
            ivImgAsynchronous.setImageBitmap(img)

        }
    }

A. launch 和 withContext 咱就不说了,异步中用到了suspendCancellableCoroutine这个函数,这个函数的作用是把异步结果以变量的形式接收,代码中就是等网络请求结束后通过resume方法把结果返回给当前接收的变量。

B. 可以看到在代码中我还注释了一个函数suspendCoroutine,这个函数的作用跟上面那个函数作用是基本上是一样的,唯一的区别是suspendCancellableCoroutine这个函数可以通过cancle取消协程的执行的