dev_pool
dev_pool

Reputation: 193

Most efficient way to continuously update the UI Thread in Android

I am experimenting with Threading in Android development by creating a stop watch. I currently have a very basic execution that seems to work just fine on the emulator, but when ran on my phone is anything but efficient (Pretty new Nexus 6 so the phone is fine). My question is, what is the most efficient way to update the UI thread continuously as a stop watch would need to do?

I am currently running it in an AsyncTask that updates the UI onProgressUpdate. I imagine an AsyncTask isn't the best choice, but I've also tried it in my own Runnable that ran even worse. I read about the Handler class, but am not confident in how to use it (or know if it's the answer). Below is where I am creating and executing my AsyncTask, and also the AsyncTask itself. I should note this is in a fragment.

// Where the thread kicks off on click
private class StartTimer implements View.OnClickListener{
    @Override
    public void onClick(View v) {
        // passes the stopWacth object and the view to update
        clockThread = new HiitClock(clockTv, stopWatch);
        clockThread.execute();
    }
}

Then this is my class that extends the AsyncTask

public class HiitClock extends AsyncTask<String, Void, String> {

    private final String LOG_TAG = HiitClock.class.getSimpleName();
    private TextView clock;
    private StopWatch stopWatch;

    public HiitClock(TextView clock, StopWatch sw){
        this.clock = clock;
        this.clockSegment = clockSegment;
        this.roundSegment = roundSegment;
        this.stopWatch = sw;
    }


    @Override
    protected String doInBackground(String... params) {

        stopWatch.start();

        while(stopWatch.getState() == 1 || stopWatch.getState() == 2){
            publishProgress();
        }

        return "done";
    }

    @Override
    protected void onProgressUpdate(Void... values) {
        super.onProgressUpdate(values);

        clock.setText(convertTime());
    }

    @Override
    protected void onPostExecute(String result) {
        // end of timer
       clock.setText(result);
    }

    /*
    * helper method for converting the time
    * */
    private String convertTime(){

        long milli = stopWatch.getTime();
        long sec = milli / 1000 ;
        long min = sec / 60;
        sec = sec % 60;
        milli = milli % 100;

        return String.format("%02d:%02d:%02d", min, sec, milli);
    }
}

-------Update---------

I appreciate the responses. I've tried all suggestions and the performance is still terrible on a real device. I created a bare bones example below. Perhaps this bare bones version will help someone see what I am doing that is keeping the UI Thread from updating efficiently. It loops 100,000 times and uses a handler to try and update the UI thread. Thanks!

public class MainActivity extends Activity {

    private RelativeLayout wrapper;
    private TextView clockTv;
    private Handler handler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        handler = new Handler();
        wrapper = (RelativeLayout) findViewById(R.id.hitt_cardio_layout);
        clockTv = (TextView) wrapper.findViewById(R.id.clock_text_view);

        Button start = new Button(this);
        start.setText("Start");
        wrapper.addView(start);
        start.setOnClickListener(new StartTimer());

    }

    private class StartTimer implements View.OnClickListener {

        @Override
        public void onClick(View v) {

            new Thread(new Runner()).start();

        }

    }

    private class Runner implements Runnable{
        int i;
        @Override
        public void run() {
            for(i = 0; i < 100000; i++){
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        clockTv.setText("index: " + i);
                    }
                });
            }
        }
    }
}

Upvotes: 2

Views: 6105

Answers (2)

Kaveesh Kanwal
Kaveesh Kanwal

Reputation: 1763

You can use onProgressUpdate() to update your UI. Apart from this there are two more ways of doing it:

  1. Use Activity's runOnUiThread method:

      Activity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        //update your UI
                    }
                });
    
  2. You can also use Handler:

    Handler h = new Handler(){
      @Override
      public void handleMessage(Message msg){
         if(msg.what == 0){
            updateUI();
         }else{
            showErrorDialog();
         }
      }
    };
    

Upvotes: 0

njzk2
njzk2

Reputation: 39386

You can post runnable on the thread that updates the view:

clock.post(new Runnable() {
    @Override public void run() {
        clock.setText(convertTime());
        // 50 millis to give the ui thread time to breath. Adjust according to your own experience
        clock.postDelayed(this, 50);
    }
});

(I omitted the stopping logic to keep the example short. Putting it back is a matter of testing and not reposting the runnable).

Upvotes: 1

Related Questions