Share via

Avoid multiple OnNetworkAvailable on registered Network Callbacks on connection

Michael Roop 1 Reputation point
2020-12-04T19:49:11.117+00:00

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));
             }
Developer technologies | .NET | Xamarin

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.