Implement a timeout in BluetoothSocket inputstream.read() in Android

16,570

Solution 1

You could do something like this:

InputStream in = someBluetoothSocket.getInputStream();
int timeout = 0;
int maxTimeout = 8; // leads to a timeout of 2 seconds
int available = 0;

while((available = in.available()) == 0 && timeout < maxTimeout) {
    timeout++;
    // throws interrupted exception
    Thread.sleep(250);
}

byte[] read = new byte[available];
in.read(read);

This way you are able to initially read from a stream with a specific timeout. If u want to implement a timeout at any time of reading you can try something like this:

Thread readThread = new ReadThread(); // being a thread you use to read from an InputStream
try {
   synchronized (readThread) {
      // edit: start readThread here
      readThread.start();
      readThread.wait(timeOutInMilliSeconds);
   }
catch (InterruptedException e) {}

using this you may need some kind of event handler to notify your application if the thread actually read something from the input stream.

I hope that helps!

----edit:

I implemented an example without using any handlers.

Socket s = new Socket("localhost", 8080);
    final InputStream in = s.getInputStream();

    Thread readThread = new Thread(new Runnable() {
        public void run() {
            int read = 0;
            try {
                while((read = in.read()) >= 0) {
                    System.out.println(new String(new byte[]{ (byte) read }));
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    });

    synchronized (readThread) {
        readThread.start();
        try {
            readThread.wait(2000);

            if(readThread.isAlive()) {
                                    // probably really not good practice!
                in.close();
                System.out.println("Timeout exceeded!");
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

Solution 2

A Kotlin extension function for socket read with timeout:

fun InputStream.read(
  buffer: ByteArray,
  offset: Int,
  length: Int,
  timeout: Long
): Int = runBlocking {
    val readAsync = async {
        if (available() > 0) read(buffer, offset, length) else 0
    }
    var byteCount = 0
    var retries = 3
    while (byteCount == 0 && retries > 0) {
        withTimeout(timeout) {
            byteCount = readAsync.await()
        }
        delay(timeout)
        retries--
    }
    byteCount
}
Share:
16,570
Poperto Arcadio Buendía
Author by

Poperto Arcadio Buendía

Updated on July 19, 2022

Comments

  • Poperto Arcadio Buendía
    Poperto Arcadio Buendía almost 2 years

    Is it possible to implement a timeout in an inputstream.read() function from a BluetoothSocket in Android?

    I've tried using Thread.sleep() but this only pauses my activity.

    ---Update---

    I had an idea, make 2 thread code herereads(t1 & t2) where each thread interrupt other, one of them(t1) do a sleep(5000) then interrupt the other thread(t2), from the other side the other thread(t2) if in read the inputstream detects some character as 0x0D interrupt the other thread(t1), but here is my question, does anybody can help me? because i didn't use interrupt() method of threads, I hope someone can help me, thank you...

    ---Update---

    
    
            public void run(){
            while(true){
                try {
                char r;
                String respuesta = "";
                while (true) {
                        r = (char) mmInStream.read();
                    respuesta += r;
                    if (r == 0x3e) {
                    break;
                        }
                    }
                respuesta = respuesta.replaceAll(" ", "");
                Log.d("respuesta", respuesta);
                rHandler.obtainMessage(MESSAGE_READ, -1, -1, respuesta).sendToTarget();
                } catch (IOException readException) {
                Log.e("ServicioGeneral", "Error de lectura", readException);
                this.interrupt();
                connectionLost();
                // posibly break();
                }
            }
        }
    
    

    This is my implementation when something comes in a different Thread, the problem is that the timeout will be reached if i dont get the 0x3e character from de mmInStream.

    I supposed that in the second example i must use a notifyAll(), but, when do I have to start the readThread()?

    Thank you, @weeman

  • Poperto Arcadio Buendía
    Poperto Arcadio Buendía about 12 years
    Very nice timeouts implementation but I dont get it to make it work in my code i've updated my answer if you can give me a hand... Thanks... by the way you put, <pre><code> byte[available] read=new byte[available] </code></pre> and is <pre><code> byte[] read=new byte[available]; </code></pre>
  • jobnz
    jobnz about 12 years
    oh, yes. You are right. I'm going to change that and try to give an answer to your updated question.
  • Poperto Arcadio Buendía
    Poperto Arcadio Buendía about 12 years
    Thanks @weeman after read the code I understand how this timeout works and i could implement one if i didn't receive response from my microcontroller, thanks...