0

I am trying to implement a REST interface in android and I need a Thread in the background sending "I am alive" messages to an ip address. To do so I created a Thread Called RestPostThread that runs in the background while I do stuff in my UI thread.

The problem is that after sending the first message to the RestPostThread I can't quit the looper or send a different message to it with another IP or something.

Here are the code for both the UI and the RestPostThread:

public class MainActivity extends AppCompatActivity{

Handler workerThreadHandler;


protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    final TextView text1 = (TextView) findViewById(R.id.text1);
    final TextView text2 = (TextView) findViewById(R.id.text2);
    setSupportActionBar(toolbar);


    final RestPostThread RPT = new RestPostThread();
    RPT.start();

    while(workerThreadHandler == null ) {
        workerThreadHandler = RPT.getThreadHandler();
    }

    Button buttonStop = (Button) findViewById(R.id.buttonStop);
    buttonStop.setOnClickListener(new View.OnClickListener(){
        public void onClick(View view) {
            try {



                workerThreadHandler.getLooper().quit();
            }catch(Exception e){
                text1.setText(e.getMessage());
                text2.setText( "Exception!");
            }

        }
    });

    Button buttonSend = (Button) findViewById(R.id.buttonSend);
    buttonSend.setOnClickListener(new View.OnClickListener(){
        public void onClick(View view) {
            try {
                text1.setText(new RestGet().execute(editText.getText().toString()).get());
                text2.setText("everything went well!");
            }catch(Exception e){
                text1.setText(e.getMessage());
                text2.setText( "Exception!");
            }

        }
    });
}

And here is the code for the RestPostThread:

public class RestPostThread extends Thread  {
public Handler mHandler;

@Override
public void run(){

    Looper.prepare();
    mHandler = new Handler() {
        public void handleMessage(Message msg) {
            Log.d("MYASDASDPOASODAPO", "dentro mensaje");
            while (!msg.obj.equals(null)) {
                try {
                    Thread.sleep(1000);
                    URL url = new URL(msg.obj.toString());
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setDoOutput(true);
                    conn.setRequestMethod("POST");
                    String input = "<Instruction><type>put_me_in</type><room>Room 1</room></Instruction>";

                    OutputStream os = conn.getOutputStream();
                    os.write(input.getBytes());
                    os.flush();

                    if (conn.getResponseCode() != HttpURLConnection.HTTP_CREATED) {
                        //  throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode());
                    }
                    BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
                    String output;
                    String aux = new String();
                    while ((output = br.readLine()) != null) {
                        aux = aux + output;
                    }
                    conn.disconnect();
                    //return aux;
                } catch(MalformedURLException e) {
                    e.printStackTrace();
                    //return null;
                } catch(IOException e) {
                    e.printStackTrace();
                    //return null;
                } catch(Exception e) {
                }
            }
            Log.d("CLOSING MESSAGE", "Closing thread");
        }
    };
    Looper.loop();
}

public Handler getThreadHandler() {
    return this.mHandler;
}
Hart
  • 1
  • 3
  • So what exactly is the question? – Mister Smith Mar 15 '16 at 17:09
  • Sorry, I wrote can and I meant can't in "I can't quit the looper or send a different message to it with another IP or something." – Hart Mar 15 '16 at 18:02
  • Sorry if its off topic but it's really easy to learn how to use library like Retrofit, http://square.github.io/retrofit than handling network with Background tasks. – Shailesh Mar 15 '16 at 18:05
  • The thing is that I need to have a background thread posting continously "I am alive" messages and I dont know if retrofit can do that – Hart Mar 16 '16 at 10:04

2 Answers2

0

Have a look at HandlerThread for dealing with a thread to handle just messages. Your Handler should not loop on a message like that, it won't work. It's the Looper's job to deal with new, incoming Message or Runnable objects sent to the Handler which is bound to the Looper.

Regardless, you should take a closer look at using a Loader to handle REST type APIs; or, explore a 3rd party library, such as retrofit, for dealing with REST.

Larry Schiefer
  • 15,687
  • 2
  • 27
  • 33
  • I think Loader is not the best approach for REST. It was meant to load data from Content Providers. – Mister Smith Mar 15 '16 at 17:05
  • Nope, it's actually meant for any asynchronous type operation where you are loading data. However, only the `CursorLoader` is provided by the framework. You can build upon the `AsyncLoader` base class to create your own REST loaders. They actually works quite well because they are life cycle aware, unlike `AsyncTask`, and they are run on a background thread. – Larry Schiefer Mar 15 '16 at 18:52
  • I looked at HandlerThread but I can't figure out how to comunicate between the UI thread and the HandlerThread, also I need the POST thread to be posting constantly in the background and I dont know how to do so without a loop. – Hart Mar 16 '16 at 09:54
  • Posting constantly would be very bad - it's going to use up a lot of network bandwidth and battery to keep spinning and posting. Be careful with what you really need to do. If you need to periodically send a "I'm alive" type message, then make it time based and event driven. You can use the same `Handler` to do that. This gist should help: https://gist.github.com/hiq-larryschiefer/956b572a1753b4ab741b – Larry Schiefer Mar 16 '16 at 10:41
  • It is something that I need to do imperatively because if the connection is lost with the telephone we need to stop a dangerous process. That's why a loop of "I am alive" messages would be in order. I figured out how to use HandlerThread but I dont know how to post constantly for a period of time. – Hart Mar 16 '16 at 11:13
  • Networks are tricky and unreliable, so be careful with how much you depend on the "continuous I'm alive" type messages. As far as getting something back on the UI thread, you can setup a `Handler` in the `Activity.onCreate()` and just send it a `Message` or even a `Runnable`. Or, use `Activity.runOnUiThread()` to post a `Runnable` for the UI thread to execute. – Larry Schiefer Mar 16 '16 at 13:42
  • I managed to solve it as I posted. You pointed me in the right direction, thanks! – Hart Mar 16 '16 at 14:04
0

I managed to solve the issue. The problem was that I was wrapping everything inside this:

while (!msg.obj.equals(null)) {}

I implemented handlers in both this thread and the UI thread and now I have communication back and forth between the both, my RestPostThread looks like this now:

public class RestPostThread extends Thread  {

public Handler mHandler,uiHandler;


public RestPostThread(Handler handler) {
    uiHandler = handler;
}

@Override
public void run(){
    Looper.prepare();
    mHandler = new Handler() {
        public void handleMessage(Message msg) {
                try {
                    //Thread.sleep(1000);
                    URL url = new URL(msg.obj.toString());
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setDoOutput(true);
                    conn.setRequestMethod("POST");
                    String input = "<Instruction><type>put_me_in</type><room>Room 1</room></Instruction>";

                    OutputStream os = conn.getOutputStream();
                    os.write(input.getBytes());
                    os.flush();

                    if (conn.getResponseCode() != HttpURLConnection.HTTP_CREATED) {
                        //  throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode());
                    }
                    BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
                    String output;
                    String aux = new String();
                    while ((output = br.readLine()) != null) {
                        aux = aux + output;
                    }
                    conn.disconnect();
                    Message msg2 = uiHandler.obtainMessage();
                    msg2.obj = aux;
                    uiHandler.sendMessage(msg2);
                }catch(MalformedURLException e){
                    e.printStackTrace();
                }catch(IOException e){
                    e.printStackTrace();
                }catch(Exception e){
                }
            }
    };
    Looper.loop();
}


public Handler getThreadHandler() {
    return this.mHandler;
}

}

And in my MainActivity I have this handler that allows me to "loop" (basically is just going back and forth between the RestPostThread and the UIThread) my Post message until I decide to stop from the MainActivity changing the boolean loop:

 public Handler uiHandler = new Handler() {
    public void handleMessage(Message inputMessage) {
        Log.d("FROM UI THREAD",inputMessage.obj.toString());
        if(loop) {
            Message msg = workerThreadHandler.obtainMessage();
            String url = "http://192.168.1.224:9000/xml/android_reply";
            msg.obj = url;
            workerThreadHandler.sendMessageDelayed(msg,1000);
        }
    }
};
Hart
  • 1
  • 3