CountdownTimer crashing app. Trying to update UI thread on tick - java

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?

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();
}
}

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().

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));

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);
}
});
}
}

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();

Related

Android / java - Using a timer Loop inside an onClick

This is my first question so I apologise if the format isn't correct.
I'm using java and trying to get a timer to run within a while loop when a button is clicked. The result should cause a .setText to alter the text in a box periodically once the start button is clicked.
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startBtn = findViewById(R.id.startButton);
item = findViewById(R.id.Rule);
startBtn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
while(true)
{
Timer();
}
}
});
}
public void Timer()
{
Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
#Override
public void run()
{
item.setText()
}
}, 5000);
}`
The issue is that when the start button is hit, nothing seems to happen.
Alternatively I also tried repeating the timer call instead. Whilst this worked it will only run the timer call once and then end the click function.
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startBtn = findViewById(R.id.startButton);
item = findViewById(R.id.Rule);
startBtn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
Timer();
Timer();
Timer();
Timer();
Timer();
}
});
}
public void Timer()
{
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
item.setText(ruleOut(rulesList));
}
}, 5000);
}
I haven't been able to find anything or work anything out for this so any help is much appreciated. I'm sure that i'll be missing something obvious. Thank you.
what you are doing is you are running all the timers at the same time so all are getting executed at the same time try to run this code
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startBtn = findViewById(R.id.startButton);
item = findViewById(R.id.Rule);
startBtn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
for(int i = 5000; true; i= i+5000){
Timer(i);
}
}
});
}
public void Timer(int time)
{
Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
#Override
public void run()
{
item.setText(String.valueOf(time));
}
}, time);
}`
Problem:
Your Timer method:
public void Timer() {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
item.setText(ruleOut(rulesList));
}
}, 5000);
}
What it does is create a new handler and posts(schedules) a block of code to run after 5 secs and returns immediately without actually executing that code.
So when you call this method multiple times, it schedules the task and returns immediately and schedules the task again and so on. Since the functions returns immediately, all the scheduled Runnable's are executed at the same time.
When you call this method inside an infinite loop, it schedules and returns and schedules and return and so on forever and never returns, causing the freezing of app.
Solution:
To solve your method you can modify the run() method to call this method after the scheduled task has been executed.
public void Timer() {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
item.setText(ruleOut(rulesList));
Timer();
}
}, 5000);
}
And set your click handler as:
startBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Timer();
}
});
In this way, as soon as you click the button, the setting of text will be scheduled to be done after 5 secs and the method Timer will run and schedule the task again.

Using timers - how to?

I got a problem with timer. After 2 sec instead of this action I am getting an error.
public class MainActivity extends AppCompatActivity {
private TextView tv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
tv = (TextView)findViewById(R.id.tv);
Timer timer=new Timer();
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
tv.setText("why?");
}
};
timer.schedule(timerTask,2000);
}
}
How to fix this?
You cannot run these from non main thread
#Override
public void run() {
tv.setText("why?");
}
You have to use runOnUiThread
#Override
public void run() {
runOnUiThread(new Runnable(){
#Override
public void run() {
tv.setText("why?");
}});
}
}
Or use post method of View like
#Override
public void run() {
tv.post(new Runnable(){
#Override
public void run() {
tv.setText("why?");
}});
}
}
I know it looks like weird, but if you write it using lambdas its much better and concise
timer.schedule(()->{tv.post(()->{setText("why?");}},2000);
You cannot update UI from inside a thread. Update UI from main thread.
Create a handler and send message to the handler after your work has been completed and update the UIthere.
Handler handler = new Handler()
{
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// Update UI
}
};
and send message to handler using handler.sendMessage()

How do I access my CountDownTimer to cancel it in Java?

Making a small game in Android Studio. Basically, the user will have a set amount of time to trigger a button press or the game will end. My CountDownTimer object is inside of a different function than my button click handler. How can I cancel the countDownTimer using cancel() from the button click handler.
Here is my code:
public countDownTimer timeLimit;
public void generate() {
final ProgressBar timer = (ProgressBar)findViewById(R.id.timer);`
int timeoutSeconds = 5000;
timer.setMax(timeoutSeconds);
timeLimit = new CountDownTimer(timeoutSeconds, 100) {
public void onTick(long millisUntilFinished) {
int timeUntilFinished = (int) millisUntilFinished;
timer.setProgress(timeUntilFinished);
}
public void onFinish() {
gameOver();
}
};
timeLimit.start();
}
public void buttonClicked(View v) {
timeLimit.cancel();
}
I'd be happy to hear any alternative ways to do this as well.
The code below works perfectly for me.
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private ProgressBar progressBar;
private CountDownTimer countDownTimer;
private Button stopTimerButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progressBar = (ProgressBar)findViewById(R.id.progressBar);
stopTimerButton = (Button)findViewById(R.id.button);
stopTimerButton.setOnClickListener(this);
int timeoutSeconds = 5000;
progressBar.setMax(timeoutSeconds);
countDownTimer = new CountDownTimer(timeoutSeconds,100) {
#Override
public void onTick(long millisUntilFinished) {
int timeUntilFinished = (int) millisUntilFinished;
progressBar.setProgress(timeUntilFinished);
}
#Override
public void onFinish() {
}
};
countDownTimer.start();
}
#Override
public void onClick(View view) {
if(view == stopTimerButton){
countDownTimer.cancel();
}
}
}

How to automatically Click a Button in Android Every Second

How to automatically Click a Button in Android after a 5 second delay
I tried with the codes that are entered in the link but my application has crashed
My codes;
public class MainActivity extends AppCompatActivity {
Button button;
TextView text;
#Override
protected void onCreate(Bundle savedInstanceState) {
try {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttonClick();
Thread timer = new Thread() {
public void run() {
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
button.performClick();
}
}
};
timer.start();
} catch (Resources.NotFoundException e) {
e.printStackTrace();
}
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
button.performClick();
}
}, 1000);
}
public void buttonClick() {
button=(Button) findViewById(R.id.button);
text=(TextView) findViewById(R.id.text);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Random s=new Random();
int number=s.nextInt(3);
switch (number)
{case 1:text.setText("1");
break;
case 2: text.setText("2");
break;
}
}
});
}
}
Logcat Error
You need to use
runOnUiThread(new Runnable() {
#Override
public void run() {
}
});
to avoid this error.
Please check Android "Only the original thread that created a view hierarchy can touch its views."
Also you can just use the Handler to perform the button click after a specified amount of time, no need to use the timer.
This is more simpler method to run every second. you dont need to trigger the button. just call the method you want to execute
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Handler handler = new Handler();
Runnable runnable = new Runnable(){
#Override
public void run() {
buttonClick();
if(handler!=null)
handler.postDelayed(runnable, 1000);
}
}
handler.postDelayed(runnable, 1000);
}

How to stop timer of an activity from another activity

Right now I have an activity, let's say 'Activity A' that runs the Timer. It is to update my Firebase when the time is up.
timer.scedule(new TimerTask()){
#Override
public void run() {
notification();
Firebase areaRef = mAreaRef.child(bKey);
areaRef.addListenerForSingleValueEvent(new com.firebase.client.ValueEventListener() {
#Override
public void onDataChange(com.firebase.client.DataSnapshot dataSnapshot) {
checkData = dataSnapshot.child("data").getValue(Integer.class);
Integer addData = checkData+1;
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
},millis);
There will be a button at 'Activity B'. When the button is clicked, the timer at 'Activity A' must be stopped.
How do I do this?
There just can be only one "Activity" activated in the same time. Your 'Activity A' can be instead by a service. And then your problem is solved by 'Activity B' directly call service method to stop the timer when the button is clicked.
If your timer task really needs to be alive across activities, maybe you should consider use a Service instead of a timer in specified activity.
1.Change Timer to CountDownTimer call start() to begin call cancel() to stop.
How to notify Activity A to stop the CountDownTimer, you can change SharedPreferences to others way to deal with data notify
public class MainActivity extends AppCompatActivity {
CountDownTimer timer = new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
SharedPreferences sharedPreferences = getSharedPreferences("count", 0);
if (sharedPreferences.getBoolean("stop", false)) {
timer.cancel();
} else {
Log.d("tag", millisUntilFinished / 1000 + "");
}
}
public void onFinish() {
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
timer.start();
Intent intent = new Intent(this, ActivityB.class);
startActivity(intent);
}
}
public class ActivityB extends AppCompatActivity {
Button mStop;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
mStop =(Button) findViewById(R.id.stop);
mStop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
SharedPreferences sharedPreferences = getSharedPreferences("count",0);
SharedPreferences.Editor edit= sharedPreferences.edit();
edit.putBoolean("stop", true);
edit.apply();
}
});
}
}

Categories