Adaptive Keepalive Strategy
Traditional keepalive mechanisms fail on Android. This guide explains LiteP2P's adaptive approach to maintaining connections.
Why Persistent Keepalive Fails
Many developers try to maintain persistent connections using frequent keepalive packets. This approach fails on Android for several reasons:
Doze suspends sockets
All network activity is paused in Doze mode, keepalive packets are never sent
NAT mappings expire
Without traffic, routers close port mappings (typically 30-120 seconds)
Radio sleeps regardless of TCP state
The cellular/WiFi radio enters low-power mode independently
OEM firmware kills idle connections
Aggressive OEMs terminate connections proactively
Recommended Keepalive Policy
LiteP2P uses an adaptive keepalive strategy that varies based on app state:
| App State | Keepalive | Rationale |
|---|---|---|
| Idle | None | Use push notifications to wake |
| Background | None | Connections will be dropped anyway |
| Foreground Service | Adaptive | Maintain connections during active work |
| Charging + Wi-Fi | Optional | Low cost, may improve responsiveness |
Keepalive Requirements
When keepalive is appropriate, it must be:
- FSM-driven – Controlled by connection state machine
- Battery-aware – Adjusts frequency based on power state
- State-aware – Only active when needed
Implementation
LiteP2P handles keepalive automatically, but you can configure the behavior:
val config = PeerConfig.Builder()
.setAppId("your-app-id")
.setKeepalivePolicy(KeepalivePolicy.ADAPTIVE)
.setKeepaliveInterval(30, TimeUnit.SECONDS) // When active
.setChargingKeepalive(true) // Enable when charging
.build()
LiteP2P.initialize(context, config)
Keepalive Policies
enum class KeepalivePolicy {
NONE, // Never send keepalive
ADAPTIVE, // Smart, state-based (recommended)
FOREGROUND, // Only during foreground service
AGGRESSIVE // Always when possible (not recommended)
}
Adaptive Behavior
When using KeepalivePolicy.ADAPTIVE, LiteP2P:
- Monitors app state – Foreground, background, service active
- Checks power state – Battery level, charging status
- Detects network type – Wi-Fi vs cellular
- Adjusts interval dynamically – More frequent when active, less when idle
// Example of internal adaptive logic
internal fun calculateKeepaliveInterval(): Long {
return when {
isCharging && isWifi -> 30_000 // 30 seconds
isCharging -> 60_000 // 1 minute
isWifi -> 120_000 // 2 minutes
else -> 0 // No keepalive, use push
}
}
Monitoring Connection Health
// Listen for connection state changes
LiteP2P.getInstance().onConnectionStateChange { state ->
when (state) {
ConnectionState.CONNECTED -> {
Log.d("LiteP2P", "Connection healthy")
}
ConnectionState.RECONNECTING -> {
Log.d("LiteP2P", "Connection lost, attempting reconnect")
}
ConnectionState.DISCONNECTED -> {
Log.d("LiteP2P", "Disconnected, waiting for wake signal")
}
}
}
Trust LiteP2P's adaptive keepalive. Don't implement your own keepalive mechanism – it will conflict with the SDK's power-efficient design.