简体   繁体   中英

How to prevent main thread from blocking when I am listening on bluetooth devices in a Xamarin Android app?

I have an app that I need to function as a bluetooth server, it will listen on incoming bluetoooth connections and print the message sent from those devices. I have managed to make some progress though I fear that I have might made a mistake calling a blocking method in the main thread of my app, that is the User Interface thread. When I call clientSocket= serverSocket.Accept(); everything in my app stops, i use a switcher to call the method that has the above line, the switcher shows like its turning on but hangs due to a method that imolements a blocking call till a bluetooth device connects to the socket. How can I avoid that effect on the main thread of my app because I believe once a bluetooth device connects to the app then the blocking call will be removed and the switcher will resume to being checked. I have thought about using a new thread to accept the socket but how will I display the data received from the device to a UI TextView element I have in my app since manipulation of TextViews and other UI is not allowed from a non-UI thread, Thank you

server_switch.Click += (o, e) =>
            {
                //check the check status of the switch and start and disable gatt accordingly
                Switch myswitch = o as Switch;
                if (myswitch.Checked)
                {
                    Log.Debug("Check Status Enabled", myswitch.Checked.ToString());
                    myswitch.Checked = true;
                    //switch the adapter mode and request for visibility
                    switch (_adapter.ScanMode)
                    {
                        case ScanMode.Connectable:
                            MakeVisibleFor300Seconds();
                            break;
                        case ScanMode.None:
                            MakeVisibleFor300Seconds();
                            break;
                        case ScanMode.ConnectableDiscoverable:
                                //do nothing, adapter in required mode
                                Log.Debug("Adapter Mode",
                                    "Connectable Discoverable:" +
                                    (_adapter.ScanMode == ScanMode.ConnectableDiscoverable).ToString());
                                break;
                    }
                      //create a new thread and run
                    
                    var newThread= new SocketListener(display_data, serverSocket);
                    newThread.Start();

                    }

                }
                else
                {
                    //the switch is disabled
                    Log.Debug("Check Status Enabled", myswitch.Checked.ToString());
                }
            };

Class for accepting new connections

  //create a new class for listening on connections and displaying message to the textview
    public class SocketListener : Thread
    {
        private TextView _data;
        private BluetoothServerSocket mysocket;

        private Stream output, input;
        //declare default ctor for reflections
        public SocketListener()
        {
            
        }
        //declare the custom ctor
        public SocketListener(TextView display, BluetoothServerSocket socket)
        {
            mysocket = socket;
            _data = display;
        }
        //override run and implement a blocking call
        public override void Run()
        {
            //NB: This implements a blocking call till a device connects
            BluetoothSocket source_device = mysocket.Accept();
            //get the input and output streams
            output = source_device.OutputStream;
            input = source_device.InputStream;
            //check if data is available and write it to our object
            StreamReader reader = new StreamReader(input);
            string dat="";
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                dat += line;
            }

            _data.Text = dat;
        }
    }

All the stuff about android, java, C#, xamarin, bluetooth, etc. is irrelevant. This question is essentially asking how to build a socket server application for a small number of clients, where "small" here means that you have the luxury of spawning one thread per client. (If you were to serve a large number of clients, then you would have to resort to a threadpool, but in your case that would be an unnecessary complication.)

The way we build a socket server application for a small number of clients is as follows:

  1. One thread (the "Accept" thread) does nothing but an endless loop where it invokes serverSocket.Accept() .
  2. When a socket connection is established, the "Accept" thread creates a "Session" thread for the connected socket. So, we have one "Session" thread per client.
  3. Each "Session" thread receives packets from a client and sends packets back to the client. When a "Session" thread has something to useful to show to the user, the "Session" thread "posts" a message to the GUI thread, which means that it sends it in a thread-safe way. Different GUI systems support different means of accomplishing this; I am not sure about Xamarin, perhaps with MessagingCenter.Send() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM