非同期でUIの更新を行うときに気にしないといけないことが多いですよね 今ではRxjavaを使えば、あまり気にすることはないんですが、AsyncTaskLoaderを使う場合は、気にしないといけません。
私も一部分で、AsyncTaskLoaderを使っていて、罠にはまりました。
MainActivity
// LoaderCallbacksの関数をオーバーライドして、処理を変更したコールバックオブジェクトを作成する private val getRssUrlCallback : LoaderManager.LoaderCallbacks<Rss> = object : LoaderManager.LoaderCallbacks<Rss> { override fun onLoadFinished(loader: Loader<Rss>?, data: Rss?) { if (data?.feedUrl.isNullOrBlank()) { var dialog = AlertDialog() dialog.title = "対応していません" dialog.onOkClickListener = DialogInterface.OnClickListener { dialog, which -> } dialog.show(supportFragmentManager, null) } } }
Activityでコールバック用のオブジェクトを作成しています。 自作のアラートを表示させる予定でしたが、下記エラーでアプリがクラッシュしました。
java.lang.IllegalStateException: Can not perform this action inside of onLoadFinished
どうやら、onLoadFinished()内でダイアログを表示してはいけないようです。
対処法は2つあります。
①Handlerを使う
MainActivity
private val getRssUrlCallback : LoaderManager.LoaderCallbacks<Rss> = object : LoaderManager.LoaderCallbacks<Rss> { override fun onLoadFinished(loader: Loader<Rss>?, data: Rss?) { if (data?.feedUrl.isNullOrBlank()) { progressBar.visibility = android.widget.ProgressBar.INVISIBLE val handler = Handler() handler.post { var dialog = AlertDialog() dialog.title = "対応していません" dialog.onOkClickListener = DialogInterface.OnClickListener { dialog, which -> } dialog.show(supportFragmentManager, null) } } } }
Handler.post()でUIスレッドにRunnableに送るので、UIスレッドの更新が行えます。 Handlerの説明は下記サイトがわかりやすいかと思います。
LoaderManager.LoaderCallbacksインタフェースのAPIまとめ
この辺りはまだあまり詳しくないため、調べてみようと思います。
②AndroidAlertBuilderを使う
MainActivity
private val getRssUrlCallback : LoaderManager.LoaderCallbacks<Rss> = object : LoaderManager.LoaderCallbacks<Rss> { override fun onLoadFinished(loader: Loader<Rss>?, data: Rss?) { if (data?.feedUrl.isNullOrBlank()) { alert("対応していません") { yesButton {} }.show() } } }
これだとFragmentを継承していないので、エラーは発生しません。