How would i go about efficiently having a timer run in the background when the application is stopped? rite now i have not done anything and the timer will continue to run when the app has been stopped but some times it will stop running without me giving it the command.
This is how i am currently running my timer:
if(t == null){
t = new Timer();
t.schedule(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
if(DHPDPS==0){
money = (DPPS+Reserve);
Reserve = (money);
String end = String.format("%1f", money);
t1.setText("$" + end);
}else if(counter > DHPDPS && DOTPPS != 0 && DHPDPS != 0){
money = (DOTPPS+Reserve);
Reserve = (money);
String end = String.format("%1f", money);
t1.setText("$" + end);
} else{
money = (DPPS+Reserve);
Reserve = (money);
String end = String.format("%1f", money);
t1.setText("$" + end);
}
counter++;
//if(counter == 3000)
// t.cancel();
// Display pay per second
if(counter <= DHPDPS || DHPDPS == 0){
t2.setText("Your pay per second is: $"+result);
}else{
t2.setText("Your pay per second is: $"+result2);
}
}
});
}
}, 20, 20);
It is declared in the onCreate(), thanks!
For tasks running in the background you should be using an IntentService. It will keep running even if your activity is paused or removed by the OS.
If your phones memory starts filling up it will close all the activities that are not actively being used.
For something like a timer it might be better to save the start time into SQLite and when the activity is reloaded reference it as a start point to calculate the duration.
Otherwise, if your intent that the timer keeps ticking turn it into an intent service.
private fun startTimer()
var lastdata = PrefUtils.getpunchtime(this)
var mEndTimediff = System.currentTimeMillis() - lastdata!!
var mTimeLeftInMillis = viewModel.START_TIME_IN_MILLIS.toLong() - mEndTimediff
viewModel.mCountDownTimer = object : CountDownTimer(mTimeLeftInMillis, 1000) {
override fun onTick(millisUntilFinished: Long) {
mTimeLeftInMillis = millisUntilFinished
updateCountDownText(mTimeLeftInMillis)
}
override fun onFinish() {
viewModel.mTimerRunning = false
}
}.start()
}
private fun updateCountDownText(mTimeLeftInMillis: Long) {
val millis: Long = mTimeLeftInMillis
val hms = String.format(
"%02d : %02d: %02d", TimeUnit.MILLISECONDS.toHours(millis),
TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(
TimeUnit.MILLISECONDS.toHours(
millis
)
),
TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(
TimeUnit.MILLISECONDS.toMinutes(
millis
)
)
)
binding.tvTimertime.setText(hms)
}
SharePreference in store Last_time
fun storepunchtime(context: Context, storepunchtime: Long) {
val editor = getSharedPreferences(context).edit()
editor.putLong(PUNCH_TIME, storepunchtime)
editor.apply()
editor.commit()
}
fun getpunchtime(context: Context): Long? {
return getSharedPreferences(context).getLong(PUNCH_TIME, 0L)
}
Related
I new to Android programming and I want to build Time Speaking clock that will speak the current time in every hour.
Please help me with my code, I want it to say the current time in every hour, but It say it in every second, here is my code.
.........................
.........................................................................................................
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tts = new TextToSpeech(this, this);
time_textView = findViewById(R.id.time_textView);
hour_textView = findViewById(R.id.hour_textView);
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
#Override
public void run() {
Calendar calendar = Calendar.getInstance();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("h:mm:ss", Locale.getDefault());
String currentTime = simpleDateFormat.format(calendar.getTime());
time_textView.setText(currentTime);
Hour = calendar.getTime().getHours();
Minute = calendar.getTime().getMinutes();
if (Hour == 1 && Minute == 00){
tts.speak("The time is 1 O'clock", TextToSpeech.QUEUE_FLUSH,null);
}
else if (Hour == 2 && Minute == 00){
tts.speak("The time is 2 O'clock", TextToSpeech.QUEUE_FLUSH,null);
}
else if (Hour == 3 && Minute == 00){
tts.speak("The time is 3 O'clock", TextToSpeech.QUEUE_FLUSH,null);
}
else if (Hour == 4 && Minute == 00){
tts.speak("The time is 4 O'clock", TextToSpeech.QUEUE_FLUSH,null);
}
else if (Hour == 5 && Minute == 00){
tts.speak("The time is 5 O'clock", TextToSpeech.QUEUE_FLUSH,null);
}
if (Hour == 6 && Minute == 00){
tts.speak("The time is 6 O'clock", TextToSpeech.QUEUE_FLUSH,null);
}
handler.postDelayed(this, 1000);
}
};
handler.post(runnable);
}
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
int result = tts.setLanguage(Locale.US);
if (result == TextToSpeech.LANG_MISSING_DATA
|| result == TextToSpeech.LANG_NOT_SUPPORTED) {
Log.e("TTS", "Language not supported");
} else {
}
} else {
Log.e("TTS", "Initialization Failed!");
}
}
#Override
public void onDestroy() {
// Don't forget to shutdown tts!
if (tts != null) {
tts.stop();
tts.shutdown();
}
super.onDestroy();
}
}
I am afraid you created an infinite loop. You created the Runnable and submitted it to the queue handler.post(runnable);. Then inside the run() method you submit it with 1 second delay on with handler.postDelayed(this, 1000);.
This is why it's triggered every second. What time does the time_textView show?
There are better ways how to run scheduled tasks, check on JobScheduler for example
I'm not sure if this is "the right way" to do it, but for the sake of "code sanity" this would be my approach (posting only the modified code):
...
// we move this here, as there's no need to initialize it every time
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("h:mm:ss", Locale.getDefault());
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
# Override
public void run() {
Calendar calendar = Calendar.getInstance();
// we save our "now" as a reference so it does not "drift"/"shift" while the code is running
Date time = calendar.getTime();
String currentTime = simpleDateFormat.format(time);
time_textView.setText(currentTime);
// use lowercase for the first letter of variable names otherwise it gets confusing ...
// for ex. my variable "time" of type Date, if it was named "Time" ...
// when I would write "Time.getHours()" to get the hours ... One might think that there's a
// Class named "Time" ('cause classes usually start with capital letters) and this class has
// some static method "getHours", so who reads the code is forced to check to see that it was a variable
hour = time.getHours();
minute = time.getMinutes();
seconds = time.getSeconds();
if (minute == 0 && seconds == 0) {
// as said in some comment before, you should only check the minutes and seconds
// the message string could be a constant and insert the hour value using String.format()
// for optimized performance, but my Java skills are too rusty for that right now
tts.speak("The time is " + hour + " O'clock", TextToSpeech.QUEUE_FLUSH, null);
}
handler.postDelayed(this, 1000);
// actually here instead of delaying for 1 second ... you could calculate the "remaing time", how many seconds are
// missing until the next XX:00:00, and delay for that much
// for extra "precision", just in case, ... delay only for something like "remaingTime - 10" (or something) and
// if the "remaingTime < 10" delay only for 1 second, this way you can be more sure you'll not be missing the
// XX:00:00 ... but do this only if you notice "imprecisions" while using postDelayed with long intervals
// and you care about them
}
};
handler.post(runnable);
...
I am struggling with wierd issue, I've made countdown timer with round progressbar. Sometimes as the time runs out, there is few pixels of progressbar left (orange between x and t), even though it reaches onFinish function. It's not a problem no more as I set countDownInterval to 10, but then showProgress function doesn't quite work, it enters else statement, but doesn't actually set progressbar to 0.
private void startCountingTime() {
if (!counting) {
timeLeftInMillis = maxTime * 1000;
endTime = System.currentTimeMillis() + timeLeftInMillis;
}
if (maxTime != 0) {
countDownTimer = new CountDownTimer(timeLeftInMillis, 100) {
#Override
public void onTick(long l) {
String text = String.format(Locale.getDefault(), "%02d:%02d",
TimeUnit.MILLISECONDS.toMinutes(l) % 60,
TimeUnit.MILLISECONDS.toSeconds(l) % 60);
timeLeftInMillis = l;
showProgress(l, maxTime);
counting = true;
question.setText(exposePasswd ? text : currentQuestion);//displays the timer or question
}
#Override
public void onFinish() {
step = 4;
counting = false;
progressBar.setProgress(0);
question.setText("Out of time! doubletap for next question");
}
}.start();
} else {
question.setText("tap to reveal, doubletap for next");
exposePasswd = false;
}
}
private void showProgress(long l, int maxTime) {
maxTime = maxTime * 1000;
int prog = (int) ((l * 100) / maxTime);
if (exposePasswd) {
// progressBar.setVisibility(View.VISIBLE);
if (progressBar.getProgress() == 0) {
progressBar.setProgress(prog);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
progressBar.setProgress(prog, true);
} else {
progressBar.setProgress(prog);
}
} else {
progressBar.setProgress(0);
Log.wtf("idk","setted");
}
}
Any ideas how to fix it?
Im not sure, why this is happening, but you could probably easily bypass this issue by adding:
progressbar.setVisibility(Visibility.GONE);
in the else statement and
progressbar.setVisibility(Visibility.VISIBLE);
when the timer starts.
I want the code to trigger the JOptionPane.
Here is the code for the working clock:
new Thread() {
public void run() {
while (true) {
GregorianCalendar cal = new GregorianCalendar();
int hour = cal.get(GregorianCalendar.HOUR);
int min = cal.get(GregorianCalendar.MINUTE);
int sec = cal.get(GregorianCalendar.SECOND);
int AM_PM = cal.get(GregorianCalendar.AM_PM);
String day_night;
if (AM_PM == 1) {
day_night = "PM";
} else {
day_night = "AM";
}
String time = hour + ":" + min + ":" + sec + " " + day_night;
lblClock.setText(time);
}
}
}.start();
Here is code I wrote to trigger alarm, but no 'play sound' is coded yet, because I can't even get the JOptionPane to appear. Why? I want to get the values from spinners, than compare to real time until they meet and than trigger alarm and exit thread. How to fix it?
btnAlarm.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
new Thread() {
public void run() {
txtAlarmSet.setVisible(true);
boolean flag = false;
GregorianCalendar g = new GregorianCalendar();
int hour = Integer.parseInt(spinnerHour.getModel().getValue().toString());
int minute = Integer.parseInt(spinnerMinute.getModel().getValue().toString());
int second = Integer.parseInt(spinnerSecond.getModel().getValue().toString());
int AMorPM;
if (rdbtnAm.isSelected()) {
AMorPM = 0;
} else
AMorPM = 1;
while (flag == false) {
int realHour = g.get(GregorianCalendar.HOUR);
int realMinute = g.get(GregorianCalendar.MINUTE);
int realSecond = g.get(GregorianCalendar.SECOND);
int realAM_PM = g.get(GregorianCalendar.AM_PM);
if (hour == realHour && minute == realMinute && second == realSecond
&& AMorPM == realAM_PM) {
JOptionPane.showMessageDialog(null, "WORKS!"); // <- this doesn't appear!
flag = true;
}
}
txtAlarmSet.setVisible(false);
}
}.start();
}
});
In your checking loop, you need to reacquire the Calendar on every pass, otherwise, you'll just end up re-checking the same time value over and over. Move the line
GregorianCalendar g = new GregorianCalendar();
inside the loop.
Note: This is not a particularly good approach to this problem. What you're doing is called "busy waiting" and it's generally not good for much other than making the CPU get hot. A better approach would be to use an event-driven approach, but that's beyond the scope of this answer.
One major problem I notice is missing } after AMorPM = 1; making it impossible to work for AM.
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>);
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...)