A Microsoft framework for building cross-platform mobile apps using .NET and C# with native performance and user interfaces.
Avoid multiple OnNetworkAvailable on registered Network Callbacks on connection
I was having problems with Xamarin Android NetworkCallback being fired twice when called again quickly after disconnecting WIFI. I was unregistering the previous callback immediately and confirmed that there was only one instance but it was firing twice
I found an answer that did not work in the old Xamarin forums but I could not get on to post my answer. So I will put it here
public void Disconnect() {
this.msgPump.Disconnect();
if (this.connectCallback != null) {
// Some note that sometimes you need to force un-bind
this.connectivityManager.BindProcessToNetwork(null);
this.connectivityManager.UnregisterNetworkCallback(this.connectCallback);
this.connectCallback.Dispose();
this.connectCallback = null;
}
if (this.network != null) {
this.network.Dispose();
this.network = null;
// Bug in the connect callback returns immediately if socket
// is still detected. Then a second time. Looks like time is
// required to shut down but no synchronisation is provided
Thread.Sleep(100);
}
}
Having the 100ms wait solves the problem. The NetworkCallback only fires the OnNetworkAvailable once
In the message pump (which handles the socket I put in another catch, just in case). This will work to catch ECONNABORTED exception to ignore it. This is what was happening on the first firing of OnNetworkAvailable if the sockets were not entirely gone.
The is in the message pump connect method. (it connects and sets up read thread etc)
try {
if (this.socket != null && this.socket.IsConnected) {
this.DisconnectAsync();
}
this.InitForConnection();
this.log.Info("ConnectAsync2", "Before connect");
this.socket = paramsObj.DiscoveredNetwork.SocketFactory.CreateSocket();
await this.socket.ConnectAsync(new InetSocketAddress(paramsObj.HostName, paramsObj.Port), 30000);
this.log.Info("ConnectAsync2", "After msg pump connect");
this.LaunchReadThread();
this.log.Info("ConnectAsync2", "After read thread launch");
this.MsgPumpConnectResultEvent?.Invoke(this, new MsgPumpResults(MsgPumpResultCode.Connected));
}
catch (ConnectException ce) {
this.log.Exception(9999, "ConnectAsync2", "Connect Exception", ce);
// Bug with multiple firing of OnAvailable with ConnectionCallback where
// sockets not finished closing. Ignore 'E'rror 'CONN'ection 'A'borted
if (!ce.Message.Contains("ECONNABORTED")) {
throw;
}
}
catch (Exception e) {
this.log.Exception(9999, "ConnectAsync2", "", e);
this.MsgPumpConnectResultEvent?.Invoke(this,
new MsgPumpResults(MsgPumpResultCode.ConnectionFailure, e.Message));
}