Skip to content

Network Monitoring

Network monitoring automatically detects internet connectivity changes and notifies your application, enabling intelligent reconnection strategies and user experience improvements.

Overview

Mobile devices frequently switch between network types: - WiFi ↔ Cellular data - Network disconnections - Airplane mode toggles - Poor signal areas

Network monitoring helps your app respond appropriately to these changes.

Configuration

Enable Network Monitoring

Configure through the bridge:

class MyBridge : PulseMqttKitBridge {
    override fun getNetworkConfig(): NetworkMonitoringConfig {
        return NetworkMonitoringConfig(enabled = true)
    }

    // Other bridge methods...
}

Disable Network Monitoring

override fun getNetworkConfig(): NetworkMonitoringConfig {
    return NetworkMonitoringConfig(enabled = false)  // Default
}

Receiving Network Events

Implement [MqttUpdatesListener.onInternetConnectionStatusChanged]:

class NetworkAwareListener : MqttUpdatesListener {
    override fun onInternetConnectionStatusChanged(isConnected: Boolean) {
        if (isConnected) {
            logger.info("Network connected")
            handleNetworkRestored()
        } else {
            logger.warning("Network disconnected")
            handleNetworkLost()
        }
    }

    private fun handleNetworkRestored() {
        // Check if MQTT needs reconnection
        if (pulseMqttKit.isConnected() == false) {
            pulseMqttKit.submitCommand(ConnectCommand(connectionOptions))
        }

        // Update UI
        showOnlineIndicator()
    }

    private fun handleNetworkLost() {
        // Pause non-critical operations
        pauseBackgroundSync()

        // Update UI
        showOfflineIndicator()
        showNetworkErrorMessage()
    }
}

pulseMqttKit.addListener(NetworkAwareListener())

Usage Patterns

Pattern 1: Intelligent Reconnection

class SmartReconnectionHandler : MqttUpdatesListener {
    private var wasDisconnectedDueToNetwork = false

    override fun onMqttConnectionLost(cause: Throwable?) {
        // Mark as potentially network-related
        wasDisconnectedDueToNetwork = true
    }

    override fun onInternetConnectionStatusChanged(isConnected: Boolean) {
        if (isConnected && wasDisconnectedDueToNetwork) {
            logger.info("Network restored, attempting reconnection")

            pulseMqttKit.submitCommand(
                ConnectCommand(
                    connectionOptions = connectionOptions,
                    retryPolicy = RetryPolicy.exponential(
                        maxRetries = 3,
                        baseDelayMillis = 1000
                    )
                )
            )

            wasDisconnectedDueToNetwork = false
        }
    }
}

Pattern 2: Network Type Detection

class NetworkTypeHandler(private val context: Context) : MqttUpdatesListener {

    override fun onInternetConnectionStatusChanged(isConnected: Boolean) {
        if (isConnected) {
            val networkType = getNetworkType()
            adjustBehaviorForNetwork(networkType)
        }
    }

    private fun getNetworkType(): NetworkType {
        val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val activeNetwork = cm.activeNetwork ?: return NetworkType.NONE
        val capabilities = cm.getNetworkCapabilities(activeNetwork) ?: return NetworkType.NONE

        return when {
            capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> NetworkType.WIFI
            capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> NetworkType.CELLULAR
            else -> NetworkType.OTHER
        }
    }

    private fun adjustBehaviorForNetwork(networkType: NetworkType) {
        when (networkType) {
            NetworkType.WIFI -> {
                // Use normal settings
                setKeepAlive(30)
                enableLargePayloads(true)
            }
            NetworkType.CELLULAR -> {
                // Optimize for cellular
                setKeepAlive(60)
                enableLargePayloads(false)
            }
            else -> {
                // Conservative settings
                setKeepAlive(45)
            }
        }
    }
}

enum class NetworkType {
    WIFI, CELLULAR, OTHER, NONE
}

Pattern 3: User Notifications

class NetworkNotificationHandler(
    private val notificationManager: NotificationManager
) : MqttUpdatesListener {

    override fun onInternetConnectionStatusChanged(isConnected: Boolean) {
        if (isConnected) {
            dismissOfflineNotification()
            showReconnectingNotification()
        } else {
            showOfflineNotification()
        }
    }

    override fun onMqttConnectComplete(reconnect: Boolean, serverUri: String?) {
        if (reconnect) {
            dismissReconnectingNotification()
            showBriefSuccessMessage()
        }
    }

    private fun showOfflineNotification() {
        val notification = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_offline)
            .setContentTitle("No Internet Connection")
            .setContentText("Waiting for network to reconnect...")
            .setPriority(NotificationCompat.PRIORITY_LOW)
            .build()

        notificationManager.notify(OFFLINE_NOTIFICATION_ID, notification)
    }
}

Best Practices

1. Always Enable for Mobile Apps

// ✅ Good - Essential for mobile apps
NetworkMonitoringConfig(enabled = true)

2. Combine with Health Monitoring

class ComprehensiveMonitoring : MqttUpdatesListener {
    override fun onInternetConnectionStatusChanged(isConnected: Boolean) {
        if (isConnected) {
            // Network back - start health monitoring
            pulseMqttKit.startHealthMonitoring()
        } else {
            // Network lost - stop health monitoring (save battery)
            pulseMqttKit.stopHealthMonitoring()
        }
    }
}

3. Provide User Feedback

// ✅ Good - Keep users informed
override fun onInternetConnectionStatusChanged(isConnected: Boolean) {
    if (!isConnected) {
        showSnackbar("No internet connection. Messages will be queued.")
    }
}

4. Handle Rapid Network Changes

class DebounceNetworkChanges : MqttUpdatesListener {
    private var networkChangeJob: Job? = null

    override fun onInternetConnectionStatusChanged(isConnected: Boolean) {
        // Cancel pending reconnection
        networkChangeJob?.cancel()

        if (isConnected) {
            // Wait 2 seconds before reconnecting (debounce)
            networkChangeJob = coroutineScope.launch {
                delay(2000)
                attemptReconnection()
            }
        }
    }
}

Required Permissions

Add to AndroidManifest.xml:

<!-- Required for network monitoring -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Troubleshooting

Problem: Network events not received

Check: 1. Network monitoring is enabled 2. ACCESS_NETWORK_STATE permission granted 3. Listener is registered

// Verify configuration
val config = bridge.getNetworkConfig()
logger.debug("Network monitoring enabled: ${config.enabled}")

Problem: False positive network events

Solution: Add debouncing:

private var lastNetworkState = false
private val debounceDelay = 1000L

override fun onInternetConnectionStatusChanged(isConnected: Boolean) {
    if (isConnected != lastNetworkState) {
        delay(debounceDelay)
        if (isConnected == currentNetworkState()) {
            lastNetworkState = isConnected
            handleNetworkChange(isConnected)
        }
    }
}

Next Steps