i am trying to update a TextView every 5 seconds with a random number.
Unfortunately the timer stops when i call the .setText-function (i commented it out, it is because of this specific statement). I call the Timer in the onCreate()-Method of the Activity.
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
Random r = new Random();
count = r.nextInt(10);
String degree = Integer.toString(count);
mDegrees.setText(degree);
showToast();
}
}
, 1, 5, TimeUnit.SECONDS);
}
Also showToast() is not called. Why is that?
Best regards,
Max
Related
I am beginner in android.
What I want:
Here I am trying to achieve that sub handler should call 10 times of every second of main handler. And that main handler should continue until 20 seconds.
Issue:
To check that i\I have used log but its not working. It goes into sub handler some times 8 times or some times 9 or 10.
Is there any logical error or is there any other better way to achieve this?
Thank you.
My code:
int i=0;
int cont;
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
i++;
cont = 1;
Log.e("main count", i + "");
final Handler handler1 = new Handler();
handler1.postDelayed(new Runnable() {
#Override
public void run() {
if (cont <= 10) {
Log.e("sub count ", cont + "");
cont++;
handler1.postDelayed(this, 100);
}
}
}, 100);
if (!(i == 20)) {
handler.postDelayed(this, 1000);
}
}
}, 1000);
It's difficult to execute code with precise timing using a Handler because you have to measure the time yourself.
It's much easier to use the built-in classes like ScheduledThreadPoolExecutor or Timer. I'd recommend the first as it would require less changes to the code. You should pick one of the scheduleAtFixedRate() or scheduleWithFixedDelay() methods according to your requirements.
final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(2);
final ScheduledFuture mainFuture = executor.scheduleWithFixedDelay(new Runnable() {
public void run() {
if (i < 20) {
Log.e("main count ", i + "");
i++;
} else {
mainFuture.cancel(true);// stop after 20 executions
}
},
0, /*initial wait time*/
1, /* time between consecutive runs */
TimeUnit.SECONDS);
final ScheduledFuture subFuture = executor.scheduleWithFixedDelay(new Runnable() {
public void run() {
if (cont < 20 * 10) {
Log.e("sub count ", cont + "");
cont++;
} else {
subFuture.cancel(true);// stop after 200 executions
executor.shutdown();
}
},
100, /*adjust this according to the desired sequencing of the count tasks */
100, /* time between consecutive runs */
TimeUnit.MILLISECONDS);
You could also use a single ScheduledFuture and execute the code for main count after every 10 executions of the sub count code.
I have a CountDown timer that counts down from 10000ms to 0ms in increments of 1 second each to make a button clickable after 10 seconds. Although the timer is accurate and does what the code says, I would like to change the way the seconds are expressed but I don't know how.
java:
void startTimer() {
cTimer = new CountDownTimer(10000, 1000) {
public void onTick(long millisUntilFinished) {
c.setText("Please wait " + millisUntilFinished/1000 + " seconds");
thx.setText(millisUntilFinished/1000 + "");
thx.setAlpha(.5f);
thx.setClickable(false);
}
public void onFinish() {
c.setText("done");
thx.setText("ready");
thx.setAlpha(1f);
thx.setClickable(true);
}
};
cTimer.start();
}
Outputted (Every second): 9, 8, 7, 6, 5, 4, 3, 2, 1, (still 1), ready
Desired: (Every second): 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, ready
Thanks,
B
EDIT:
I added 1 to the countdown, thx.setText(((millisUntilFinished/1000) + 1) + "");
New output: 10, 9, 8, 7, 6, 5, 4 ,3 , 2, (Still 2), ready
Closer... but not quite.
This is just my investigation on CountDownTimer when I used CountDownTimer
few month before and its work fine in my application.
public void onTick(long millisUntilFinished)
This millisUntilFinished will give the remaining time in millisecond, and last 1000 millisecond is to call onFinish() method, So onTick method will get called until the remaining time is more than (1000(for OnFinish) + 1000(for counter)) milliseconds, if the last remaining millisecond is less than 2000millisecond it will skip the onTick() and it will directly call onFinish() when timer ends. For more details just see Handler method in this source.
So the main problem is when we give some X(our case 10000)milliseconds, but to start the counter it's taking some 50 to 150 milliseconds, So if we add that millisecond in our total time we will get the counter until end,
So you can try like this, Nothing change just I added 150 milliseconds in your total time.
void startTimer() {
cTimer = new CountDownTimer(10150, 1000) {
public void onTick(long millisUntilFinished) {
c.setText("Please wait " + millisUntilFinished/1000 + " seconds");
thx.setText(millisUntilFinished/1000 + "");
thx.setAlpha(.5f);
thx.setClickable(false);
}
public void onFinish() {
c.setText("done");
thx.setText("ready");
thx.setAlpha(1f);
thx.setClickable(true);
}
};
cTimer.start();
}
Let me know if its works or not, If you ask me why you are not using Handler, I can say CountDownTime internally using Handler.
Try this one for counter:
public void CountDown() {
final TextView textic = (TextView) findViewById(R.id.tvConuter);
CountDownTimer Count = new CountDownTimer(10000, 1000) {
public void onTick(long millisUntilFinished) {
long str = millisUntilFinished / 1000;
String TimeFinished = String.valueOf(str);
textic.setText(TimeFinished);
}
public void onFinish() {
textic.setText("STOP");
}
};
Count.start();
}
This worked perfectly for me.
I would suggest to use Timer() or Handler() class.
int tick = 0;
Handler handler = new Handler();
Runnable r = new Runnable() {void run(){
if (i < 10) {
handler.postDelayed()}
else {
//finished
tick = 0;
}}};
starting:
handler.post(r);
new CountDownTimer(10000, 1000) {
public void onTick(long millisUntilFinished) {
mTextField.setText("seconds: " + millisUntilFinished / 1000);
//here you can have your logic to set text to edittext
}
public void onFinish() {
mTextField.setText("done!");
}
}.start();
private void countDownTimer(int seconds) {
countDownTimer = new CountDownTimer(seconds * 1000L, 1000 - 500) {
public void onTick(long millisUntilFinished) {
//Convert to seconds
int secondsUnillFinished = (int) (millisUntilFinished / 1000);
//Set text to seconds
textView.setText(String.valueOf(secondsUnillFinished));
//At zero, do something
if(secondsUnillFinished == 0) {
countDownTimer.cancel();
textView.setVisibility(View.INVISIBLE);
}
}
#SuppressLint("SetTextI18n")
public void onFinish() {
//Dont put anything here
}
}.start();
}
For my code I use a countdown timer, however I add seconds to it as after they get an answer correct, the timer is reset to 5 seconds. The problem with this is that the text that displays the time still has the wrong number, it doesn't repeat digits. For instance if it was a 5 second timer and it goes 5,4,3 then the user gets it right, the time will go 3, 3, 3, 2, 1.
Here is my countdown code
n = 5000;
time = new TextView(this);
time.setTextColor(Color.parseColor("#FFFFFF"));
timer = new CountDownTimer(n, 1000) {
public void onTick(long millisUntilFinished) {
time.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
Intent endIntent = new Intent(MainActivity.this, Endgame.class);
endIntent.putExtra("rounds",round);
MainActivity.this.startActivity(endIntent);
}
}.start();
Then if the user gets the question right - this is the part that restarts it
if(person == false){
picturechanger();
n=5000;
timer.onTick(5000);
}
Try:
if(person == false){
picturechanger();
n=5000; // Not sure why u put n=5000 here..?
if(timer != null)
timer.cancel();
timer.start();
}
I don't really want to start a thread then put it to sleep, such as:
Thread.start();
Thread.sleep(3000); //*Example*
Instead, I want to this something like this (And I apologize for this amateur illustration):
Thread.start(3000) //*thread will be given a certain amount of time to execute*
//*After 3000 milliseconds, the thread stops and or sleeps*
I'm doing this because I'm making a program/ mini-game that times user input for a certain time. Basically, the user has 5 seconds to input a certain character/number/letter and after that time, the input stream is cut off. Kind of like:
Scanner kb = new Scanner(System.in);
int num = kb.nextInt();
kb.close() //*Closes kb and input stream in turn*
I suggest you use a ScheduledExecutorService and scheduleWithFixedDelay(Runnable, long, long, TimeUnit). You can cancel that if the user completes whatever task before the delay expires. If the delay runs out then the user failed whatever task.
You can try this sample.
final List<Integer> result = new ArrayList<>();
Thread thread = new Thread() {
volatile boolean isDone = false;
Timer timer = new Timer();
#Override
public void run() {
timer.schedule(new TimerTask() {
#Override
public void run() {
isDone = true;
}
}, 5000);
Scanner kb = new Scanner(System.in);
while (!isDone) {
int num = 0;
num = kb.nextInt();
result.add(num);
}
kb.close();
}
};
thread.start();
thread.join();
for (Integer i : result) {
System.out.print(i + " ");
}
Here is my timer class, This class is designed to constantly update a timer in a view. However, when I run the app the first toast message is displayed to the screen but the second one is never reached (the timerTask's "run" method is never executed). I know that this is probably something simple that I am doing wrong. If anyone could steer me in the right direcion that would be great.
public class MyTimer {
static Timer _timerTask = new Timer();
static int totalSeconds = 1, hour = 0, min = 0, sec = 0;
static String mTimeFormat = "%02d:%02d:%02d";
static String timeTakenString;
public static void start (){
Toast.makeText(GPSMain.context, "Message one", Toast.LENGTH_LONG).show();
TimerTask timer = new TimerTask() {
#Override
public void run() {
Toast.makeText(GPSMain.context, "Message two", Toast.LENGTH_LONG).show();
totalSeconds += 1;
sec += 1;
if(sec >= 60) {
sec = 0;
min += 1;
if (min >= 60) {
min = 0;
hour += 1;
}
}
timeTakenString = String.format(mTimeFormat, hour, min, sec);
postExecute.sendEmptyMessage(0); //update UI
}
private Handler postExecute = new Handler(){
public void dispatchMessage(Message msg) {
super.dispatchMessage(msg);
GPSMain.timer.setText("Time Taken: "+timeTakenString);
}
};
};
_timerTask.scheduleAtFixedRate(timer,1000,1000);
}
}
code in another file calling this class:
MyTimer myTimer = new MyTimer();
....
myTimer.start();
PROJECT SPEC CHANGED!
My project leader changed the spec of the project so that it no longer needs to update the timer to the UI but rather display it as an end result. Accepting the first answer anyway as it solves the original problem. Will post the new code below.
New code calls:
System.currentTimeMillis();
at the beggining and end of the runcycle, which returns a long. The first value is then subtracted from the second value to calculate the amount of time taken to execute the runcycle. That value is then manipulated and put into a timer format that is displayed at the end as a string.
public static String getTimeTaken(long end, long start){
#SuppressWarnings("unused")
String formattedTime = "", hourHour = "", hourMin = ":", minSec = ":";
long timeTaken = (end-start)/1000, hour = 0, min = 0, sec = 0;
if (timeTaken>9 ){
hourHour = "0";
hourMin = ":0";
if (timeTaken>=60){
if (timeTaken>= 3200){
hour = timeTaken/3200;
timeTaken = timeTaken%3200;
if (hour>9){
hourHour = "";
}
}
min = timeTaken/60;
timeTaken = timeTaken%60;
if (min >9){
hourMin = ":";
}
}
sec = timeTaken;
if(sec%60<10){
minSec = ":0";
}
return formattedTime = (hourHour+hour+hourMin+min+minSec+sec);
}
sec = timeTaken;
minSec = ":0";
hourMin = ":0";
hourHour = "0";
return formattedTime = (hourHour+hour+hourMin+min+minSec+sec);
}
Using thread you cant update your UI for that you have to use runOnUiThread
youractivity.this.runOnUiThread(new Runnable(){public void run(){Toast.makeText(mContext, "Message", Toast.LENGTH_LONG).show();}});
(Very late...just answering in case someone reach this question... scheduling a task doesn't garantee it will run on the proper time... it may take longer, sometimes much longer...)