BETA

Coroutineを使ってDialogを簡単に表示する

投稿日:2018-10-19
最終更新:2018-10-24

Coroutine時代のDialogFragment - Qiita に関して、Coroutineのみで完結させたい。

下準備

build.gradle(Module: app)の設定

dependencies {
    // ~~~
    // 以下の2つを追加、バージョンはその時の最新を導入する。
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.30.2'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:0.30.2'
}

// そのままだと警告が表示されるので抑制。
kotlin {
    experimental {
        coroutines "enable"
    }
}

実装

package com.practice.maccyo.coroutinesdialog

import android.app.AlertDialog
import android.app.Dialog
import android.app.DialogFragment
import android.app.FragmentManager
import android.os.Bundle
import kotlinx.coroutines.experimental.GlobalScope
import kotlinx.coroutines.experimental.channels.BroadcastChannel
import kotlinx.coroutines.experimental.launch

class MessageDialogFragment : DialogFragment() {
    enum class DialogResult {
        OK,
        Cancel
    }

    private var title = ""
    private var message = ""
    private var positiveText = ""
    private var negativeText = ""

    private val channel = BroadcastChannel<DialogResult>(1)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        arguments?.let {
            title = it.getString(ARG_TITLE)
            message = it.getString(ARG_MESSAGE)
            positiveText = it.getString(ARG_POSITIVE)
            negativeText = it.getString(ARG_NEGATIVE)
        }
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val builder = AlertDialog.Builder(activity)
        builder.setTitle(title)
            .setMessage(message)
            .setPositiveButton(positiveText) { _, _ -> GlobalScope.launch { channel.send(DialogResult.OK) } }
            .setNegativeButton(negativeText) { _, _ -> GlobalScope.launch { channel.send(DialogResult.Cancel) } }
        return builder.create()
    }

    suspend fun showAndSuspend(fm: FragmentManager, tag: String? = null): DialogResult {
        show(fm, tag)
        return channel.openSubscription().receive()
    }

    companion object {
        private const val ARG_TITLE = "title"
        private const val ARG_MESSAGE = "message"
        private const val ARG_POSITIVE = "positive"
        private const val ARG_NEGATIVE = "negative"

        @JvmStatic
        fun newInstance(title: String, message: String, positiveText: String = "OK", negativeText: String = "キャンセル") =
            MessageDialogFragment().apply {
                arguments = Bundle().apply {
                    putString(ARG_TITLE, title)
                    putString(ARG_MESSAGE, message)
                    putString(ARG_POSITIVE, positiveText)
                    putString(ARG_NEGATIVE, negativeText)
                }
            }
    }
}

使い方

        button.setOnClickListener {
            GlobalScope.launch(Dispatchers.Main) {
                val dialog = MessageDialogFragment.newInstance("タイトル", "メッセージ")
                val result = dialog.showAndSuspend(fragmentManager)
                val resultText = if (result == MessageDialogFragment.DialogResult.OK) "OK" else "Cancel"
                Toast.makeText([email protected], "結果:$resultText", Toast.LENGTH_LONG).show()
            }
        }

注意事項

画面回転時に再生成処理が走って情報を受け取れなくなる。元記事ではそのへんも対応していたが、どうすればいいのかがわからない...

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

@maccyoの技術ブログ(予定) C#/VB.NET/Kotlin/Delphi

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう