コルーチンからLiveDataの更新をトリガーしようとしています:
object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
AddressList.value = listOf()
GlobalScope.launch {
AddressList.value = getAddressList()
}
return AddressList
}
しかし、私は次のエラーを受け取ります:
IllegalStateException:バックグラウンドスレッドでsetValueを呼び出せない
コルーチンで動作させる方法はありますか?
_liveData.value = value
_の代わりにliveData.postValue(value)
を使用します。非同期と呼ばれます。
ドキュメント から:
postValue-指定された値を設定するためにタスクをメインスレッドにポストします。
次のいずれかを実行できます。
object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
AddressList.value = listOf()
GlobalScope.launch {
AddressList.postValue(getAddressList())
}
return AddressList
}
または
fun getAddressesLiveData(): LiveData<List<Address>> {
AddressList.value = listOf()
GlobalScope.launch {
val adresses = getAddressList()
withContext(Dispatchers.Main) {
AddressList.value = adresses
}
}
return AddressList
}
私の場合、起動引数にDispatchers.Mainを追加する必要があり、正常に機能しました。
val job = GlobalScope.launch(Dispatchers.Main) {
delay(1500)
search(query)
}
他の人が指摘したように、この場合、ライブラリはメインスレッドに操作をポストする独自のメソッドを提供しますが、コルーチンは、特定のライブラリの機能に関係なく機能する一般的なソリューションを提供します。
最初のステップは、バックグラウンドジョブのGlobalScope
の使用を停止することです。これを行うと、アクティビティ、スケジュールされたジョブ、またはこれから呼び出したすべての作業単位が破壊され、さらにジョブがリークするリークが発生します。バックグラウンドで続行し、その結果をメインスレッドに送信します。 GlobalScope
の公式ドキュメント の内容は次のとおりです。
アプリケーションコードは通常、アプリケーション定義のCoroutineScopeを使用する必要があります。GlobalScopeのインスタンスで非同期または起動を使用することはお勧めしません。
独自のコルーチンスコープを定義し、そのcoroutineContext
プロパティにディスパッチャとして_Dispatchers.Main
_を含める必要があります。さらに、関数呼び出し内でジョブを起動してLiveData
(基本的には別の種類のFuture
)を返すパターン全体は、コルーチンを使用する最も便利な方法ではありません。代わりに
_suspend fun getAddresses() = withContext(Dispatchers.Default) { getAddressList() }
_
呼び出しサイトではコルーチンをlaunch
する必要があります。コルーチン内で、ブロッキングメソッドのようにgetAddresses()
を自由に呼び出して、アドレスを直接戻り値として取得できます。
withContext(Dispatchers.Main){}
を使用することで可能であることがわかりました。
object AddressList: MutableLiveData<List<Address>>()
fun getAddressesLiveData(): LiveData<List<Address>> {
GlobalScope.launch {
withContext(Dispatchers.Main){ AddressList.value = getAddressList() }
}
return AddressList
}
Coroutinesを使用してUIを更新する場合、これを達成する方法は2つあります
GlobalScope.launch(Dispatchers.Main):
GlobalScope.launch(Dispatchers.Main) {
delay(1000) // 1 sec delay
// call to UI thread
}
そして、いくつかの作業をバックグラウンドで実行したいが、その後Iを更新したい場合、これは次のようにして達成できます。
withContext(Dispatchers.Main)
GlobalScope.launch {
delay(1000) // 1 sec delay
// do some background task
withContext(Dispatchers.Main) {
// call to UI thread
}
}