change android UI according to a background thread results

1.9k views Asked by At

I'm developing an android app that requires to make UI changes according to a background thread processing results, I tried the following code at first:

        Thread run_time = new Thread (){
            public void run(){
                ConnectToServer connect = new ConnectToServer(null);
                while(true){
                        String server_response = connect.getServerResponse();
                        if(!server_response.equals(null)){  
                            setResponse(server_response);
                            response_received();
                    }
                }
            }
        };
        run_time.start();

but my App crashes because i tried to make a UI changes from that background thread, then I tried that way:

        runOnUiThread(new Runnable() {
            public void run(){
                ConnectToServer connect = new ConnectToServer(null);
                while(true){
                        String server_response = connect.getServerResponse();
                        if(!server_response.equals(null)){
                            setResponse(server_response);
                            response_received();
                    }
                }
            }
        });

but i got that exception:

01-29 16:42:17.045: ERROR/AndroidRuntime(605): android.os.NetworkOnMainThreadException
01-29 16:42:17.045: ERROR/AndroidRuntime(605):     at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1084)
01-29 16:42:17.045: ERROR/AndroidRuntime(605):     at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:151)
01-29 16:42:17.045: ERROR/AndroidRuntime(605):     at libcore.io.IoBridge.recvfrom(IoBridge.java:503)
01-29 16:42:17.045: ERROR/AndroidRuntime(605):     at java.net.PlainSocketImpl.read(PlainSocketImpl.java:488)
01-29 16:42:17.045: ERROR/AndroidRuntime(605):     at java.net.PlainSocketImpl.access$000(PlainSocketImpl.java:46)

and after search i found that I must run the code as AsyncTask to avoid these problems, but when attempting to use it i found that it's must be used with small tasks only not like a thread that runs in the background all the run_time.

So, what's the best day to run a thread or a task in the background in whole the run_time and also reflect it's changes to the UI.

4

There are 4 answers

0
Nathaniel D. Waggoner On

EDIT:

For Long running network work you have a few options.

First and formost check the android docs on this topic:

http://developer.android.com/training/basics/network-ops/index.html

Next, I generally use Services for this type of thing:

https://developer.android.com/guide/components/services.html

I will point you at the vogella tutorial for this as well:

http://www.vogella.com/tutorials/AndroidServices/article.html

For communication from threads/asynctasks/services to the UI use Handlers:

Use Handlers:

static public class MyThread extends Thread {
    @Override
    public void run() {
      try {
        // Simulate a slow network
        try {
          new Thread().sleep(5000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        downloadBitmap = downloadBitmap("http://www.devoxx.com/download/attachments/4751369/DV11");
        // Updates the user interface
        handler.sendEmptyMessage(0);
      } catch (IOException e) {
        e.printStackTrace();
      } finally {

      }
    }
  }
    handler = new Handler() {
      @Override
      public void handleMessage(Message msg) {
        // cal uiMethods here...
        imageView.setImageBitmap(downloadBitmap);
//        dialog.dismiss();
      }

    };

Taken from this tutorial:

http://www.vogella.com/tutorials/AndroidBackgroundProcessing/article.html

You can make this more interesting by defining constant_codes which corespond to the desired action:

private int DO_THIS = 0x0;
private int DO_THAT = 0x1;

// in your UI:

 public void handleMessage(Message msg) {
        // cal uiMethods here...
        switch(msg.what()){
           case(DO_THIS):
             // do stuff
             break;
           case(DO_THAT):
            // do other stuff
            break;
        }
      }

// in your thread:

Message m = handler.obtainMessage(DO_THIS);
handler.sendMessage(m);

If the thread code (asynch task, service etc...) is separate from the UI you can use Broadcasts to pass the data between the two and then use Handlers from there to act on the UI thread.

0
Darko Rodic On
1
Rajan On

Use this code - it may contain compile time error you have to do it correct

public class MainActivity extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    Connect connect = new Connect();
    connect.execute();
}

class Connect extends AsyncTask<Void, String, Void>
{
    @Override
    protected Void doInBackground(Void... params) 
    {
        ConnectToServer connect = new ConnectToServer(null);
        while(true)
        {
            String server_response = connect.getServerResponse();
            if(!server_response.equals(null))
            {  
                publishProgress(server_response);
                //setResponse(server_response);
                response_received();
            }
        }
        return null;
    }

    @Override
    protected void onProgressUpdate(String... values) {

        super.onProgressUpdate(values);
        setResponse(values[0]);
    }

    @Override
    protected void onPostExecute(Void result) {
        super.onPostExecute(result);
    }
}
}
2
Jerry Wattre On

You need "handlers" along with "loopers" for optimization Example:

public void myMethod(){
    Thread background = new Thread(new Runnable(){
        @Override
        public void run(){
            Looper.prepare();
            //Do your server process here
            Runnable r=new Runnable() {
                   @Override
                   public void run() {
                                            //update your UI from here
                   }
            };
            handler.post(r);
            Looper.loop();
        }
    });
    background.start();
}

And of course this is without using AsyncTask