Android ConnectivityManager onAvailable иногда не возвращается

#android #android-connectivitymanager

#Android #android-connectivitymanager

Вопрос:

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

 class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        ConnectionStateMonitor().enable(this)
    }

    class ConnectionStateMonitor : NetworkCallback() {
        private val networkRequest: NetworkRequest = NetworkRequest.Builder()
            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build()

        fun enable(context: Context) {
            val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            connectivityManager.registerNetworkCallback(networkRequest, this)
        }

        override fun onAvailable(network: Network) {
            Log.i(TAG, "onAvailable ")
        }

        override fun onLost(network: Network?) {
            super.onLost(network)
            Log.i(TAG, "onLost ")
        }
    }
}
  

Эта реализация работает хорошо, за исключением двух проблем, с которыми мы столкнулись

  1. Если мы подключаемся к Интернету, используя как Wi-Fi, так и мобильные данные, и отключаем Wi-Fi, иногда запускается onLost() обратный вызов, за которым следует onAvailable() , как и ожидалось, но в других случаях запускается только onLost() , что неверно.

  2. Если у нас нет подключения к Интернету и мы открываем приложение, onLost() оно не запускается, однако, если у нас есть подключение к Интернету и мы открываем приложение, onAvailable() оно запускается.

Любая помощь, предложения, обходные пути или другие подходы для надежного обнаружения изменений подключения к Интернету действительно были бы оценены.

Протестировано на Xioami A2 (Android 9), OnePlus (Android 9)

ДЕМОНСТРАЦИОННЫЙ проект
https://github.com/PhanVanLinh/AndroidNetworkChangeReceiver

Комментарии:

1. Вы нашли подход к решению вашей второй проблемы?

2. Нет, я не могу найти ответ, поэтому я удаляю эту функцию из своего приложения. я все еще ищу решение

Ответ №1:

Я использовал ваш проект и добавил другой метод: onCapabilitiesChanged . Я начал с того, что режим полета был включен по электронной почте, а затем выключен, а затем снова включен. Это журналы:

Доступно 632

onCapabilitiesChanged 632 [Транспорт: СОТОВАЯ СВЯЗЬ …]

Доступно 632

onCapabilitiesChanged 632 [Транспорт: СОТОВАЯ СВЯЗЬ …]

Доступно 632

onCapabilitiesChanged 632 [Транспорт: СОТОВАЯ СВЯЗЬ …]

onCapabilitiesChanged 632 [Транспорт: СОТОВАЯ СВЯЗЬ …]

onCapabilitiesChanged 632 [Транспорт: СОТОВАЯ СВЯЗЬ …]

Доступно 633

onCapabilitiesChanged 633 [Транспорт: WIFI …] onAvailable 633 onCapabilitiesChanged 633 [Транспорт: WIFI …]

Доступно 633

onCapabilitiesChanged 633 [Транспорт: WIFI …]

onCapabilitiesChanged 633 [Транспорт: WIFI …]

onCapabilitiesChanged 633 [Транспорт: WIFI …]

onCapabilitiesChanged 633 [Транспорт: WIFI …]

onCapabilitiesChanged 633 [Транспорт: WIFI …]

onCapabilitiesChanged 633 [Транспорт: WIFI …]

onLost 632

onLost 632

onLost 632

onLost 633

onLost 633

onLost 633

Доступно 634

onCapabilitiesChanged 634 [Транспорт: СОТОВАЯ СВЯЗЬ …]

Доступно 634

onCapabilitiesChanged 634 [Транспорт: СОТОВАЯ СВЯЗЬ …]

Доступно 634

onCapabilitiesChanged 634 [Транспорт: СОТОВАЯ СВЯЗЬ …]

onCapabilitiesChanged 634 [Транспорт: СОТОВАЯ СВЯЗЬ …]

onCapabilitiesChanged 634 [Транспорт: СОТОВАЯ СВЯЗЬ …]

onCapabilitiesChanged 634 [Транспорт: СОТОВАЯ СВЯЗЬ …]

Доступно 635

onCapabilitiesChanged 635 [Транспорт: WIFI …]

Доступно 635

onCapabilitiesChanged 635 [Транспорт: WIFI …]

Доступно 635

onCapabilitiesChanged 635 [Транспорт: WIFI …]

onCapabilitiesChanged 635 [Транспорт: WIFI …]

onCapabilitiesChanged 635 [Транспорт: WIFI …]

onCapabilitiesChanged 635 [Транспорт: WIFI …]

onLost 634

onLost 634

onLost 634

onCapabilitiesChanged 635 [Транспорт: WIFI …]

onCapabilitiesChanged 635 [Транспорт: WIFI …]

Как вы можете видеть, LOST предназначен для сотовой передачи, в то время как AVAILABLE предназначен для WiFi

Следуя вашему варианту использования (включить Wi-Fi, включить mobiledata, отключить данные Wi-Fi, включить Wi-Fi, отключить Wi-Fi), это то, что я получаю.

Доступно 640

onCapabilitiesChanged 640 [Транспорт: WIFI … ]

Доступно 640

onCapabilitiesChanged 640 [Транспорт: WIFI … ]

onCapabilitiesChanged 640 [Транспорт: WIFI … ]

onCapabilitiesChanged 640 [Транспорт: WIFI … ]

onCapabilitiesChanged 640 [Транспорт: WIFI … ]

onCapabilitiesChanged 640 [Транспорт: WIFI … ]

Загрузка 640

Загрузка 640

Доступно 641

onCapabilitiesChanged 641 [Транспорт: СОТОВАЯ СВЯЗЬ … ]

Доступно 641

onCapabilitiesChanged 641 [Транспорт: СОТОВАЯ СВЯЗЬ … ]

onCapabilitiesChanged 641 [Транспорт: СОТОВАЯ СВЯЗЬ … ]

onCapabilitiesChanged 641 [Транспорт: СОТОВАЯ СВЯЗЬ … ]

Доступно 642

onCapabilitiesChanged 642 [Транспорт: WIFI … ]

Доступно 642

onCapabilitiesChanged 642 [Транспорт: WIFI … ]

onCapabilitiesChanged 642 [Транспорт: WIFI … ]

onCapabilitiesChanged 642 [Транспорт: WIFI … ]

onCapabilitiesChanged 642 [Транспорт: WIFI … ]

onCapabilitiesChanged 642 [Транспорт: WIFI … ]

onLost 641

onLost 641

onLost 642

onLost 642

Доступно 643

onCapabilitiesChanged 643 [Транспорт: СОТОВАЯ СВЯЗЬ … ]

Доступно 643

onCapabilitiesChanged 643 [Транспорт: СОТОВАЯ СВЯЗЬ … ]

onCapabilitiesChanged 643 [Транспорт: СОТОВАЯ СВЯЗЬ … ]

onCapabilitiesChanged 643 [Транспорт: СОТОВАЯ СВЯЗЬ … ]

Комментарии:

1. Спасибо за ваше тестирование. Я прочитал ваш журнал 3 раза, но все еще не могу понять. В настоящее время, если у вас есть устройство Android 9, вы можете еще раз протестировать несколько раз, как это `включить Wi-Fi, включить mobiledata, отключить данные Wi-Fi, включить Wi-Fi, отключить Wi-Fi // обычно onAvaiable здесь не вызывается). Вы можете попробовать это несколько раз, и вы увидите проблему. На моем устройстве Android 8 все работает хорошо, но я не уверен, что все Android 8 работают хорошо или нет

2. Он вызывал onAvailable для сотовой сети для меня: каждый раз, когда я отключал Wi-Fi (даже в последний раз). Я использую Samsung Note 8 с Android 9.

3. При повторной попытке я не получил onLost для сотовой связи, когда я включил Wi-Fi, а затем я не получил onAvailable, когда я его выключил.

4. onCapabilitiesChanged должно сработать. У меня также была похожая проблема, и добавление проверки на наличие действительного Интернета networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) amp;amp; networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) помогло

Ответ №2:

Определение широковещательного приемника на AndroidManifest немного изменилось. Вы можете найти соответствующее описание здесь.

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

Комментарии:

1. Я прочитал ваш источник на github и обнаружил, что ваша основная идея — проверять состояние Интернета каждые 5 секунд. Если это правильно, я чувствую, что это не очень хорошо для производительности. Есть ли какой-либо способ оптимизации? Поправьте меня, если я ошибаюсь.

2. Привет, я могу понять ваши опасения, хорошо, тогда я обновлю контекст ответа, может быть, вы сможете найти другое решение на developer.android.com .

3. Да, на самом деле изменение подключения к Интернету для прослушивания является лишь небольшим улучшением для моего приложения. Если он потребляет слишком много батареи, я думаю, мне не нужно помещать его внутрь, потому что от него не слишком много пользы. Теперь я уже удаляю эту функцию из своего приложения: D, просто когда вызываю API и интернета нет, я показываю ошибку: v

Ответ №3:

Может быть, вы можете попробовать использовать requestNetwork вместо registerNetworkCallback .

Комментарии:

1. Это не изменило бы ничего, связанного с onAvailable. Единственная разница в поведении между ними заключается в том, что requestNetwork они будут поддерживать сеть для вашего приложения, а registerNetworkCallback нет. Т. е., если ни у каких приложений нет открытых requestNetwork запросов для определенной сети, ConnectivityService это приведет к ее отключению. Однако для этого не требуется никаких registerNetworkCallback запросов типа.

Ответ №4:

Обратный вызов должен выглядеть следующим образом:

 val callback = object : ConnectivityManager.NetworkCallback() {

    private val availableNetworks: MutableSet<Network> = HashSet()

    override fun onAvailable(network: Network) {
        val networkCapabilities = connectivityManager.getNetworkCapabilities(network)
        val hasInternetCapability =
            networkCapabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)

        if (hasInternetCapability == true) {
            availableNetworks.add(network)
            sendNetworkState()
        }
    }

    override fun onLost(network: Network) {
        availableNetworks.remove(network)
        sendNetworkState()
    }

    private fun sendNetworkState() {
        if (availableNetworks.isNotEmpty()) {
            // TODO: Notify the Internet connection is available
        } else {
            // TODO: Notify the Internet connection is unavailable
        }
    }
}
  

Регистрация обратного вызова:

 val request = NetworkRequest.Builder()
    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
    .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
    .build()

connectivityManager.registerNetworkCallback(networkRequest, callback)

  

Объяснение

onLost вызывается для каждой сети, которая была ранее передана onAvailable , согласно документации:

Если обратный вызов был зарегистрирован с помощью registerNetworkCallback(), он будет вызываться для каждой сети, которая больше не удовлетворяет критериям обратного вызова.

Также возможно, что onAvailable будет вызван дважды перед onLost

Первоначально код был найден здесь:https://www.youtube.com/watch?v=To9aHYD5OVk