Android Kotlin refre sh textview - PullRequest
       75

Android Kotlin refre sh textview

1 голос
/ 01 августа 2020

Я хочу обновлять локальный IP-адрес системы android каждый раз, когда он изменяется в текстовом представлении, это мой код.

Функция для получения IP-адреса:

fun getIpv4HostAddress(): String {
    NetworkInterface.getNetworkInterfaces()?.toList()?.map { networkInterface ->
        networkInterface.inetAddresses?.toList()?.find {
            !it.isLoopbackAddress && it is Inet4Address
        }?.let { return it.hostAddress }
    }
    return ""
}

, а код внутри onCreate файла MainActivity.tk - это

val textView: TextView = findViewById(R.id.getIP)
    textView.setText("IP local: " + getIpv4HostAddress())
    textView.invalidate()

Я хочу, чтобы он обновлялся и отображался в реальном времени в texview, например, после установки и удаления режима полета или изменения сети wifi-> mobile mobile-> wifi

здесь оставляю как видно в приложении, кто-нибудь мне в помощь пожалуйста

введите описание изображения здесь

Ответы [ 2 ]

0 голосов
/ 01 августа 2020

У меня было почти готовое решение для этой проблемы, кроме извлечения IPv4-адреса, поэтому я отправлю его здесь, чтобы вы могли его использовать.

В основном, решение состоит из двух основных компонентов: «службы», которая отслеживает сетевые изменения, и тема RX , на которую вы подписываетесь и публикуете обновления об изменениях в сети.

Шаг 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: Реализуйте прослушиватель сетевых изменений service

Импорт опущен, чтобы код был как можно более лаконичным. NetworkReachabilityService - это не обычная служба Android, которую вы можете запустить, и она будет работать, даже когда приложение будет убито. Это класс, который устанавливает прослушиватель на ConnectivityManager и обрабатывает все обновления, связанные с состоянием сети.

Любой тип обновления обрабатывается аналогично: что-то изменено -> сообщение NetworkState объект с соответствующим значением. При каждом изменении мы можем запросить IPv4 для отображения в пользовательском интерфейсе (см. Шаг 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, так как он не возвращал никаких IPv4-адресов, в то время как устройство явно имело один. Это два метода извлечения адресов IPv4 и IPv6 соответственно. Методы были изменены с использованием этого SO-ответа о том, как извлекать IP-адреса. В целом, это на 90% то же сопоставление inetAddresses со значениями IP-адресов.

Добавьте эти два метода в 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: Обновите пользовательский интерфейс

Простое решение, связанное с пользовательским интерфейсом, представляет собой прямую подписку на тему NETWORK_REACHABILITY, и при каждом изменении, полученном через эту тему, мы извлекаем данные IPv4 из NetworkReachabilityService и отображаем их в пользовательском интерфейсе. Вы хотите рассмотреть два основных метода: 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, мы устанавливаем слушателя, который реагирует на любое изменение сети. Каждое изменение запускает обновление, которое отправляет значение субъекту RX, содержащему последнее состояние сети. Подписавшись на эту тему, мы можем отслеживать изменения состояния сети и предполагать, что у устройства был изменен адрес, и, таким образом, мы обновили sh значение IPv4, отображаемое в TextView.

Я решил, что этот код подходит для go на GitHub, поэтому здесь ссылка на проект .

0 голосов
/ 01 августа 2020

Для получения информации о событиях в реальном времени вы можете использовать разные способы в зависимости от того, находится ли ваше приложение на переднем плане или в фоновом режиме, когда информация необходима.

Поскольку в вашем случае приложение кажется на переднем плане, вы используйте application.class, чтобы написать код для приема сетевых изменений с помощью широковещательного приемника (зарегистрированного программно) или каким-либо другим способом. Затем в функции, которая получает эту информацию об изменении события, вызовите свой getIpv4HostAddress(), который установит ip string и использует его в наборе textview в другом вызове.

...