从MvvM体系结构和Kotlin中的广播接收器更新片段ui

问题描述 投票:0回答:1

作为Kotlin和mvvm架构的新手,我浪费了过去两天的时间,没有找到成功的答案。因此,我正在寻找一种干净的解决方案,以在设备在Internet中连接/断开连接时更改片段ui(在我的情况下,它只是一个textview)。我正在使用mvvm架构和android架构组件(viewmodels,livedata,数据绑定...)。我有一个基础活动,具有底部导航和多个片段。

我正在尝试从自定义广播接收器获取连接事件,并且我希望以某种方式在ViewModel或我的片段中传递该事件。

我的第一个想法是使用界面。此接口由广播接收器的onreceive触发,并且在我的片段或视图模型中实现,因此,当发生Internet事件时,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年的解决方案也将是一件好事。预先谢谢你。

android android-fragments kotlin mvvm broadcastreceiver
1个回答
0
投票

最终,我找到了想要的一种干净而现代的解决方案。诀窍是将BroadcastReceiver包装在LiveData中。通过使用此模式,您可以直接从片段中观察LiveDada的连接并更新ui。当然,也有可能(如提到的sergiy tikhonov一样)在基本活动中有一个随播对象,该对象带有一个从BroadcastReceiver更新的LiveData,您可以从片段中观察到它,但是我不喜欢这种方法。

所以它是这样的:

使用网络状态创建一个枚举。

enum class NetworkAvailability {
    UNKNOWN,
    CONNECTED,
    DISCONNECTED
}

创建扩展LiveData的类。我使用单例模式,因为我不需要多个实例。我创建一个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
                }
            })
© www.soinside.com 2019 - 2024. All rights reserved.