0

I'm new to programming on android and I'm writing a simple application of a turn-based game that uses bluetooth. My app consists of Main Activity is responsible for starting a bluetooth connection and exchanging some configuration messages and a SecondActivity that implements a custom view with the game map. I can correctly pair the devices and exchange information between the two even in the custom view, the problem is that in the custom view I would wait to receive information without blocking the ui thread, at the moment I am waiting to receive data in this way

Custom view

state = bluetoothService.getState();
while(state != NOT_EMPTY){
    try {
        Thread.sleep(500);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    state = bluetoothService.getState();
}
info = bluetoothService.getMessage();

this obviously causes black screens and non-responsiveness, is there another way to wait to receive data?

The connection is managed through a BluetoothService class, with threads, the one that takes care of reading the data does this

private class ConnectedThread extends Thread {
        private final BluetoothSocket mSocket;
        private final InputStream mInStream;
        private final OutputStream mOutStream;

        public ConnectedThread(BluetoothSocket socket) {
            mSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;

            try {
                tmpIn = mSocket.getInputStream();
                tmpOut = mSocket.getOutputStream();
            } catch (IOException e) {
                e.printStackTrace();
            }

            mInStream = tmpIn;
            mOutStream = tmpOut;
        }

        public void run(){
            byte[] buffer = new byte[1024]; 

            int bytes; // bytes returned from read()

            // Keep listening to the InputStream until an exception occurs
            while (true) {
                // Read from the InputStream
                try {
                    bytes = mInStream.read(buffer);
                    if(bytes != 0) {
                        String incomingMessage = new String(buffer, 0, bytes);
                        message = incomingMessage;
                        mState = NOT_EMPTY;
                    }
                } catch (IOException e) {
                    break;
                }
            }
        }
}

//getMessage method just returns message if not null
Taslim Oseni
  • 6,086
  • 10
  • 44
  • 69
JayJona
  • 469
  • 1
  • 16
  • 41
  • 1
    put it to Thread or async task – A Farmanbar Jul 05 '19 at 13:43
  • 1
    you can use AsyncTask to do the job for you, it do all the work in background and then send the result to your main Thread, you can find an example here https://stackoverflow.com/questions/14250989/how-to-use-asynctask-correctly-in-android – Ezaldeen sahb Jul 05 '19 at 14:08

1 Answers1

2

The main idea is not to pull from the activity, but instead call a method of the activity from the background thread.

So when constructring your reader thread, pass a reference to the activity and create a handler:

    private SecondActivity mActivity;
    private Handler mActivityHandler;

    public ConnectedThread(BluetoothSocket socket, SecondActivity activity) {
        mActivity = activity;
        mActivityHandler = new Handler(activity.getMainLooper());

        ...
    }

When a message is received, call a method of the activity. The call must be done on the main thread, so use the handler:

final String message = incomingMessage;
Runnable runnable = new Runnable() {
    @Override 
    public void run() {
        mActivity.onMessageReceived(message);
    } 
};
mActivityHandler.post(myRunnable);

In the activity, do something with message:

public void onMessageReceived(String message) {
    // handle the message...
}
Codo
  • 75,595
  • 17
  • 168
  • 206
  • I was using an async task as suggested in the comments, what's the difference between using an async task and your solution? What is the best in performance and correctness? – JayJona Jul 07 '19 at 19:08
  • *AsyncTask* executed a given task in the background and then finishes. It seems more suitable if you have chunks of work. In our situation where the background thread is mainly waits for data and from time to time receives data, the background thread seems more appropriate. I don't know how you use the AsyncTask: Do you run a separate one for each message and use *onPostExecute* to deliver the message? Or do you run it indefinitely and use a handler (as above) to deliver the message? Bot approaches seem unnatural. – Codo Jul 08 '19 at 06:01
  • yes I was using sepate async task for each message and it didn't seem the best solution – JayJona Jul 08 '19 at 11:00
  • if this is such a common pattern, why doesn't Android build it in for us? Like WinSock from MS Windows? – Phlip Nov 09 '19 at 19:50