Networkcallback вызывается несколько раз даже после отмены регистрации
В моем Android-приложении мне нужно вызывать API через соединение Wi-Fi, которое не имеет интернет-соединения, даже если сотовые данные включены. Мне удается справиться с этим с помощью нижнего кода:
NetworkRequest.Builder builder;
builder = new NetworkRequest.Builder();
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
final ConnectivityManager connectivityManager = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
connectivityManager.requestNetwork(builder.build(), new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
connectivityManager.unregisterNetworkCallback(this);
SendAPIRequest();
}
});
Все идет нормально. Однако на некоторых устройствах Android метод onAvailable (и, следовательно, метод SendAPIRequest) иногда вызывается несколько раз, а не всегда. Как указано на developer.android.com, сетевой вызов может вызываться более одного раза, если сеть, удовлетворяющая запросу, изменяется. ( https://developer.android.com/reference/android/net/ConnectivityManager.NetworkCallback.html) Но, как вы можете видеть в моем коде, я немедленно отменяю регистрацию обратного вызова сети, чтобы предотвратить этот обратный вызов от вызова в другой раз, даже если сеть изменится. Что я делаю неправильно?
1 ответ
Я знаю, что это старый вопрос, но для тех, кому это будет интересно, я недавно заметил, что обратные вызовы вызываются из рабочего потока. Таким образом, может возникнуть состояние гонки, если вы не запускаете свой код в основном потоке. Также onAvailable все еще можно вызвать после отмены регистрации обратного вызова. Таким образом, вам нужно будет реализовать так, чтобы то, что вы делаете внутри onAvailable, было безопасно вызывать даже после того, как его живой контекст исчез.
например, Proves onAvailable работает в рабочем потоке
override fun onAvailable(network: Network) {
Logging.i(Logging.APP_STATE, "Network available")
if (Thread.currentThread() != Looper.getMainLooper().thread) {
throw RuntimeException("What? This doesn't run on the main thread!")
}
isConnected = true
}