1

i want to update the local ip of the android system every time it changes in a textview, this is my code.

The function to obtain the ip is this

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

and the code inside the onCreate of the MainActivity.tk is this

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

I want it to update and show it in real time in the texview, for example after setting and removing airplane mode, or changing networks wifi-> mobile mobile-> wifi

here I leave as seen in the application, someone to help me please

enter image description here

N3R4ZZuRR0
  • 2,400
  • 4
  • 18
  • 32

2 Answers2

0

To receive event information at real time you can use different ways depending upon if your app is in foreground or background when the info is needed.

Since in your case the app seems to be in foreground, you make use of application.class to write code for receiving network changes using broadcast receiver( programatically registered) or some other way. And then in the function that receives that event change info , make a call to your getIpv4HostAddress() that would set the ip string and use it in the set the textview in another calss.

Kaveri
  • 1,060
  • 2
  • 12
  • 21
0

I've happened to have almost ready to use solution for this problem except extracting IPv4 address so I'll post it here so you could make use of it.

Basically, the solution consists of two main components: a "service" that listens to network changes and an RX subject to which you subscribe and post updates about network changes.

Step 0: Preparation

Make sure your AndroidManifest.xml file has next permissions included:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Your app has to enable compatibility options to allow the use of Java 8 features. Add the next lines in your build.gradle file:

android {
    ...
    compileOptions {
        targetCompatibility = "8"
        sourceCompatibility = "8"
    }
}

In order to make use of RX Kotlin add next dependencies:

implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
implementation 'io.reactivex.rxjava3:rxkotlin:3.0.0'

Step 1: Implement network change listener service

Imports are omitted to make code as concise as possible. NetworkReachabilityService is not a conventional Android service that you can start and it will run even when then the app is killed. It is a class that sets a listener to ConnectivityManager and handles all updates related to the network state.

Any type of update is handled similarly: something changed -> post NetworkState object with an appropriate value. On every change, we can request IPv4 to display in the UI (see on step 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
            )
        }
    }
}

Step 2: Implement a method to extract IPv4 (bonus IPv6)

I had to modify your IPv4 extraction a little as it did not return any IPv4 addresses while a device clearly had one. These are two methods to extract IPv4 and IPv6 addresses respectively. Methods were modified using this SO answer on how to extract IP addresses. Overall, it is 90% the same mapping of inetAddresses to the IP address values.

Add these two methods to 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()

Step 3: Update UI

The simples solution related to UI is a direct subscription to NETWORK_REACHABILITY subject and on each change received through that subject, we pull out IPv4 data from NetworkReachabilityService and display it in the UI. Two main methods you want to look at are subscribeToUpdates and updateIPv4Address. And do not forget to unsubscribe by using unsubscribeFromUpdates to prevent memory leaks.

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()
    }
}

Recap

Using a ConnectivityManager instance we set a listener which reacts on any network change. Each change triggers an update which posts value to RX subject holding the latest network state. By subscribing to the subject we can track network state changes and assume the device had its address changed and thus we refresh IPv4 value displayed in a TextView.

I decided this code was good to go on GitHub, so here is the link to the project.

Jenea Vranceanu
  • 4,530
  • 2
  • 18
  • 34
  • you are a genius, it worked perfectly my programming level is very basic and I still understand you ... thank you for taking the time to answer me in such detail, really thank you very much. regards – damian reyes Aug 01 '20 at 18:40
  • @damianreyes, you are welcome. All of the programmers started similarly - they had no or bare minimum knowledge. You are on a good path. – Jenea Vranceanu Aug 01 '20 at 20:40