3

In the below code I am trying to run a thread when a button is clicked. In the button listener I create a new thread and run it...but at run time, when the button is pressed, the button itself freezes and the app does not respond and I receive ANR dialog. Moreover, when the socket is connected successfully even the TexView

mtvStatus.setText("RFC-SOCKET CONNECTED");

displays nothing.

Please let me know why this is happening.

button listener:

this.mbtnConnect.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            BluetoothSocket rfcSocket = mSPPCtrl.rfcConnect();
            if (rfcSocket.isConnected()) {
                mtvStatus.setText("RFC-SOCKET CONNECTED");

                Thread rx = new Thread(new RxRun(rfcSocket));
                rx.run();

            } else {
                mtvStatus.setText("RFC-SOCKET NOT CONNECTED");
            }

        }
    });

runnable class

private class RxRun implements Runnable {

    private BluetoothSocket mRFCSocket = null;
    private OutputStream mRFCOS = null;
    private InputStream mRFCIS = null;

    public RxRun(BluetoothSocket rfcSocket) {
        this.mRFCSocket = rfcSocket;

        try {
            this.mRFCOS = rfcSocket.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            this.mRFCIS = rfcSocket.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        try {
            this.mRFCOS.write(DIRON.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }

        while (this.mRFCSocket.isConnected()) {
            try {
                int readBytes = this.mRFCIS.read(new byte[5120]);
                Log.d(TAG, CSubTag.bullet("RxRun", "readBytes:" + readBytes));
                //mtvRx.setText(""+readBytes);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}
Onik
  • 19,396
  • 14
  • 68
  • 91
Amrmsmb
  • 1
  • 27
  • 104
  • 226
  • 6
    I believe you shoudnt call rx.run(), instead call rx.start(); – Mateus Brandao Nov 12 '15 at 17:21
  • 6
    You should use `rx.start();` instead of `rx.run();` – Titus Nov 12 '15 at 17:21
  • 5
    Don't think you should be doing a .rfConnect() on your UI thread either... – JJF Nov 12 '15 at 17:23
  • 1
    Or why you shouldn't use `Thread` directly. Use an `ExecutorService` instead. The `.run()` method is inherited from `Runnable` and will not automagically run "in the background" for you. Also, how do you intend to collect the results? – fge Nov 12 '15 at 17:34
  • @fge i am just making a test..and to answer your question "how do u intend to collect the result"? ..i want to display the result in the log.d inside the while loop..but it displays nothing and any log statement AFTER this line: int readBytes = this.mRFCIS.read(new byte[5120]); is never called...any suggestion why it is not getting called – Amrmsmb Nov 12 '15 at 17:37

2 Answers2

1

...when the button is pressed, the button itself freezes and the app does not respond and I receive ANR dialog. Moreover, when the socket is connected successfully even the TexView displays nothing.

It's expected, because you haven't actually started the rx thread. Here is what is going on:

  1. mSPPCtrl gets connected,
  2. mtvStatus's text is set to "RFC-SOCKET CONNECTED", but you cannot visually see it because
  3. run() method of the RxRun instance is called manually where the loop while (this.mRFCSocket.isConnected()) may last as long as the socket is connected.

All the above said is invoked on UI-thread and that's the reason of ANR.

You should not call run() manually. Start the rx thread with

rx.start();

Also I highly recommend to move all the rfcSocket logic inside of the thread and notify the UI-thread on success/failure of connection.

EDIT

Here is one the option mentioned in my comment.

Start the rx thread on a button click

this.mbtnConnect.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        new Thread(new RxRun(rfcSocket)).start();
    }
});

Move your logic inside of the run() method:

public void run() {
        BluetoothSocket rfcSocket = mSPPCtrl.rfcConnect();
        if (rfcSocket.isConnected()) {
            mtvStatus.post(new Runnable() {
                @Override
                public void run() {
                    mtvStatus.setText("RFC-SOCKET CONNECTED");
                }
            });
        } else {
            mtvStatus.post(new Runnable() {
                @Override
                public void run() {
                    mtvStatus.setText("RFC-SOCKET NOT CONNECTED");
                }
            });
            return;
        }
    // the rest of your logic
    }

Some links that might help:

  1. Android documentation on Threads
  2. SO question Android basics: running code in the UI thread
  3. another SO post on Update UI from Thread
Community
  • 1
  • 1
Onik
  • 19,396
  • 14
  • 68
  • 91
  • thanks for ur answer..would u please tell me more about notify() method why it should be used..is it like "return" – Amrmsmb Nov 12 '15 at 22:09
  • 1
    @LetsamrIt No, I didn't mean the `Object`'s `notify()` method, I used it as a verb. There are several options to "inform" a UI-thread from a background thread. Like by means of `Handler`, `runOnUiThread()` method if you passed a context to the background thread, `Observer` pattern implementation or a direct call of an `YourActivity` method (within which views must be touched on UI-thread only). Just use one of the techniques. If you really need help at this I'll edit the answer tomorrow (I'm almost asleep... :)) – Onik Nov 12 '15 at 22:18
1

The error here is really simple - do not use run() on the Thread instance, as this will actually run it's Runnable on the current Thread! Use start() and it will work fine :-)

Kelevandos
  • 7,024
  • 2
  • 29
  • 46