I've created a class to make a countdown and used it to return the formated time as a TextView. However, I'm not beeing able to get the time to be exibed on in place. When, instead of calling the method getTime() I use a string, it shows fine.
The main method is like this:
setContentView(R.layout.activity_main);
matchTime = findViewById(R.id.match_Time);
playTime = new Play();
matchTime.setText(playTime.getPlayTime());
While my class Play goes like this:
//Other implementations
private void updatePlay() {
int minutes = (int) (timeUntilEnd/ 1000) / 60;
int seconds = (int) (timeUntilEnd/ 1000) % 60;
timeUntilEndFormated= String.format(Locale.getDefault(),"%02d:%02d", minutes, seconds);
playTime.setText(timeUntilEndFormated);
}
public TextView getPlayTime() {
return playTime;
}
It looks like you are setting the text of matchTime to a TextView.
setText is a method that should receive a String, not a TextView object.
But, if you simply return a String in getPlayTime(), updatePlay() wont work because playTime.setText() wont affect matchTime at all.
To solve this you pass matchTime to Play's constructor, and then update it directly:
public class Play{
private TextView matchTime;
public Play(TextView matchTime){
this.matchTime = matchTime;
}
private void updatePlay() {
int minutes = (int) (timeUntilEnd/ 1000) / 60;
int seconds = (int) (timeUntilEnd/ 1000) % 60;
timeUntilEndFormated= String.format(Locale.getDefault(),"%02d:%02d", minutes, seconds);
matchTime.setText(timeUntilEndFormated);
}
}
And then you only need to do this in your main method:
playTime = new Play(matchTime);
playTime.updatePlay();
Be careful with passing TextView's to other objects. This can create a memory leak, since TextView holds an instance of your Context. To avoid memory leaks you have to release the object in your activity's onDestroy() method:
public void onDestroy() {
super.onDestroy();
playTime = null;
}
Related
Why does the timer stop working when i put the postDelayed(this,1000); inside the if statement, just under seconds++;?
There are 3 buttons (start,stop,reset) in the layout. Press Start->running=true,press stop->running=stop,press reset->running=false seconds=0
private void runTimer() {
final TextView timeView = (TextView) findViewById(R.id.time_view);
final Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
int hours = seconds / 3600;
int minutes = (seconds % 3600) / 60;
int secs = seconds % 60;
String time = String.format("%d:%2d:%02d", hours, minutes, secs);
timeView.setText(time);
if (running) {
seconds++;
//handler.postDelayed(this, 1000);
//doesnt work if i put it here
}
handler.postDelayed(this, 1000);
}
});
}
At the time you call runTimer() the variable running is set to false. Most likely you have to move the call to runTimer() into the onClickStart() method (after setting running to true).
When declaring booleans their default value is assumed with false.
In my program you set the string value for the countdown timer in the secondActivity. That value is then sent to the MainActivities textView which is then supposed to start counting down as soon as the value is fetched. Right now I have made it so you can set the value, and the value is fetched correctly, but what I don't know how to do is start Counting Down this value when It is received. I have already made a CounterClass.
Here is my MainActivity Code...
Bundle extras = getIntent().getExtras();
String intentString;
if(extras != null) {
intentString = extras.getString("TimeValue");
timer = new CounterClass(60000, 1000);
timer.start();
timeSent();
} else {
intentString = "Default String";
}
textTime= (TextView) findViewById(R.id.timeText);
textTime.setText(intentString);
You need to start your timer. Always read the docs.
timer = new CounterClass(millisInFuture, countdownInterval);
timer.start();
EDIT
millisInFuture --- The number of millis in the future from the call to start() until the countdown is done and onFinish() is called.
countDownInterval ---
The interval along the way to receive onTick(long) callbacks.
EDIT 18-12-2015
Convert your intentString to millisInFuture and send it to the CounterClass. And then format it back to HH:MM in onTick() method.
String time = "16:54";
String split[] = time.split(":");
long futureInMillis = Integer.parseInt(split[0]) * 60 * 60 * 1000 + Integer.parseInt(split[1]) * 60 * 1000;
Lets say that you really want to implement your own class.
I think the best and clean way to do it is by interface.
First create a interface class.
AddTimes.java
public interface AddTimes {
void writeTime(String time);
}
Now, implement your interface in your class.
public class MainActivity extends AppCompatActivity implements AddTimes{
Use your class TextView variable "textTime"
timeText = (TextView)findViewById(R.id.timeText); //remove declaration TextView and use timeText instead of textTime .
start your class
new CounterClass(5000L,500L, this).start();
At the CounterClass, add constructor.
AddTimes addTimes;
public CounterClass(long millisInFuture, long countDownInterval, AddTimes addTimes) {
super(millisInFuture, countDownInterval);
this.addTimes = addTimes;
}
Replace textTime.setText(hms); to addTimes.writeTime(hms);
Finally. At your main activity. Implement AddTimes method.
public void writeTime(String time) {
timeText.setText("Time - " + time);
}
Instead of this
TextView timeText = (TextView)findViewById(R.id.timeText);
timeText.setText(intentString);
you need this
textTime= (TextView)findViewById(R.id.timeText);
textTime.setText(intentString);
timer = new CounterClass(10000, 1000);
timer.start();
As you might see timeText has changed to textTime which is a class member variable and your CounterClass uses it.
Copy the code as it is to you MainActivity.java file. Hope this might work.
public class MainActivity extends AppCompatActivity {
TextView textTime;
CountDownTimer timer;
int intValue = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Bundle extras = getIntent().getExtras();
if(extras != null) {
String intentString = extras.getString("TimeValue"); //if this is a plain number like 20, 45, 209, 8
intValue = Integer.valueOf(intentString);
}
textTime= (TextView)findViewById(R.id.timeText);
timer = new CountDownTimer(intValue * 1000, 1000) {
public void onTick(long millisUntilFinished) {
intValue--;
textTime.setText("Count Down: " + intValue);
}
#Override
public void onFinish() {}
}
}
timer.start();
}
You can simply use the count down timer:
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
textField.setText("seconds remaining: " + millisUntilFinished / 1000);
//here you can have your logic to set text to edittext
}
public void onFinish() {
textField.setText("done!");
}
}.start();
I would like to create a stopwatch as an android app. My problem is that I got a stackoverflow. Basically I have a class Timer and an onCreate method that instatiate it. Thats my implementation:
public abstract class Timer implements Runnable {
private boolean running;
public void start(){
running = true;
this.start();
}
#Override
public void run() {
long milliSeconds = 0;
long seconds = 0;
long minutes = 0;
long baseTime = SystemClock.elapsedRealtime();
while(running){
long time = SystemClock.elapsedRealtime() - baseTime;
long rest = time % 60000;
milliSeconds = rest % 1000;
seconds = rest - milliSeconds;
minutes = time - seconds - milliSeconds;
display(milliSeconds, seconds, minutes);
}
}
public void stop(){
running = false;
}
public abstract void display(long milliSeconds, long seconds, long minutes);
}
And my onCreate method:
public TextView time;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.opslimit);
time = (TextView)findViewById(R.id.textView3);
Timer timer = new Timer(){
#Override
public void display(long milliSeconds, long seconds, long minutes) {
time.setText(minutes + ":" + seconds + ":" + milliSeconds);
}
};
timer.start();
}
Has anyone an idea why I got a Stackoverflow. May be it deals with the display part?
You call start method recursively within itself. Fix it, and you won't get SO exception.
Note, however, that even if you change to :
public void start(){
running = true;
this.run();
}
which will fix stackoverflow, your code will run in a main thread and therefore your app won't work. You have to spawn a new thread.
I really suggest you use CountDownTimer - it will be clean code and less boilerplate threading, check example at the link.
You can, however, make your code work by doing this changes :
make Timer extends Thread instead of implementing Runnable.
change start to :
public void start(){
running = true;
super.start(); // <- note super here
}
Optionally add Override notation to start/stop methods, or rename your stop -> stopTimer
I want to create a CountDownTimer passing its remaining time through all activities and show it in TextViews. I tried using intent.putExtra but when i start the new Activity the Timer restarts.
This is what I need:
-ActivityA starts with a 60 seconds timer, so its TextView shows 59...58...57...etc...
-ActivityB starts after 6 seconds so its TextView shows 54...53...52...etc...
The Countdown simply have to go on from first to last activity.
Hope I was clear enough.
Thank you for solutions and sorry for my Ital-English.
use a static variable (maybe create a new class for "better" code).
public static int time;
Or you can declare it in your ActivityA, count the variable down and use it in ActivityB
textView.setText("" + ActivityA.time);
EDIT:
public class MyTimer {
private static int time = 60;
public MyTimer() {
if(time >= 60) {
countDown(); //let countDown only run once
}
}
private void countDown() {
//insert a thread here, which counts your time down
}
public int getTime() {
return this.time;
}
}
And then, in your acitivities:
MyTimer mTimer = new MyTimer();
textview.setText(mTimer.getTime() + "");
For my Android application there is a timer that measures how much time has passed. Ever 100 milliseconds I update my TextView with some text like "Score: 10 Time: 100.10 seconds". But, I find the TextView only updates the first few times. The application is still very responsive, but the label will not update. I tried to call .invalidate(), but it still does not work. I don't know if there is some way to fix this, or a better widget to use.
Here is a example of my code:
float seconds;
java.util.Timer gametimer;
void updatecount() { TextView t = (TextView)findViewById(R.id.topscore);
t.setText("Score: 10 - Time: "+seconds+" seconds");
t.postInvalidate();
}
public void onCreate(Bundle sis) {
... Load the UI, etc...
gametimer.schedule(new TimerTask() { public void run() {
seconds+=0.1; updatecount();
} }, 100, 100);
}
The general solution is to use android.os.Handler instead which runs in the UI thread. It only does one-shot callbacks, so you have to trigger it again every time your callback is called. But it is easy enough to use. A blog post on this topic was written a couple of years ago:
http://android-developers.blogspot.com/2007/11/stitch-in-time.html
What I think is happening is you're falling off the UI thread. There is a single "looper" thread which handles all screen updates. If you attempt to call "invalidate()" and you're not on this thread nothing will happen.
Try using "postInvalidate()" on your view instead. It'll let you update a view when you're not in the current UI thread.
More info here
Use Below code to set time on TextView
public class MyCountDownTimer extends CountDownTimer {
public MyCountDownTimer(long startTime, long interval) {
super(startTime, interval);
}
#Override
public void onFinish() {
ExamActivity.this.submitresult();
}
#Override
public void onTick(long millisUntilFinished) {
long millis = millisUntilFinished;
int seconds = (int) (millis / 1000) % 60;
int minutes = (int) ((millis / (1000 * 60)) % 60);
int hours = (int) ((millis / (1000 * 60`enter code here` * 60)) % 24);
String ms = String
.format("%02d:%02d:%02d", hours, minutes, seconds);
txtimedisplay.setText(ms);
}
}
There is one more way to change text each second; this is ValueAnimator. Here is my solution:
long startTime = System.currentTimeMillis();
ValueAnimator animator = new ValueAnimator();
animator.setObjectValues(0, 1000);
animator.setDuration(1000);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationStart(Animator animation) {
long currentTime = System.currentTimeMillis();
String text = TimeFormatUtils.formatTime(startTime - currentTime);
yourTextView.setText(text);
}
#Override
public void onAnimationRepeat(Animator animation) {
long currentTime = System.currentTimeMillis();
String text = TimeFormatUtils.formatTime(startTime - currentTime);
yourTextView.setText(text);
}
});
animator.start();