結果的に凄く楽です。
しかし、処理後のデータを表示に利用する時は、場合により同じコルーチンの中で使う事。
外に出して問題が無ければ良いが、操作は同じなのに画面表示の状態が変わってしまう時は疑ってみる。
async { }.await() に騙されてはいけない。
UIスレッドで処理後データが予想と異なることが良くある。タイミングの問題?
原因が分からず、対処療法で何日も悩み、コルーチン内に置くことで操作と結果が毎回予想と同じになりました。
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_progressBar = requireActivity().findViewById(R.id.progressbar)
}
fun proc() {
ProgressBar.VISIBLE.also { _progressBar!!.visibility = it }
CoroutineScope(Dispatchers.Default).launch {
async { /* 長い処理 */ }.await()
withContext(Dispatchers.Main){
/* scrollToPosition()などを使う場合はコルーチンの中にまとめる */
_recyclerView!!.setAdapter( adapter() )
if (sw) _recyclerView!!.scrollToPosition(position()) // adapter()、position()は割愛
ProgressBar.GONE.also { _progressBar!!.visibility = it }
}
}
}
【追記】
async { }.await() は、コルーチンの中では戻り値が帰るまでワーカースレッドの他を待たせる。
UIスレッドは動き続けていて長い処理が終わっていなくてもデータへのアクセスができてしまう。
今回はデータを使う部分をコルーチンの中に入れて思い通りの動作にしたという事。
状況によってはコールバックを使わないと望む動作にならないかな。それは面倒くさいな。
他のViewの反応をAllWaitFlag で強制帰還で飛ばしてしまおう。
【追記の追記】
処理が短時間で終わる時にグルグルがフラッシュしてしまう。
気になる場合は、postDelayed() を利用する。
var flag:Boolean = true
Handler(Looper.getMainLooper()).postDelayed({
if (flag) ProgressBar.VISIBLE.also { _progressBar!!.visibility = it }
},100)
CoroutineScope(Dispatchers.Default).launch {
async { /* 処理 */ }.await() // ワーカースレッドで実行
withContext(Dispatchers.Main) { // UIスレッドに移って実行
// UIスレッドで処理後の内容を設定する
flag = false
ProgressBar.GONE.also { _progressBar!!.visibility = it }
}
}
時間経過後にグルグルを表示する設定。ここでは 0.1秒の設定。
処理が終わっていればフラグを倒してグルグルを非表示にする。
時間経過後に実行される場合、もうフラグが倒れているので何もしない。
処理が長引いた場合は、時間経過後にグルグル表示する。
ワーカースレッドの処理が終わり、後処理も済めばグルグルを非表示にする。
設定時間経過より短い場合はグルグルが表示されない。
処理が長い場合はグルグルが表示される。
コードの条件により上手く動作しない事もある。
その場合は遅延表示を諦める