I have made a Countdown to a future date (with remaining days, hours, minutes, seconds) using CountDownTimer and lots of code from this answer: https://stackoverflow.com/a/32773716/3984944
Now I want to do exactly the same but counting up from a past date. My TextView should refresh every second and show the elapsed time.
What I tried:
I tried manipulating the CountDownTimer so that it works in reverse order. Changing the interval to -1000 or adding 2000 milliseconds to the Countdown every second. Both didn't work.
Then I figured I should use the Chronometer class. The standard Chronometer only displays hours, minutes and seconds as far as I'm concerned. So no days. I then wrote the following code in the style of the CountDownTimer answer I found before that updates a TextView with the desired data:
final Chronometer ch = (Chronometer) findViewById(R.id.ch_chronometer);
final TextView tv = (TextView) findViewById(R.id.tv_show_stopwatch);
ch.setBase(endMillis); //endMillis is the date in Milliseconds
chCountdownSince.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
public void onChronometerTick(Chronometer cArg) {
long t = System.currentTimeMillis() - chCountdownSince.getBase();
long days = TimeUnit.MILLISECONDS.toDays(t);
t -= TimeUnit.DAYS.toMillis(days);
long hours = TimeUnit.MILLISECONDS.toHours(t);
t -= TimeUnit.HOURS.toMillis(hours);
long minutes = TimeUnit.MILLISECONDS.toMinutes(t);
t -= TimeUnit.MINUTES.toMillis(minutes);
long seconds = TimeUnit.MILLISECONDS.toSeconds(t);
String stopwatchDisplay = "Days: %d Hours: %d Minutes: %d Seconds: %d";
stopwatchDisplay = String.format(stopwatchDisplay, days, hours, minutes, seconds);
tv.setText(stopwatchDisplay);
}
});
I feel like this snipped makes absolute sense but upon execution it doesn't change my TextView at all. I feel like this is just not how Chronometer works but I don't know what I'm doing wrong.
Edit :
I think you forgot to start Chronometer completely.
Given that
The calls to onTick(long) are synchronized to this object so that one
call to onTick(long) won't ever occur before the previous callback is
complete.
Its unlikely that ticks are done on UI thread, but this is exactly where you need to set your text, try changing
tv.setText(stopwatchDisplay);
to
tv.post(new Runnable() {
public void run() {
tv.setText(stopwatchDisplay);
});
please use handler..
public void countDownStart() {
handler = new Handler();
runnable = new Runnable(){
#Override
public void run(){
handler.postDelayed(this,1000);
try {
FestCountdownTimer timer = new FestCountdownTimer(00, 00, 9, 3, 01, 2017);
new CountDownTimer(timer.getIntervalMillis(), 1000) {
#Override
public void onTick(long millisUntilFinished){
int days = (int) ((millisUntilFinished / 1000) / 86400);
int hours = (int) (((millisUntilFinished / 1000)
- (days * 86400)) / 3600);
int minutes = (int) (((millisUntilFinished / 1000)
- (days * 86400) - (hours * 3600)) / 60);
int seconds = (int) ((millisUntilFinished / 1000) % 60);
String countdown = String.format("%02dd %02dh %02dm %02ds", days,
hours, minutes, seconds);
txtTimerDay.setText("" + String.format("%02d", days));
txtTimerHour.setText("" + String.format("%02d", hours));
txtTimerMinute.setText(""
+ String.format("%02d", minutes));
txtTimerSecond.setText(""
+ String.format("%02d", seconds));
}
#Override
public void onFinish() {
textViewGone();
MainActivity.aSwitch.setChecked(false);
creditText.setText("Toggle On To Start");
}
}.start();
} catch (Exception e) {
e.printStackTrace(); }
}
};
handler.postDelayed(runnable, 1 * 1000);
}
Remember, 9 is Hours,3 is date,1 is Febraury Month..Month starts from 0th Index
FestCountdownTimer class
public class FestCountdownTimer {
private long intervalMillis;
public FestCountdownTimer(int second, int minute, int hour, int monthDay, int month, int year) {
Time futureTime = new Time();
// Set date to future time
futureTime.set(second, minute, hour, monthDay, month, year);
futureTime.normalize(true);
long futureMillis = futureTime.toMillis(true);
Time timeNow = new Time();
// Set date to current time
timeNow.setToNow();
timeNow.normalize(true);
long nowMillis = timeNow.toMillis(true);
// Subtract current milliseconds time from future milliseconds time to retrieve interval
intervalMillis = futureMillis - nowMillis;
}
public long getIntervalMillis() {
return intervalMillis;
}
}
Hope it helps.. :)
Related
My current task is to create Linked List with Clock objects in it. Furthermore, I have to create a method that will add one minute to each clock inside the Linked List.
There is one thing I thought about and I would like to add to this task as my idea - i called it validator. I want it to validate if there is 60 minutes on the clock, so it will change hour and minutes after adding this one minute.
I tried to create diffrent methods and if variations. I ran out of any ideas.
import java.util.*;
import java.io.*;
import java.lang.*;
import java.time.*;
class Clock {
private int hours;
private int minutes;
public Clock (int hours, int minutes){
this.hours = hours;
this.minutes = minutes;
}
public int getHours() {
return hours;
}
public int getMinutes(){
return minutes;
}
public int addOneMinute(){
return minutes = minutes + 1;
}
public int hoursSwapper(){
return (hours = hours + 1);
}
public int minutesSwapper() {
return (minutes = 00);
}
public String toString() {
return "Clock time is " + hours + "." + minutes;
}
}
class Program{
public static void main (String [] args) throws java.lang.Exception{
Random hoursGenerator = new Random();
Random minutesGenerator = new Random();
Clock clock0 = new Clock(hoursGenerator.nextInt(24), minutesGenerator.nextInt(60));
Clock clock1 = new Clock(hoursGenerator.nextInt(24), minutesGenerator.nextInt(60));
Clock clock2 = new Clock(hoursGenerator.nextInt(24), minutesGenerator.nextInt(60));
Clock clock3 = new Clock(hoursGenerator.nextInt(24), minutesGenerator.nextInt(60));
Clock clock4 = new Clock(hoursGenerator.nextInt(24), minutesGenerator.nextInt(60));
LinkedList<Clock> clockCollection = new LinkedList<Clock>();
clockCollection.add(clock0);
clockCollection.add(clock1);
clockCollection.add(clock2);
clockCollection.add(clock3);
clockCollection.add(clock4);
for (int j = 0; j < clockCollection.size(); j ++){
System.out.println(clockCollection.get(j));
clockCollection.get(j).addOneMinute();
System.out.println(clockCollection.get(j));
if (clockCollection.get(j) == 60) {
}
System.out.println(clockCollection.get(j));
System.out.println("---");
}
}
}
I would like to make the code upgrade na system.out hour IF there would be 60 minutes (raise hour and reset minutes to 00).
You can create a private method checkMinutes() that you will call inside of the Clock class every time you add minutes in one of the class's methods (for example if you made an addFiveMinutes().
public int addOneMinute(){
minutes++;
checkMinutes();
}
private void checkMinutes(){
if (minutes >= 60)
{
hours++;
minutes = minutes - 60;
}
}
//Having the private check method makes it simple to expand functionality in the future like so
public int addFiveMinutes(){
minutes = minutes + 5;
checkMinutes();
}
This will ensure the time rollovers to the correct amount as well, for example if minutes is 65 then the new minutes will be 5.
Now every time you call addOneMinute() in your main method, you don't have to check for anything! It will all be done automatically every single time.
I have used ListView to create my order cards. In which I had run a continuous timer for each card using handler to check how much time has been spent. I have used code in adapter. But my problem is when there is more then one order then the timer time overlaps on each card. For example, if I have 3 cards then ist card will show time of 1,2,3 one by one at interval of one second and 2nd will show time of 2 n 3 and for 3rd timer is stop. Another problem is timer stops after a particular amount if time. Help me regarding this.
This is my piece of code of custom adapter:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View vv = LayoutInflater.from(mContext).inflate(R.layout.adapter_listview_newpage_card,null,false);
menuModels = new ArrayList<>();
// menuModels.clear();
order_time = (TextView) vv.findViewById(R.id.order_time);
// This is my handler of timer:
final Handler myHandler = new Handler(); //declare this line in class
myHandler.postDelayed( // called this line from createlaytout function first time
new Runnable() {
public void run() {
TimeZone tz = TimeZone.getTimeZone("Asia/Kolkata");
// Log.e("TAG", "timezone "+tz );
Calendar cd = Calendar.getInstance(tz);
int min0 = cd.get(Calendar.MINUTE);
int sec0 = cd.get(Calendar.SECOND);
int hour0 = cd.get(Calendar.HOUR_OF_DAY);
// int ampm0 = cd.get(Calendar.AM_PM);
int total = (hour0 * 60 * 60) + (min0 * 60) + sec0;
int finalTime = total - Integer.parseInt(data.getTimer_time());
int hoursnew = 0;
int seconds = finalTime;
int minutes = seconds / 60;
seconds = seconds % 60;
if (minutes > 59) {
hoursnew = minutes / 60;
minutes = minutes % 60;
}
// Log.e("TAG", "timer" + minutes + "-" + seconds + "$$" + data.getOrder_id());
order_time.setText(" " + data.getOrder_id() + "&" + String.format("%02d", hoursnew) + ":" + String.format("%02d", minutes) + ":" + String.format("%02d", seconds));
myHandler.postDelayed(this, 1000);
}
}, 0);
// Here order_time is textview where I add time.
}
Updated code
Hi, I was able to run timer in my code but the problem is that now i am having null pointer exception at adapter.setnotifydata change.
My code for adapter where I set time on textview
public class customadapetr_new extends BaseAdapter {
public customadapetr_new(ArrayList<DataModel> dataModels, Context context, NewPageActivity objNewPageActivity) {
this.dataSet=dataModels;
this.mContext=context;
this.objNewPageActivity = objNewPageActivity;
}
private void setTime(final int order_time, final TextView tv) {
TimeZone tz = TimeZone.getTimeZone("Asia/Kolkata");
// Log.e("TAG", "timezone "+tz );
Calendar cd = Calendar.getInstance(tz);
int min0 = cd.get(Calendar.MINUTE);
int sec0 = cd.get(Calendar.SECOND);
int hour0 = cd.get(Calendar.HOUR_OF_DAY);
// int ampm0 = cd.get(Calendar.AM_PM);
int total = (hour0 * 60 * 60) + (min0 * 60) + sec0;
int finalTime = total - order_time;
int hoursnew = 0;
int seconds = finalTime;
int minutes = seconds / 60;
seconds = seconds % 60;
if (minutes > 59) {
hoursnew = minutes / 60;
minutes = minutes % 60;
}
tv.setText(" " + String.format("%02d", hoursnew) + ":" + String.format("%02d", minutes));
}
}
And my code from where I have called handler
public class NewPageActivity extends Fragment{
private final Runnable timerRunnable = new Runnable() {
#Override
public void run() {
Log.e("TAG", "run:timer run run " );
adapter.notifyDataSetChanged();
timerHandler.postDelayed(this, 60000); //run every minute
}
};
}
I am getting error at adapter.notifyDataSetChanged() and attaching scrrenshot link of error i.e http://prntscr.com/dmxjr9
I want to calculate the total running time of my program from start to end and refresh running time in JFrame, but when I run my program I get excess 70 years, 1 day and 2 hours. Why ? What wrong ?
private void setMachineTime(){
Timer timer = new Timer();
long startTime = new Date().getTime();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
long endTime = new Date().getTime();
long diffTime = endTime - startTime ;
String time = new SimpleDateFormat("yy:mm:dd:HH:mm:ss").format(diffTime);
System.out.println(time);
}
}, 0, 1000);
}
actual result
UPD:
I rewrote code with my own format time method. Now I got what I want. Thanks to all of you.
private void setMachineTime(){
Timer timer = new Timer();
long startTime = new Date().getTime();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
long endTime = new Date().getTime();
long diffTime = endTime - startTime;
String diffSeconds = formatTime(diffTime / 1000 % 60);
String diffMinutes = formatTime(diffTime / (60 * 1000) % 60);
String diffHours = formatTime(diffTime / (60 * 60 * 1000) % 24);
System.out.println(diffHours + ":" + diffMinutes + ":" + diffSeconds);
}
}, 0, 1000);
}
private String formatTime(long diff){
long t;
t = diff;
if(t < 10){
return String.valueOf("0"+t);
} else {
return String.valueOf(t);
}
}
You are formatting the time difference as yy:mm:dd:HH:mm:ss. Just printing out diffTime would give you the milliseconds, divide by 1000 if you need seconds.
EDIT: I think i see what you are trying to do, but you are dealing with a time interval, which cannot be formatted as a date. You'll need to roll your own formatting for displaying the time as seconds, minutes, hours etc. or use an external library.
getTime return number of milliseconds from 1.1.1970...and same is for SimpleDateFormat converting number to date (and then formating it). It means when your diffTime = 0, SimpleDateFormat will try to format Date 1.1.1970 0:00:00 and with your formating string it will be 70:01:01:00:00:00. Try to use http://joda-time.sourceforge.net/api-release/org/joda/time/Interval.html instead.
And by the way, your formating string is wrong anyway...you use mm where I supouse you wanted month...but mm are minutes.
Hi I am new to Android
I would like keep the following code seperatly from my MainActivity file. However, when I try to findViewById() inside the seperate class, I get the error
"cannot be resolved"
Now I know I cannot extend the MainActivity class as it will lead to stack overflow, but could someone tell me how to go about access a textview from this seperate file?
public class Counter {
private TextView tempTextView;
//Temporary TextView
private Button tempBtn;
public Handler mHandler = new Handler();
public long startTime;
public long elapsedTime;
public final int REFRESH_RATE = 100;
public String hours,minutes,seconds,milliseconds;
public long secs,mins,hrs,msecs;
public boolean stopped = false;
public Runnable startTimer = new Runnable() {
public void run() {
elapsedTime = System.currentTimeMillis() - startTime;
updateTimer(elapsedTime);
mHandler.postDelayed(this,REFRESH_RATE);
}
};
private void updateTimer (float time) {
secs = (long) (time / 1000);
mins = (long) ((time / 1000) / 60);
hrs = (long) (((time / 1000) / 60) / 60); /* Convert the seconds to String * and format to ensure it has * a leading zero when required */
secs = secs % 60;
seconds = String.valueOf(secs);
if (secs == 0) {
seconds = "00";
}
if (secs < 10 && secs > 0) {
seconds = "0" + seconds;
} /* Convert the minutes to String and format the String */
mins = mins % 60;
minutes = String.valueOf(mins);
if (mins == 0) {
minutes = "00";
}
if (
mins < 10 && mins > 0
) {
minutes = "0" + minutes;
} /* Convert the hours to String and format the String */
hours = String.valueOf(hrs);
if (hrs == 0) {
hours = "00";
}
if (hrs < 10 && hrs > 0) {
hours = "0" + hours;
}
/* Although we are not using milliseconds on the timer in this example * I included the code in the event that you wanted to include it on your own */
milliseconds = String.valueOf((long) time);
if (milliseconds.length() == 2) {
milliseconds = "0" + milliseconds;
}
if (milliseconds.length() <= 1) {
milliseconds = "00";
}
milliseconds = milliseconds.substring(milliseconds.length() - 3, milliseconds.length() - 2);
/* Setting the timer text to the elapsed time */
// ((TextView) findViewById(R.id.elapsed_value)).setText(hours + ":" + minutes + ":" + seconds);
// ((TextView)findViewById(R.id.timerMs)).setText("." + milliseconds); }
}
}
You need to inflate a view and call the mehod findViewById() from this view. To inflate a view, you need a Context (you can set it in a custom constructor)
View view;
LayoutInflater inflater = (LayoutInflater) yourContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.mylayout, null);
tempTextView = (TextView) view.findViewById(R.id.tv);
Because, findViewById() is method from Activity class. That's why you can not use it in any other Java class.
And second you can not update Android application UI from any worker thread.
So better to use AsyncTask and pass the TextView's references which you want to update after certain task.
Or use runOnMainUiThread() if you are going to update Application UI from other worker thread. But Be sure runOnUiThread() only works with Activity Context.
You could create a constructor for Counter that takes a reference to your TextView from your Activity.
public Counter(TextView tv) {
tempTextView = tv;
}
Then call findViewById() on your MainActivity as pass in the result when you're instantiating Counter.
You're already on the UI thread, no need for AsyncTask here...
You can have a constructor where you set an activity variable.
public Counter (MainActivity activity) {
mActivity = activity;
}
Then, you can call
mActivity.findViewById(...);
which will find the view in your MainActivity layout that you set in
setContentView(<layout>);
Trying to make a small countdown timer in my app but it's not working.
Idea is to count down to a specific time. First by days and when it gets closer, by hours.
The following method is inside my Fragmentclass.java (so it's a fragment)
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onViewCreated(view, savedInstanceState);
Calendar cal = Calendar.getInstance();
cal.set(2012, 8, 29, 10, 0);
long endTime = cal.getTimeInMillis();
long currentTime = System.currentTimeMillis();
long remaining = currentTime - endTime;
long seconds = remaining / 1000 % 60;
new CountDownTimer(seconds, 1000) {
TextView tv = (TextView)getActivity().findViewById(R.id.introTimeLeft);
public void onTick(long millisUntilFinished) {
Calendar cal = Calendar.getInstance();
cal.set(2012, 8, 29, 10, 0);
long endTime = cal.getTimeInMillis();
long currentTime = System.currentTimeMillis();
long remaining = currentTime - endTime;
long hours = remaining / 3600000;
long mins = remaining / 60000 % 60;
long seconds = remaining / 1000 % 60;
long days = hours / 24;
String remainingText = String.valueOf(days) + " days";
Log.i("countdown",String.valueOf(days));
tv.setText("Days left: " + days);
}
public void onFinish() {
Log.i("countdown","CD Finished");
tv.setText("CD Finished!");
}
}.start();
}
Note that the textbox value is just for testing right now, but i can't seem to get it to display the countdown.
Also is this the best approach?
Here are the values of the variables if I run your code:
endTime = 1348902045437
currentTime = 1340645325437
remaining = -8256720000
seconds = 0
as you see seconds == 0, and this is the reason.
Also note that the first argument in the CountDownTimer(long millisInFuture, long countDownInterval) constructor is
The number of millis in the future from the call to start() until the
countdown is done and onFinish() is called.
So a fixed code would be:
Calendar cal = Calendar.getInstance();
cal.set(2012, 8, 29, 10, 0);
long endTime = cal.getTimeInMillis();
long currentTime = System.currentTimeMillis();
long remaining = endTime - currentTime;
new CountDownTimer(remaining, 1000) {
...
UPDATE:
It is odd it does not update the text view. The only idea I can propose is to run update calls on the main UI thread. It should be something like this:
public void onTick(long millisUntilFinished) {
final String days = .. // some code to generate days
getActivity().runOnUiThread(new Runnable() {
public void run() {
tv.setText("Days left: " + days);
}
});
}
public void onFinish() {
Log.i("countdown","CD Finished");
getActivity().runOnUiThread(new Runnable() {
public void run() {
tv.setText("CD Finished!");
}
});
}
If this doesn't help - then I'm out of ideas.