Jamanfi
Jamanfi

Reputation: 11

CountdownTimer crashing app. Trying to update UI thread on tick

I want the countdowntimer to be on a separate thread and for it to update the UI on each tick. Every time I click start the app just closes and I get the 'app has stopped' error message.

public class Activity_MultiplayerGame extends AppCompatActivity {

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

public void btnStart_onClick(View view){
    CountDownTimer timer = new CountDownTimer(15000, 1000){

        @Override
        public void onTick(final long millisUntilFinished) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    TextView countdownText = (TextView) findViewById(R.id.countdown);
                    Integer timeUntilFinished = (int) millisUntilFinished/1000;
                    countdownText.setText(timeUntilFinished);
                }
            });
        }

        @Override
        public void onFinish() {
            TextView countdownText = (TextView) findViewById(R.id.countdown);
            countdownText.setText("Finished");
        }
    };

    timer.start();
}
}

I've made the assumption that creating a CountDownTimer gives it its own thread?

Upvotes: 1

Views: 1236

Answers (5)

AbdulAli
AbdulAli

Reputation: 555

The CountDownTimer gives out callbacks on the same thread, in which it was created. So the runOnUiThread in onTick is absolutely not required if the CountDownTimer constructor was called on UI thread.

Also,

TextView countdownText = (TextView) findViewById(R.id.countdown);

being called in onTick method is poor design, as findViewById method consumes considerable processing power.

Finally the actual problem as Nabin Bhandari pointed out is the integer value passed to setText method. You need to wrap it to string. This code is enough

final TextView countdownText = (TextView) findViewById(R.id.countdown);
    CountDownTimer timer = new CountDownTimer(15000, 1000) {
        @Override
        public void onTick(long millisUntilFinished) {
            countdownText.setText(String.valueOf(millisUntilFinished/1000));
        }

        @Override
        public void onFinish() {
            countdownText.setText("Finished");
        }
    };
    timer.start();

Upvotes: 0

faraz khonsari
faraz khonsari

Reputation: 1954

you can use Handler. I wrote a sample for you

this code increase a counter every one second and show and update counter value on a textView.

public class MainActivity extends Activity {


    private Handler handler = new Handler();
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.text);
        startTimer();
    }


    int i = 0;
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            i++;
            textView.setText("counter:" + i);
            startTimer();
        }
    };

    public void startTimer() {
        handler.postDelayed(runnable, 1000);
    }

    public void cancelTimer() {
        handler.removeCallbacks(runnable);
    }

    @Override
    protected void onStop() {
        super.onStop();
        cancelTimer();
    }
}

Upvotes: 1

mancini13
mancini13

Reputation: 35

This code also work it decrease counter(or increase whatever you want) and show in text view you can also stop or reset counter via click the same button.

public class MainActivity extends AppCompatActivity {


TextView textView;
Button count;

boolean timelapseRunning = true;
int NUM_OF_COUNT=15;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    textView=(TextView)findViewById(R.id.textview);
    count=(Button)findViewById(R.id.count);
    runTimer();

}
public void onclick(View view){
    if (!timelapseRunning) {
       timelapseRunning=true;
    } else {
        timelapseRunning = false;

    }
    if(NUM_OF_COUNT==0){
        NUM_OF_COUNT=15;
    }
}
private void runTimer() {
           final Handler handler = new Handler();
    handler.post(new Runnable() {
        @Override
        public void run() {
            textView.setText(""+NUM_OF_COUNT);
            if (!timelapseRunning && NUM_OF_COUNT>0) {
                NUM_OF_COUNT--;
            }
            handler.postDelayed(this, 1000);
        }
    });
}
}

Upvotes: 0

Nabin Bhandari
Nabin Bhandari

Reputation: 16399

Here's your problem:

countdownText.setText(timeUntilFinished);

You have passed integer to setText(int) method, which actually takes the string resource id rather than the integer to be displayed. You should use the method setText(String).

Try this:

countdownText.setText(String.valueOf(timeUntilFinished));

Upvotes: 0

Josef Adamcik
Josef Adamcik

Reputation: 5780

You cannot update UI from other thread than main (ui) thread on android. There are many ways to approach the problem, but I suppose you should start with AsyncTask if you really need another thread. Check doInBackround and onProgressUpdate methods.

If you don't need other thread (and if this is only about the counter you dont') you can check Handler class and postAtTime(Runnable, long), postDelayed(Runnable, long) methods. Or you can make subclass of Handler class and use combination of sendMessageDelayed(android.os.Message, long) and overridden handleMessage().

Upvotes: 0

Related Questions