LoginSignup
11
7

More than 5 years have passed since last update.

Coroutineを用いてonActivityResultを簡潔に実装する

Last updated at Posted at 2019-04-26

startActivityForResultとonActivityResult

通常立ち上げたactivityから結果を受け取るには
requestCodeを定義し。startActivityForResultを呼び出し
onActivityResultをoverrideして結果を受け取ります。

機能が増えていくとrequestCodeの定義とonActivityResultの中の
実装が増えていき煩雑になっていきます。

Coroutineを用いたonActivityResultの実装

本記事はcoroutineを用いてstartActivityForResultからonActivityResultまでの
処理をシンプルに実装する処理を紹介します。

BaseActivityの実装

まず、親となるActivityにcoroutineを用いて
onActivityResultの待ち合わせ処理を実装します。

BaseActivity.kt
abstract class BaseActivity : AppCompatActivity() {

    companion object {
        private const val REQUEST_CODE_DEFERRED = 10001
    }
    //onActivityResultの結果待ち合わせ用
    private var deferredResult = CompletableDeferred<ActivityResult>()

    //startActivityForResult同時に待ち合わせ開始
    fun launchStartActivityForResult(intent: Intent): Deferred<ActivityResult> {
        if(deferredResult.isActive) deferredResult.cancel()
        deferredResult = CompletableDeferred()
        startActivityForResult(intent, REQUEST_CODE_DEFERRED)
        return deferredResult
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if(requestCode == REQUEST_CODE_DEFERRED) {
            //結果受け取り
            deferredResult.complete(ActivityResult(resultCode, data))
        } else {
            super.onActivityResult(requestCode, resultCode, data)
        }
    }
}

class ActivityResult(val resultCode: Int, val data: Intent?) { }

deferredResultというCompletableDeferred型の待ち合わせオブジェクトを定義し、
launchStartActivityForResult関数で待ち合わせを始めて、
onActivityResultで結果を受け取ります。

呼び出し側の例

上記で実装した関数を用いてカメラのIntentから結果を受け取るサンプル

SampleActivity.kt
button.setOnClickListener {
  val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
  GlobalScope.launch(Dispatchers.Main) {
    //startActivityForResultの結果の待ち合わせ
    val activityResult = launchStartActivityForResult(intent).await()
    if(activityResult.resultCode != Activity.RESULT_OK) return@launch
    activityResult.data?.extras?.let { bundle ->
      val bitmap = bundle.get("data") as Bitmap
      //do something
    }
  }
}

BaseActiviyを継承したActivityで
coroutineスコープ内にてlaunchStartActivityForResult()を呼び
その返り値をawait()関数で待ちその後結果を処理します。

まとめ

coroutineのスレッド待ち合わせを使うことによりstartActivityForResultからonActivityResultまでの処理をまとめて実装することができ、
requestCodeの定義も無くすことができました。

参考

kotlinx.cotoutines CompletableDeferred

11
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
7