ユーザ用ツール

サイト用ツール


kotlin:coroutines

差分

この文書の現在のバージョンと選択したバージョンの差分を表示します。

この比較画面にリンクする

両方とも前のリビジョン 前のリビジョン
次のリビジョン
前のリビジョン
kotlin:coroutines [2019/10/03 06:44]
ips
kotlin:coroutines [2020/01/14 07:03] (現在)
ips [まとめ]
ライン 3: ライン 3:
 [[https://​kotlinlang.org/​docs/​tutorials/​coroutines/​coroutines-basic-jvm.html|Your first coroutine with Kotlin]] [[https://​kotlinlang.org/​docs/​tutorials/​coroutines/​coroutines-basic-jvm.html|Your first coroutine with Kotlin]]
  
-Threadとは比べ物にならないほど軽い!+[[https://​github.com/​pljp/​kotlinx.coroutines/​blob/​japanese_translation/​docs/​basics.md|pljp/​kotlinx.coroutines]] 
 + 
 +===== coroutineの使い方 ===== 
 + 
 +<code xml build.gradle (Modlue.app)>​ 
 +dependencies { 
 +    implementation fileTree(dir:​ '​libs',​ include: ['​*.jar'​]) 
 +    ・・・ 
 +    androidTestImplementation '​androidx.test.espresso:​espresso-core:​3.1.1'​ 
 +    implementation "​org.jetbrains.kotlinx:​kotlinx-coroutines-android:​1.3.2"​ // step1 
 + 
 +
 +</​code>​ 
 + 
 +<code kotlin>​ 
 +package com.nekotype.ips.api 
 + 
 +import android.os.AsyncTask 
 +import androidx.appcompat.app.AppCompatActivity 
 +import android.os.Bundle 
 +import android.util.Log 
 +import kotlinx.android.synthetic.main.activity_main.* 
 +import kotlinx.coroutines.* //​ step2 
 + 
 + 
 +class MainActivity : AppCompatActivity() { 
 + 
 +    override fun onCreate(savedInstanceState:​ Bundle?) { 
 +        super.onCreate(savedInstanceState) 
 +        setContentView(R.layout.activity_main) 
 + 
 +         // click 
 +        button.setOnClickListener { 
 +           ​println("​start:​ ${Thread.currentThread().name}"​) 
 +            GlobalScope.launch{ 
 +                println("​coroutine:​ ${Thread.currentThread().name}"​) 
 +            } 
 +            println("​end:​ ${Thread.currentThread().name}"​) 
 +        } 
 + 
 +    } 
 +
 + 
 + ↓ 
 +start: main 
 +end: main 
 +coroutine: DefaultDispatcher-worker-1 
 +</​code>​ 
 + 
 + 
 + 
 +===== Threadとは比べ物にならないほど軽い! ​=====
  
 <code kotlin> <code kotlin>
ライン 47: ライン 98:
 </​code>​ </​code>​
  
 +===== launchと違いasyncは値を返す =====
 +<code kotlin>
 +import kotlinx.coroutines.*
 +import java.util.concurrent.atomic.AtomicLong
 +import kotlin.concurrent.thread
 +
 +fun main() {
 +    runBlocking {
 +        val sum = deferred.sumBy { it.await() }
 +        println("​Sum:​ $sum")
 +    }
 +}
 +
 +val deferred = (1..1_000_000).map { n ->
 +    GlobalScope.async {
 +        delay(1000)
 +
 +        n
 +    }
 +}
 + ↓
 +Sum: 1784293664
 +</​code>​
 +
 +===== mainスレッド(UIスレッド)へのアクセスが簡単 =====
 +
 +launchやasyncで新しいcoroutineを作成するが、Dispatchers.Mainで簡単にmainスレッドを呼び出せる。
 +今までのdoInBackgroundでpublishProgressを使ってonProgressUpdateを呼び出すようなことをしなくてよくなる。
 +
 +<code kotlin>
 +package com.nekotype.ips.myapplication
 +
 +import androidx.appcompat.app.AppCompatActivity
 +import android.os.Bundle
 +import android.util.Log
 +import kotlinx.android.synthetic.main.activity_main.*
 +import kotlinx.coroutines.*
 +import java.text.SimpleDateFormat
 +import java.util.*
 +
 +class MainActivity : AppCompatActivity() {
 +
 +    override fun onCreate(savedInstanceState:​ Bundle?) {
 +        super.onCreate(savedInstanceState)
 +        setContentView(R.layout.activity_main)
 +
 +        val format = SimpleDateFormat("​kk:​mm:​ss"​)
 +
 +        Log.d("​async",​ "​${text1.text} ${format.format(Date())} : ouerLaunch1 : ${Thread.currentThread().name}\n\n"​)
 +
 +        GlobalScope.launch {
 +
 +            Log.d("​async",​ "​${text1.text} ${format.format(Date())} : inLaunch1 : ${Thread.currentThread().name}\n\n"​)
 +
 +            async{
 +                delay(3000)
 +                Log.d("​async",​ "​${text1.text} ${format.format(Date())} : async1 : ${Thread.currentThread().name}\n\n"​)
 +            }
 +
 +            Log.d("​async",​ "​${text1.text} ${format.format(Date())} : inLaunch2 : ${Thread.currentThread().name}\n\n"​)
 +
 +
 +            async(Dispatchers.Main) {
 +                delay(1000)
 +                Log.d("​async",​ "​${text1.text} ${format.format(Date())} : async2 : ${Thread.currentThread().name}\n\n"​)
 +            }
 +
 +            async {
 +                delay(500)
 +                Log.d("​async","​${text1.text} ${format.format(Date())} : async3 : ${Thread.currentThread().name}\n\n"​)
 +                async(Dispatchers.Main) {
 +                    Log.d("​async",​ "​${text1.text} ${format.format(Date())} : inAsync3 : ${Thread.currentThread().name}\n\n"​)
 +                }
 +
 +            }
 +
 +        }
 +
 +        Log.d("​async","​${text1.text} ${format.format(Date())} : ouerLaunch2 : ${Thread.currentThread().name}\n\n"​)
 +    }
 +}
 +
 + ↓
 +
 +05:32:14 : ouerLaunch1 : main
 +05:32:14 : ouerLaunch2 : main
 +05:32:14 : inLaunch1 : DefaultDispatcher-worker-1
 +05:32:14 : inLaunch2 : DefaultDispatcher-worker-1
 +05:32:14 : async3 : DefaultDispatcher-worker-1
 +05:32:14 : inAsync3 : main // ⇒ worker-1 の内側からmainを呼び出している
 +05:32:15 : async2 : main
 +05:32:17 : async1 : DefaultDispatcher-worker-3
 +
 +</​code>​
 +
 +<code kotlin>
 +        Log.d( ​ "​coroutine","​start"​)
 +        GlobalScope.launch(Dispatchers.Main) {
 +                Log.d( ​ "​coroutine","​coroutin"​)
 +                Text.text="​click"​ // 画面のテキストを変更する
 +        }
 +        Log.d( ​ "​coroutine","​end"​)
 +   ↓
 +2020-01-14 06:​24:​17.847 7602-7602/​com.nekotype.ips.coroutine D/​coroutine:​ start
 +2020-01-14 06:​24:​17.847 7602-7602/​com.nekotype.ips.coroutine D/​coroutine:​ end
 +2020-01-14 06:​24:​17.849 7602-7602/​com.nekotype.ips.coroutine D/​coroutine:​ coroutin
 +</​code>​
 +===== キャンセル =====
 +
 +<​code>​
 +    private var myjob:Job? =null
 +    private ​ var myjobs= mutableListOf<​Job?>​()
 +
 +    ...
 +        myjob=GlobalScope.launch {
 +            progress_countdown.max=1000
 +    ...
 +    ​
 +    // 画面を閉じた場合にコルーチンをキャンセル
 +    override fun onPause() {
 +        super.onPause()
 +        myjobs.map {
 +            Log.d("​choice","​cancel"​)
 +            it?​.cancel()
 +        }
 +    }
 +
 +</​code>​
 +
 +===== join =====
 +コルーチン内で他のコルーチンの終了を待機する。
 +
 +<code kotlin>
 +    fun TestCoroutin(){
 +        Log.d( ​ "​coroutine","​start"​)
 +        GlobalScope.launch() {
 +
 +            launch {
 +                Log.d( ​ "​coroutine","​coroutin_inner"​)
 +            }
 +
 +            Log.d( ​ "​coroutine","​coroutin_outer"​)
 +        }
 +        Log.d( ​ "​coroutine","​end"​)
 +    }
 +    ↓
 +2020-01-14 06:​29:​12.311 7952-7952/​com.nekotype.ips.coroutine D/​coroutine:​ start
 +2020-01-14 06:​29:​12.340 7952-7952/​com.nekotype.ips.coroutine D/​coroutine:​ end
 +2020-01-14 06:​29:​12.347 7952-7998/​com.nekotype.ips.coroutine D/​coroutine:​ coroutin_outer
 +2020-01-14 06:​29:​12.348 7952-7999/​com.nekotype.ips.coroutine D/​coroutine:​ coroutin_inner
 +</​code>​
 + ↓
 +<code kotlin>
 +    fun TestCoroutin(){
 +        Log.d( ​ "​coroutine","​start"​)
 +        GlobalScope.launch() {
 +
 +            launch {
 +                Log.d( ​ "​coroutine","​coroutin_inner"​)
 +            }.join() // 待つ
 +
 +            Log.d( ​ "​coroutine","​coroutin_outer"​)
 +        }
 +        Log.d( ​ "​coroutine","​end"​)
 +    }
 +    ↓
 +2020-01-14 06:​30:​51.472 8058-8058/​com.nekotype.ips.coroutine D/​coroutine:​ start
 +2020-01-14 06:​30:​51.500 8058-8058/​com.nekotype.ips.coroutine D/​coroutine:​ end
 +2020-01-14 06:​30:​51.505 8058-8111/​com.nekotype.ips.coroutine D/​coroutine:​ coroutin_inner //​順番が変わる
 +2020-01-14 06:​30:​51.508 8058-8110/​com.nekotype.ips.coroutine D/​coroutine:​ coroutin_outer //​順番が変わる
 +</​code>​
 +
 +
 +===== runBlockingとasync =====
 +runBlockingとasyncは戻り値をもつことができる。
 +asyncは非同期に処理する。asyncにはawaitでまつことができる。
 +
 +===== まとめ =====
 +
 +UIにアクセスするには
 +GlobalScope.launch(Dispatchers.Main) {...
 +
 +Jobを取得してキャンセルするには
 +myjob=GlobalScope.launch { ...
 +myjob.cancel()
 +
 +戻り値を取得するには
 +runBlocking
 +async
 +
 +待ちたいとき(同期)
 +GlobalScope.launch() {
 +launch { ... }.join() ​
  
 +待ちたいとき(非同期) ​   ​
 +GlobalScope.launch() {
 +async { ... }.await() ​
kotlin/coroutines.1570052699.txt.gz · 最終更新: 2019/10/03 06:44 by ips