Android 使用 kotlin 协程

我写这篇blog的原因是网上很多都是用的coroutines旧版本,但正式版本进行了修改。因为我也是才开始学习coroutines,因此只涉及使用。

第一步:添加依赖

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.0'

在我写的时候,kotlinx-coroutines-android:1.1.0版本,是Kotlin 1.3.11版本的配套版本。若是再低版本中,coroutines处于试验状态,需要添加以下代码

kotlin {
    experimental {
        coroutines 'enable'
    }
}

第二步 :activity_main.xml 布局


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity">

    <ImageView android:visibility="gone" android:id="@+id/image" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/>

    <TextView android:id="@+id/tvContent" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/>

    <TextView android:id="@+id/tvGetPic" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="20dp" android:layout_gravity="center" android:textSize="20sp" android:text="获取" />

LinearLayout>

第三步:MainActivity.kt

    private val UI: CoroutineContext = Dispatchers.Main
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        tvGetPic.setOnClickListener {
            getText()
            }
        }
}
    
    //方法一:
    fun getText1(){
        val job = GlobalScope.launch(Background) {
            var str = ""
            val client = OkHttpClient()
            val request = Request.Builder()
                    .url("http://www.wanandroid.com/friend/json")
                    .build()
            val response = client.newCall(request).execute()
            response.run {
                body()?.let {
                    val ins = it.string()
                    str= ins
                }
            }
            launch(UI) {
                tvContent.text = str
            }
        }
    }
    

	//方法二:
    fun getText2(){
        val deferred = GlobalScope.async {
            var str = ""
            val client = OkHttpClient()
            val request = Request.Builder()
                    .url("http://www.wanandroid.com/friend/json")
                    .build()
            val response = client.newCall(request).execute()
            response.run {
                body()?.let {
                    val ins = it.string()
                    str = ins
                }
            }
            str
        }

        runBlocking {
            tvContent.text = deferred.await()
        }
    }

Dispatchers.Main为Android应用程序提供上下文 ——官方文档

launch { // 运行在父协程的上下文中,即 runBlocking 主协程
    println("main runBlocking : I'm working in thread ${Thread.currentThread().name}")
}
launch(Dispatchers.Unconfined) { // 不受限的——将工作在主线程中
    println("Unconfined : I'm working in thread ${Thread.currentThread().name}")
}
launch(Dispatchers.Default) { // 将会获取默认调度器,共享的后台线程池
    println("Default : I'm working in thread ${Thread.currentThread().name}")
}
launch(newSingleThreadContext("MyOwnThread")) { // 将使它获得一个新的线程
    println("newSingleThreadContext: I'm working in thread ${Thread.currentThread().name}")
}

Dispatchers.Default——将会获取默认调度器,共享的后台线程池
kotlin中文网链接

效果图:

Android 使用 kotlin 协程_第1张图片

协程共有三种方式:

  1. runBlocking:在主线程中调用了 runBlocking, 阻塞 会持续到 runBlocking 中的协程执行完毕。

2.launch:

val job = GlobalScope.launch(Background) {
            //代码块.....
        }

launch会返回一个job,这个job是可以被取消的,可以和Android activity,fragment的生命周期联系起来。

在上面中出现了这样一段代码:

    fun getText1(){
        val job = GlobalScope.launch(Background) {
            var str = ""
            val client = OkHttpClient()
            val request = Request.Builder()
                    .url("http://www.wanandroid.com/friend/json")
                    .build()
            val response = client.newCall(request).execute()
            response.run {
                body()?.let {
                    val ins = it.string()
                    str= ins
                }
            }
            launch(UI) {
                tvContent.text = str
            }
        }
    }

两次使用launch的方式不同,因为本质上,协程是轻量级的线程。 它们在 CoroutineScope 上下文中和 launch 协程构建器 一起被启动。 这里我们在 GlobalScope 中启动了一些新的协程,存活时间是指新的协程的存活时间被限制在了整个应用程序的存活时间之内。第二次的launch活动范围被限制在第一个之中 。

  1. async :
        val deferred = GlobalScope.async {
            var str = ""
            val client = OkHttpClient()
            val request = Request.Builder()
                    .url("http://www.wanandroid.com/friend/json")
                    .build()
            val response = client.newCall(request).execute()
            response.run {
                body()?.let {
                    val ins = it.string()
                    str = ins
                }
            }
            str
        }

        runBlocking {
            tvContent.text = deferred.await()
        }

async 与launch的区别在于,async 可以返回获取的值。例如网络请求,不依赖回调接口就可以将获得的数据返回。
与launch一样,async也是可以被取消的

我自己也是刚刚开始学习,如果有什么问题,可以在评论中指出来。

Android 使用 kotlin 协程_第2张图片

帮助:
1.kotlin中文文档 https://www.kotlincn.net/docs/reference/
2.https://www.jianshu.com/p/04f28bbc66dc

你可能感兴趣的:(Android)