[英]How to update fragment UI with data from SQLite in the onReceive() of Broadcast Receiver
[英]Update fragment ui from broadcast receiver in MvvM architecture and Kotlin
作為 kotlin 和 mvvm 架構的新手,我浪費了過去兩天來尋找這個問題的答案,但沒有任何成功。 所以我正在尋找一個干凈的解決方案來更改片段 ui(在我的情況下它只是一個文本視圖),當設備在互聯網上連接/斷開時。 我正在使用 mvvm 架構和 android 架構組件(視圖模型、實時數據、數據綁定......)。 我有一個帶有底部導航和多個片段的基本活動。
我正在嘗試從自定義廣播接收器獲取連接事件,並且我想以某種方式在視圖模型或我的片段中傳遞該事件。
我的第一個想法是使用接口。 此接口由 broadcastreceiver 的 onreceive 觸發,並在我的片段或視圖模型中實現,因此當互聯網事件發生時,textview 在我的片段中更新。 但是我不確定如何在廣播接收器中使用該接口,或者我不知道即使這是可能的還是一個好的做法。
到目前為止我所做的是創建廣播接收器
class ConnectionStateObserver: BroadcastReceiver() {
override fun onReceive(p0: Context?, p1: Intent?) {
//somehow use the interface in here
}
}
在我的基本活動中注冊/注銷它
override fun onResume() {
super.onResume()
val broadcastIntent = IntentFilter()
broadcastIntent.addAction(ConnectivityManager.CONNECTIVITY_ACTION)
registerReceiver(ConnectionStateObserver(), broadcastIntent)
}
override fun onPause() {
super.onPause()
unregisterReceiver(ConnectionStateObserver())
}
(我知道 ConnectivityManager.CONNECTIVITY_ACTION 已被棄用,但我找不到更好的解決方案)。
創建接口
interface ConnectionStatusChange{
fun onChange()
}
並在我的片段中實現接口
class myFragment : Fragment(), ConnectionStatusChange {
override fun onChange() {
// do the ui changes here
}
}
我想知道這種方法是否是一種好的做法,以及如何使其發揮作用。 如果無法做到這一點,請給我一些建議(代碼總是很感激。=)),另外最好有一個現代的。 而不是 5 年前的解決方案。 先感謝您。
最終我找到了一個我想要的干凈和現代的解決方案。 訣竅是將 BroadcastReceiver 包裝在 LiveData 中。 通過使用此模式,您可以直接從片段中觀察連接 LiveDada 並更新 ui。 當然,也有可能(就像提到的 sergiy tikhonov 一樣)在基礎活動中擁有一個伴隨的 object,其中的 LiveData 是從 BroadcastReceiver 更新的,您可以從片段中觀察它,但我不喜歡這種方法。
所以它是這樣工作的:
創建一個包含網絡狀態的枚舉。
enum class NetworkAvailability {
UNKNOWN,
CONNECTED,
DISCONNECTED
}
創建擴展 LiveData 的 class。 我正在使用 singleton 模式,因為我不想要多個實例。 我創建了一個 BroadcastReceiver 實例,並在 LiveData 的 onActive 和 onInactive 方法中注冊/取消注冊它。
class ConnectionStateLiveData(val context: Context) : LiveData<NetworkAvailability>() {
companion object {
private lateinit var instance: ConnectionStateLiveData
fun get(context: Context): ConnectionStateLiveData {
instance = if (::instance.isInitialized){
instance
}else{
ConnectionStateLiveData(context)
}
return instance
}
}
private val connectivityBroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(p0: Context?, p1: Intent?) {
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val netInfo = connectivityManager.activeNetworkInfo
value = if (netInfo != null && netInfo.isConnected) {
NetworkAvailability.CONNECTED
} else {
NetworkAvailability.DISCONNECTED
}
}
}
override fun onActive() {
super.onActive()
value = NetworkAvailability.UNKNOWN
val broadcastIntent = IntentFilter()
broadcastIntent.addAction(ConnectivityManager.CONNECTIVITY_ACTION)
context.registerReceiver(connectivityBroadcastReceiver, broadcastIntent)
}
override fun onInactive() {
super.onInactive()
context.unregisterReceiver(connectivityBroadcastReceiver)
}
}
最后,我觀察了片段中的 LiveData。
ConnectionStateLiveData.get(context).observe(viewLifecycleOwner, Observer {
if (it == NetworkAvailability.CONNECTED) {
binding.noInternetTextView.visibility = View.GONE
}
})
public class ReceiverLiveData<T> extends LiveData<T> {
private final Context context;
private final IntentFilter filter;
private final BiFunction<Context, Intent, T> mapFunc;
public ReceiverLiveData(Context context, IntentFilter filter, BiFunction<Context, Intent, T> mapFunc) {
this.context = context;
this.filter = filter;
this.mapFunc = mapFunc;
}
@Override
protected void onInactive() {
super.onInactive();
context.unregisterReceiver(mBroadcastReceiver);
}
@Override
protected void onActive() {
super.onActive();
//initialize LiveData value
mBroadcastReceiver.onReceive(context, null);
context.registerReceiver(mBroadcastReceiver, filter);
}
final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
setValue(mapFunc.apply(context, intent));
}
};
}
public static class ViewModel extends AndroidViewModel {
public ViewModel(@NonNull Application application) {
super(application);
}
public final LiveData<NetworkInfo> activeNetworkInfoLiveData = new ReceiverLiveData<>(getApplication(), new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION), (c, i) -> ((ConnectivityManager) c.getSystemService(CONNECTIVITY_SERVICE)).getActiveNetworkInfo());
}
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="viewModel"
type="com.XXXX.settingitemtest.MainActivity.ViewModel" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text='@{viewModel.activeNetworkInfoLiveData.connected ? "Connected" : "Disconnected"}'/>
</LinearLayout>
</layout>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.