Android Kotlin 刷新文本视图
Android Kotlin refresh textview
我想在文本视图中每次更改时更新 android 系统的本地 ip,这是我的代码。
获取ip的函数是这个
fun getIpv4HostAddress(): String {
NetworkInterface.getNetworkInterfaces()?.toList()?.map { networkInterface ->
networkInterface.inetAddresses?.toList()?.find {
!it.isLoopbackAddress && it is Inet4Address
}?.let { return it.hostAddress }
}
return ""
}
MainActivity.tk 的 onCreate 中的代码是这样的
val textView: TextView = findViewById(R.id.getIP)
textView.setText("IP local: " + getIpv4HostAddress())
textView.invalidate()
我希望它在 texview 中实时更新和显示,例如在设置和删除飞行模式后,或者更改网络 wifi-> 移动 mobile-> wifi
这里我离开了,如申请中所示,请有人帮助我
要实时接收事件信息,您可以使用不同的方式,具体取决于您的应用在需要信息时是在前台还是后台。
由于在您的情况下应用程序似乎在前台,您利用 application.class
编写代码以使用广播接收器(以编程方式注册)或其他方式接收网络更改。然后在接收该事件更改信息的函数中,调用您的 getIpv4HostAddress()
来设置 ip string
并在另一个 calss 的 textview
集合中使用它。
除了提取 IPv4 地址之外,我几乎已经准备好使用解决方案来解决这个问题,所以我将 post 放在这里,以便您可以使用它。
基本上,该解决方案由两个主要组件组成:侦听网络变化的“服务”和您订阅的 RX subject 以及有关网络变化的 post 更新。
第 0 步:准备
确保您的 AndroidManifest.xml
文件具有以下权限:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
您的应用必须启用兼容性选项才能使用 Java 8 项功能。在您的 build.gradle
文件中添加下一行:
android {
...
compileOptions {
targetCompatibility = "8"
sourceCompatibility = "8"
}
}
为了使用 RX Kotlin 添加下一个依赖项:
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
implementation 'io.reactivex.rxjava3:rxkotlin:3.0.0'
第 1 步:实施网络更改侦听器服务
省略导入以使代码尽可能简洁。 NetworkReachabilityService
不是您可以启动的常规 Android 服务,它会 运行 即使应用程序被终止。它是一个 class 设置监听器 ConnectivityManager
并处理与网络状态相关的所有更新。
任何类型的更新都以类似方式处理:更改了某些内容 -> post NetworkState
具有适当值的对象。在每次更改时,我们都可以请求 IPv4 在 UI 中显示(参见步骤 3)。
sealed class NetworkState {
data class Available(val type: NetworkType) : NetworkState()
object Unavailable : NetworkState()
object Connecting : NetworkState()
object Losing : NetworkState()
object Lost : NetworkState()
}
sealed class NetworkType {
object WiFi : NetworkType()
object CELL : NetworkType()
object OTHER : NetworkType()
}
class NetworkReachabilityService private constructor(context: Application) {
private val connectivityManager: ConnectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
// There are more functions to override!
override fun onLost(network: Network) {
super.onLost(network)
postUpdate(NetworkState.Lost)
}
override fun onUnavailable() {
super.onUnavailable()
postUpdate(NetworkState.Unavailable)
}
override fun onLosing(network: Network, maxMsToLive: Int) {
super.onLosing(network, maxMsToLive)
postUpdate(NetworkState.Losing)
}
override fun onAvailable(network: Network) {
super.onAvailable(network)
updateAvailability(connectivityManager.getNetworkCapabilities(network))
}
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
super.onCapabilitiesChanged(network, networkCapabilities)
updateAvailability(networkCapabilities)
}
}
companion object {
// Subscribe to this subject to get updates on network changes
val NETWORK_REACHABILITY: BehaviorSubject<NetworkState> =
BehaviorSubject.createDefault(NetworkState.Unavailable)
private var INSTANCE: NetworkReachabilityService? = null
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
fun getService(context: Application): NetworkReachabilityService {
if (INSTANCE == null) {
INSTANCE = NetworkReachabilityService(context)
}
return INSTANCE!!
}
}
private fun updateAvailability(networkCapabilities: NetworkCapabilities?) {
if (networkCapabilities == null) {
postUpdate(NetworkState.Unavailable)
return
}
var networkType: NetworkType = NetworkType.OTHER
if (networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
networkType = NetworkType.CELL
}
if (networkCapabilities.hasTransport(TRANSPORT_WIFI)) {
networkType = NetworkType.WiFi
}
postUpdate(NetworkState.Available(networkType))
}
private fun postUpdate(networkState: NetworkState) {
NETWORK_REACHABILITY.onNext(networkState)
}
fun pauseListeningNetworkChanges() {
try {
connectivityManager.unregisterNetworkCallback(networkCallback)
} catch (e: IllegalArgumentException) {
// Usually happens only once if: "NetworkCallback was not registered"
}
}
fun resumeListeningNetworkChanges() {
pauseListeningNetworkChanges()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
connectivityManager.registerDefaultNetworkCallback(networkCallback)
} else {
connectivityManager.registerNetworkCallback(
NetworkRequest.Builder().build(),
networkCallback
)
}
}
}
第 2 步:实现提取 IPv4 的方法(奖励 IPv6)
我不得不稍微修改您的 IPv4 提取,因为它没有 return 任何 IPv4 地址,而设备显然有一个。这是分别提取 IPv4 和 IPv6 地址的两种方法。使用 this SO answer 修改了如何提取 IP 地址的方法。总体而言,inetAddresses
到 IP 地址值的映射有 90% 相同。
将这两个方法添加到NetworkReachabilityService
class:
fun getIpv4HostAddress(): String? =
NetworkInterface.getNetworkInterfaces()?.toList()?.mapNotNull { networkInterface ->
networkInterface.inetAddresses?.toList()
?.filter { !it.isLoopbackAddress && it.hostAddress.indexOf(':') < 0 }
?.mapNotNull { if (it.hostAddress.isNullOrBlank()) null else it.hostAddress }
?.firstOrNull { it.isNotEmpty() }
}?.firstOrNull()
fun getIpv6HostAddress(): String? =
NetworkInterface.getNetworkInterfaces()?.toList()?.mapNotNull { networkInterface ->
networkInterface.inetAddresses?.toList()
?.filter { !it.isLoopbackAddress && it is Inet6Address }
?.mapNotNull { if (it.hostAddress.isNullOrBlank()) null else it.hostAddress }
?.firstOrNull { it.isNotEmpty() }
}?.firstOrNull()
第 3 步:更新 UI
与 UI 相关的简单解决方案是直接订阅 NETWORK_REACHABILITY
主题,并且在通过该主题收到的每个更改中,我们从 NetworkReachabilityService
中提取 IPv4 数据并将其显示在UI。您要查看的两个主要方法是 subscribeToUpdates
和 updateIPv4Address
。并且不要忘记使用 unsubscribeFromUpdates
取消订阅以防止内存泄漏。
class MainActivity : AppCompatActivity() {
private val compositeDisposable = CompositeDisposable()
private lateinit var textView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
textView = findViewById(R.id.text_view)
val service = NetworkReachabilityService.getService(application)
service.resumeListeningNetworkChanges()
subscribeToUpdates()
}
override fun onDestroy() {
super.onDestroy()
unsubscribeFromUpdates()
}
private fun unsubscribeFromUpdates() {
compositeDisposable.dispose()
compositeDisposable.clear()
}
private fun subscribeToUpdates() {
val disposableSubscription =
NetworkReachabilityService.NETWORK_REACHABILITY
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ networkState ->
// We do not care about networkState right now
updateIPv4Address()
}, {
// Handle the error
it.printStackTrace()
})
compositeDisposable.addAll(disposableSubscription)
}
private fun updateIPv4Address() {
val service = NetworkReachabilityService.getService(application)
textView.text = service.getIpv4HostAddress()
}
}
回顾
使用 ConnectivityManager
实例,我们设置了一个监听器,它对任何网络变化做出反应。每次更改都会触发更新,其中 posts 对持有最新网络状态的 RX 主体的价值。通过订阅主题,我们可以跟踪网络状态变化并假设设备的地址已更改,因此我们刷新 TextView
.
中显示的 IPv4 值
我认为这段代码可以继续 GitHub,所以这里是 the link to the project。
我想在文本视图中每次更改时更新 android 系统的本地 ip,这是我的代码。
获取ip的函数是这个
fun getIpv4HostAddress(): String {
NetworkInterface.getNetworkInterfaces()?.toList()?.map { networkInterface ->
networkInterface.inetAddresses?.toList()?.find {
!it.isLoopbackAddress && it is Inet4Address
}?.let { return it.hostAddress }
}
return ""
}
MainActivity.tk 的 onCreate 中的代码是这样的
val textView: TextView = findViewById(R.id.getIP)
textView.setText("IP local: " + getIpv4HostAddress())
textView.invalidate()
我希望它在 texview 中实时更新和显示,例如在设置和删除飞行模式后,或者更改网络 wifi-> 移动 mobile-> wifi
这里我离开了,如申请中所示,请有人帮助我
要实时接收事件信息,您可以使用不同的方式,具体取决于您的应用在需要信息时是在前台还是后台。
由于在您的情况下应用程序似乎在前台,您利用 application.class
编写代码以使用广播接收器(以编程方式注册)或其他方式接收网络更改。然后在接收该事件更改信息的函数中,调用您的 getIpv4HostAddress()
来设置 ip string
并在另一个 calss 的 textview
集合中使用它。
除了提取 IPv4 地址之外,我几乎已经准备好使用解决方案来解决这个问题,所以我将 post 放在这里,以便您可以使用它。
基本上,该解决方案由两个主要组件组成:侦听网络变化的“服务”和您订阅的 RX subject 以及有关网络变化的 post 更新。
第 0 步:准备
确保您的 AndroidManifest.xml
文件具有以下权限:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
您的应用必须启用兼容性选项才能使用 Java 8 项功能。在您的 build.gradle
文件中添加下一行:
android {
...
compileOptions {
targetCompatibility = "8"
sourceCompatibility = "8"
}
}
为了使用 RX Kotlin 添加下一个依赖项:
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
implementation 'io.reactivex.rxjava3:rxkotlin:3.0.0'
第 1 步:实施网络更改侦听器服务
省略导入以使代码尽可能简洁。 NetworkReachabilityService
不是您可以启动的常规 Android 服务,它会 运行 即使应用程序被终止。它是一个 class 设置监听器 ConnectivityManager
并处理与网络状态相关的所有更新。
任何类型的更新都以类似方式处理:更改了某些内容 -> post NetworkState
具有适当值的对象。在每次更改时,我们都可以请求 IPv4 在 UI 中显示(参见步骤 3)。
sealed class NetworkState {
data class Available(val type: NetworkType) : NetworkState()
object Unavailable : NetworkState()
object Connecting : NetworkState()
object Losing : NetworkState()
object Lost : NetworkState()
}
sealed class NetworkType {
object WiFi : NetworkType()
object CELL : NetworkType()
object OTHER : NetworkType()
}
class NetworkReachabilityService private constructor(context: Application) {
private val connectivityManager: ConnectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
// There are more functions to override!
override fun onLost(network: Network) {
super.onLost(network)
postUpdate(NetworkState.Lost)
}
override fun onUnavailable() {
super.onUnavailable()
postUpdate(NetworkState.Unavailable)
}
override fun onLosing(network: Network, maxMsToLive: Int) {
super.onLosing(network, maxMsToLive)
postUpdate(NetworkState.Losing)
}
override fun onAvailable(network: Network) {
super.onAvailable(network)
updateAvailability(connectivityManager.getNetworkCapabilities(network))
}
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
super.onCapabilitiesChanged(network, networkCapabilities)
updateAvailability(networkCapabilities)
}
}
companion object {
// Subscribe to this subject to get updates on network changes
val NETWORK_REACHABILITY: BehaviorSubject<NetworkState> =
BehaviorSubject.createDefault(NetworkState.Unavailable)
private var INSTANCE: NetworkReachabilityService? = null
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
fun getService(context: Application): NetworkReachabilityService {
if (INSTANCE == null) {
INSTANCE = NetworkReachabilityService(context)
}
return INSTANCE!!
}
}
private fun updateAvailability(networkCapabilities: NetworkCapabilities?) {
if (networkCapabilities == null) {
postUpdate(NetworkState.Unavailable)
return
}
var networkType: NetworkType = NetworkType.OTHER
if (networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
networkType = NetworkType.CELL
}
if (networkCapabilities.hasTransport(TRANSPORT_WIFI)) {
networkType = NetworkType.WiFi
}
postUpdate(NetworkState.Available(networkType))
}
private fun postUpdate(networkState: NetworkState) {
NETWORK_REACHABILITY.onNext(networkState)
}
fun pauseListeningNetworkChanges() {
try {
connectivityManager.unregisterNetworkCallback(networkCallback)
} catch (e: IllegalArgumentException) {
// Usually happens only once if: "NetworkCallback was not registered"
}
}
fun resumeListeningNetworkChanges() {
pauseListeningNetworkChanges()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
connectivityManager.registerDefaultNetworkCallback(networkCallback)
} else {
connectivityManager.registerNetworkCallback(
NetworkRequest.Builder().build(),
networkCallback
)
}
}
}
第 2 步:实现提取 IPv4 的方法(奖励 IPv6)
我不得不稍微修改您的 IPv4 提取,因为它没有 return 任何 IPv4 地址,而设备显然有一个。这是分别提取 IPv4 和 IPv6 地址的两种方法。使用 this SO answer 修改了如何提取 IP 地址的方法。总体而言,inetAddresses
到 IP 地址值的映射有 90% 相同。
将这两个方法添加到NetworkReachabilityService
class:
fun getIpv4HostAddress(): String? =
NetworkInterface.getNetworkInterfaces()?.toList()?.mapNotNull { networkInterface ->
networkInterface.inetAddresses?.toList()
?.filter { !it.isLoopbackAddress && it.hostAddress.indexOf(':') < 0 }
?.mapNotNull { if (it.hostAddress.isNullOrBlank()) null else it.hostAddress }
?.firstOrNull { it.isNotEmpty() }
}?.firstOrNull()
fun getIpv6HostAddress(): String? =
NetworkInterface.getNetworkInterfaces()?.toList()?.mapNotNull { networkInterface ->
networkInterface.inetAddresses?.toList()
?.filter { !it.isLoopbackAddress && it is Inet6Address }
?.mapNotNull { if (it.hostAddress.isNullOrBlank()) null else it.hostAddress }
?.firstOrNull { it.isNotEmpty() }
}?.firstOrNull()
第 3 步:更新 UI
与 UI 相关的简单解决方案是直接订阅 NETWORK_REACHABILITY
主题,并且在通过该主题收到的每个更改中,我们从 NetworkReachabilityService
中提取 IPv4 数据并将其显示在UI。您要查看的两个主要方法是 subscribeToUpdates
和 updateIPv4Address
。并且不要忘记使用 unsubscribeFromUpdates
取消订阅以防止内存泄漏。
class MainActivity : AppCompatActivity() {
private val compositeDisposable = CompositeDisposable()
private lateinit var textView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
textView = findViewById(R.id.text_view)
val service = NetworkReachabilityService.getService(application)
service.resumeListeningNetworkChanges()
subscribeToUpdates()
}
override fun onDestroy() {
super.onDestroy()
unsubscribeFromUpdates()
}
private fun unsubscribeFromUpdates() {
compositeDisposable.dispose()
compositeDisposable.clear()
}
private fun subscribeToUpdates() {
val disposableSubscription =
NetworkReachabilityService.NETWORK_REACHABILITY
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ networkState ->
// We do not care about networkState right now
updateIPv4Address()
}, {
// Handle the error
it.printStackTrace()
})
compositeDisposable.addAll(disposableSubscription)
}
private fun updateIPv4Address() {
val service = NetworkReachabilityService.getService(application)
textView.text = service.getIpv4HostAddress()
}
}
回顾
使用 ConnectivityManager
实例,我们设置了一个监听器,它对任何网络变化做出反应。每次更改都会触发更新,其中 posts 对持有最新网络状态的 RX 主体的价值。通过订阅主题,我们可以跟踪网络状态变化并假设设备的地址已更改,因此我们刷新 TextView
.
我认为这段代码可以继续 GitHub,所以这里是 the link to the project。