Второй этап выхода из офлайн режима
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
package core.network
|
||||
|
||||
import android.content.Context
|
||||
import android.content.IntentFilter
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.NetworkRequest
|
||||
import android.util.Log
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* Менеджер состояния сети
|
||||
* Отслеживает подключение к интернету через NetworkCallback + BroadcastReceiver
|
||||
*/
|
||||
@Singleton
|
||||
class NetworkManager @Inject constructor(
|
||||
private val context: Context
|
||||
) {
|
||||
private val _isOnline = MutableStateFlow(isNetworkAvailable())
|
||||
val isOnline: StateFlow<Boolean> = _isOnline.asStateFlow()
|
||||
|
||||
private val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
|
||||
private var networkReceiver: NetworkReceiver? = null
|
||||
private var isMonitoring = false
|
||||
|
||||
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
|
||||
override fun onAvailable(network: Network) {
|
||||
Log.d("NetworkManager", "Network available - callback")
|
||||
_isOnline.value = true
|
||||
}
|
||||
|
||||
override fun onLost(network: Network) {
|
||||
Log.d("NetworkManager", "Network lost - callback")
|
||||
_isOnline.value = false
|
||||
}
|
||||
|
||||
override fun onCapabilitiesChanged(
|
||||
network: Network,
|
||||
networkCapabilities: NetworkCapabilities
|
||||
) {
|
||||
val hasInternet = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
val hasValidated = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
|
||||
Log.d("NetworkManager", "Capabilities changed: hasInternet=$hasInternet, hasValidated=$hasValidated")
|
||||
_isOnline.value = hasInternet && hasValidated
|
||||
}
|
||||
|
||||
override fun onUnavailable() {
|
||||
Log.d("NetworkManager", "Network unavailable - callback")
|
||||
_isOnline.value = false
|
||||
}
|
||||
}
|
||||
|
||||
fun startMonitoring() {
|
||||
if (isMonitoring) {
|
||||
Log.w("NetworkManager", "Already monitoring, skipping")
|
||||
return
|
||||
}
|
||||
|
||||
isMonitoring = true
|
||||
val cm = connectivityManager ?: run {
|
||||
Log.e("NetworkManager", "ConnectivityManager is null")
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// 1. Регистрируем NetworkCallback для активного отслеживания
|
||||
val networkRequest = NetworkRequest.Builder()
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
|
||||
.build()
|
||||
|
||||
cm.registerNetworkCallback(networkRequest, networkCallback)
|
||||
Log.d("NetworkManager", "Registered NetworkCallback")
|
||||
|
||||
// 2. Регистрируем BroadcastReceiver как запасной механизм
|
||||
// (на Android 10+ работает только для foreground приложений)
|
||||
val receiver = NetworkReceiver(this)
|
||||
networkReceiver = receiver
|
||||
val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
|
||||
try {
|
||||
@Suppress("DEPRECATION")
|
||||
context.registerReceiver(receiver, filter)
|
||||
Log.d("NetworkManager", "Registered NetworkReceiver")
|
||||
} catch (e: Exception) {
|
||||
Log.w("NetworkManager", "Failed to register BroadcastReceiver: ${e.message}")
|
||||
}
|
||||
|
||||
// 3. Инициализируем текущее состояние
|
||||
_isOnline.value = isNetworkAvailable()
|
||||
Log.d("NetworkManager", "Initial network state: ${_isOnline.value}")
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e("NetworkManager", "Error setting up network monitoring", e)
|
||||
_isOnline.value = isNetworkAvailable()
|
||||
}
|
||||
}
|
||||
|
||||
fun stopMonitoring() {
|
||||
if (!isMonitoring) return
|
||||
isMonitoring = false
|
||||
|
||||
try {
|
||||
connectivityManager?.unregisterNetworkCallback(networkCallback)
|
||||
Log.d("NetworkManager", "Unregistered NetworkCallback")
|
||||
} catch (e: Exception) {
|
||||
Log.e("NetworkManager", "Error unregistering NetworkCallback", e)
|
||||
}
|
||||
|
||||
try {
|
||||
networkReceiver?.let {
|
||||
context.unregisterReceiver(it)
|
||||
it.cleanup()
|
||||
networkReceiver = null
|
||||
Log.d("NetworkManager", "Unregistered NetworkReceiver")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("NetworkManager", "Error unregistering NetworkReceiver", e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isNetworkAvailable(): Boolean {
|
||||
return try {
|
||||
val network = connectivityManager?.activeNetwork
|
||||
val capabilities = connectivityManager?.getNetworkCapabilities(network)
|
||||
val available = capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) == true
|
||||
Log.d("NetworkManager", "isNetworkAvailable check: $available")
|
||||
available
|
||||
} catch (e: Exception) {
|
||||
Log.e("NetworkManager", "Error checking network", e)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun notifyNetworkRestored() {
|
||||
Log.d("NetworkManager", "Network restored notified - forcing state update")
|
||||
_isOnline.value = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Принудительно проверяет текущее состояние сети и уведомляет подписчиков
|
||||
*/
|
||||
fun refreshNetworkState() {
|
||||
val currentState = isNetworkAvailable()
|
||||
Log.d("NetworkManager", "Refreshed network state: $currentState")
|
||||
_isOnline.value = currentState
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package core.network
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.ConnectivityManager
|
||||
import android.util.Log
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* BroadcastReceiver для надежного отслеживания изменений сети
|
||||
* Используется как дополнение к NetworkCallback для лучшей надежности
|
||||
*/
|
||||
@Singleton
|
||||
class NetworkReceiver @Inject constructor(
|
||||
private val networkManager: NetworkManager
|
||||
) : BroadcastReceiver() {
|
||||
|
||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
|
||||
private var lastKnownState: Boolean = false
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (intent.action == ConnectivityManager.CONNECTIVITY_ACTION) {
|
||||
val isConnected = isNetworkAvailable(context)
|
||||
|
||||
Log.d("NetworkReceiver", "Broadcast received: isConnected=$isConnected, lastKnown=$lastKnownState")
|
||||
|
||||
// Отправляем уведомление только если состояние изменилось
|
||||
if (isConnected != lastKnownState) {
|
||||
lastKnownState = isConnected
|
||||
|
||||
scope.launch {
|
||||
if (isConnected) {
|
||||
Log.d("NetworkReceiver", "Network connected - notifying NetworkManager")
|
||||
// Небольшая задержка для стабилизации сети
|
||||
kotlinx.coroutines.delay(500)
|
||||
networkManager.notifyNetworkRestored()
|
||||
} else {
|
||||
Log.d("NetworkReceiver", "Network disconnected")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isNetworkAvailable(context: Context): Boolean {
|
||||
return try {
|
||||
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
|
||||
val network = cm?.activeNetwork
|
||||
val capabilities = cm?.getNetworkCapabilities(network)
|
||||
capabilities?.hasCapability(android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET) == true
|
||||
} catch (e: Exception) {
|
||||
Log.e("NetworkReceiver", "Error checking network", e)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun cleanup() {
|
||||
scope.cancel()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user