Trying to make a timer loop - java

I'm trying to make a count down time loop.
I want it to make it loop till "int x" reaches 100.
I've tried adding a do/while and a for loop but I think I'm doing it wrong.
Any suggestions?
Thanks for looking. :-) `
public class MainActivity extends Activity{
Button buttonStartTime;
// clicking this button will start time count down
TextView textViewShowTime; // will show the time
TextView shots;
CountDownTimer countDownTimer; // built in android class CountDownTimer
long totalTimeCountInMilliseconds; // total count down time in milliseconds
long timeBlinkInMilliseconds; // start time of start blinking
boolean blink; // controls the blinking .. on and off
static int x = 3;
int whole = 100;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getReferenceOfViews (); // get all views
setActionListeners (); // set action listerns
totalTimeCountInMilliseconds = 60 * 1000; // time count for 3 minutes = 180 seconds
timeBlinkInMilliseconds = 10 * 1000; // blink starts at 1 minutes = 60 seconds
}
private void setActionListeners() {
buttonStartTime.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
textViewShowTime.setTextAppearance(getApplicationContext(), R.style.normalText);
countDownTimer = new CountDownTimer(totalTimeCountInMilliseconds, 500) {
// 500 means, onTick function will be called at every 500 milliseconds
#Override
public void onTick(long leftTimeInMilliseconds) {
long seconds = leftTimeInMilliseconds / 1000;
if ( leftTimeInMilliseconds < timeBlinkInMilliseconds ) {
textViewShowTime.setTextAppearance(getApplicationContext(), R.style.blinkText);
// change the style of the textview .. giving a red alert style
if ( blink ) {
textViewShowTime.setVisibility(View.VISIBLE);
// if blink is true, textview will be visible
} else {
textViewShowTime.setVisibility(View.INVISIBLE);
}
blink = !blink; // toggle the value of blink
}
textViewShowTime.setText(String.format("%02d", seconds / 60) + ":" + String.format("%02d", seconds % 60));
// format the textview to show the easily readable format
}
#Override
public void onFinish() {
x++;
// this function will be called when the timecount is finished
textViewShowTime.setText("SHOT!!!");
textViewShowTime.setVisibility(View.VISIBLE);
}
}
.start();
}
});
}
private void getReferenceOfViews() {
buttonStartTime = (Button) findViewById(R.id.btnStartTime);
textViewShowTime = (TextView) findViewById(R.id.tvTimeCount);
}
}`

totalTimeCountInMilliseconds =1000 * 1000; // time count for 3 minutes = 180 seconds
timeBlinkInMilliseconds = 10 * 1000; // blink starts at 1 minutes = 60 seconds
new CountDownTimer(totalTimeCountInMilliseconds , timeBlinkInMilliseconds )
above will call onTick 100 times

Related

Reset Horizontal Progress Bar to 0 every night 12oClock?

I want to reset my horizontal progressbar to 0 every night at 12.
Here is my code.
public class MainActivity extends AppCompatActivity {
private TextView textView;
Button btn;
private int Counter counter;
Progressbar progressbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.txtvw);
progressbar = findViewById(R.id.progressbar_Horizontal);
progressbar.setMax(10);
btn = findViewById(R.id.btn_clc);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
counter++;
textView.setText(String.valueOf(counter));
progressbar.setProgress(counter)
}
});
Calendar calendar = Calendar.getInstance();
int hour = 23;
int minute = 59;
int second = 59;
int curHour = calendar.get(Calendar.HOUR_OF_DAY);
int curMinute = calendar.get(Calendar.MINUTE);
int curSecond = calendar.get(Calendar.SECOND);
if (hour==curHour && minute==curMinute && second==curSecond) {
progressbar.setProgress(0);
}
}
}
In this method at the output there is no response to the progressbar! Is this the right way to do or is there any other way?
You don't get any response because you're defining the action in OnCreate method. This method is executed one time when you enter the Activity. So this action defined only works if you launch your Ativity exactly at 23:59:59.
If you want to do it right, implement AlarmManager. You can set the time you want (23:59:59) and do whatever you want (reset the bar) at that moment. You can implement it also when the app is closed, in the background or when the screen is off.
Take a look at this: Alarm Manager Example

Keep the chronometer always running without a service

I'm using a chronometer and it needs to run persistently until stopped.
The code I'm using below works well and the chronometer keeps running, however, when the device restarts, I get negative values.
SharedPreferences sharedPreferences = getSharedPreferences("chronometer", MODE_PRIVATE);
//Check if the start time was saved before
long elapsedTime = sharedPreferences.getLong("elapsed_time", 0);
if (elapsedTime != 0) {
//It means the chronometer was running before, so we set the time from SharedPreferences
chronometer.setBase(elapsedTime);
chronometer.start();
}
//Code below starts the chronometer, after the user manually starts it
Button startButton = findViewById(R.id.btnStart);
startButton.setOnClickListener(v -> {
//Save the starting time
long elapsedRealtime = SystemClock.elapsedRealtime();
sharedPreferences.edit().putLong("elapsed_time", elapsedRealtime).apply();
chronometer.setBase(SystemClock.elapsedRealtime());
chronometer.start();
});
Why does the chronometer display negative values after a re-boot & how can I sort it out?
From Android Documentation
Chronometer
Class that implements a simple timer.
You can give it a start time in the SystemClock#elapsedRealtime
timebase, and it counts up from that.
The timebase of this class is based on SystemClock.elapsedRealtime().
elapsedRealtime
public static long elapsedRealtime()
Returns milliseconds since boot, including time spent in sleep.
Back to your questions:
Why does the chronometer display negative values after a re-boot?
Here is an example to demonstrate this scenario.
Assume your phone is running about 10 minutes from last booting, at that time users open the activity, the elapsedRealtime() method will return 600000L (10 mins = 10 * 60 * 1000 milliseconds). When users click on the Start button, you set that time for Chronometer as basetime and save 600000L to SharePreferences using elapsed_time key.
Right now: elapsedRealTime() = 10 mins | Chronometer = 00:00
After 1 min: elapsedRealtime() = 11 mins | Chronometer = 01:00
After 10 minutes: elapsedRealTime() = 20 mins | Chronometer = 10:00
At this time users press the BACK key to exit the app and restart the phone.
The phone is kinda slow, so it took 2 mins from booting. Users open the activity again. At this time.
elapsedRealtime() returns 120000L (2 mins = 2 * 60 * 1000 milliseconds)
The value you saved in the SharePreferences (elapsed_time) is 600000L
Because the value you set as basetime of Chronometer is ahead of the elapsedRealtime(), so the Chronometer will display -08:00 and start counting up from that value.
How can I sort it out?
You can save the elapsed time of Chronometer and the elapsed time from the last time users leave the activity until the next time users open the activity. Then using these two values to calculate the basetime for Chronometer.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<Chronometer
android:id="#+id/chronometer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:textColor="#F00"
android:textSize="24sp" />
<Button
android:id="#+id/btnStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start" />
</LinearLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final String KEY_CHRONOMETER_ELAPSED_TIME = "chronometerElapsedTime";
private static final String KEY_CHRONOMETER_STOPPED_TIME = "chronometerStoppedTime";
private Chronometer chronometer;
private SharedPreferences prefs;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
chronometer = findViewById(R.id.chronometer);
// Code below starts the chronometer, after the user manually starts it
Button startButton = findViewById(R.id.btnStart);
startButton.setOnClickListener(v -> {
setElapsedTime(-1);
setStoppedTime(-1);
chronometer.setBase(SystemClock.elapsedRealtime());
chronometer.start();
});
}
#Override
protected void onStart() {
super.onStart();
prefs = getSharedPreferences("chronometer", MODE_PRIVATE);
if (prefs.contains(KEY_CHRONOMETER_ELAPSED_TIME)
&& prefs.contains(KEY_CHRONOMETER_STOPPED_TIME)) {
long chronometerElapsedTime = prefs.getLong(KEY_CHRONOMETER_ELAPSED_TIME, -1);
long chronometerStoppedTime = prefs.getLong(KEY_CHRONOMETER_STOPPED_TIME, -1);
if (chronometerElapsedTime != -1 && chronometerStoppedTime != -1) {
long now = System.currentTimeMillis();
long elapsedTimeFromLastStop = now - chronometerStoppedTime; // Including restart time
long elapsedRealTime = SystemClock.elapsedRealtime();
long base = elapsedRealTime - (chronometerElapsedTime + elapsedTimeFromLastStop);
chronometer.setBase(base);
chronometer.start();
}
}
}
#Override
protected void onStop() {
setElapsedTime(getChronometerTimeMs());
setStoppedTime(System.currentTimeMillis());
super.onStop();
}
private void setElapsedTime(long elapsedTimeMs) {
prefs.edit().putLong(KEY_CHRONOMETER_ELAPSED_TIME, elapsedTimeMs).apply();
}
private void setStoppedTime(long stoppedTimeMs) {
prefs.edit().putLong(KEY_CHRONOMETER_STOPPED_TIME, stoppedTimeMs).apply();
}
private long getChronometerTimeMs() {
long chronometerTimeMs = 0;
// Regex for HH:MM:SS or MM:SS
String regex = "([0-1]?\\d|2[0-3])(?::([0-5]?\\d))?(?::([0-5]?\\d))?";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(chronometer.getText());
if (matcher.find()) {
boolean isHHMMSSFormat = matcher.groupCount() == 4;
if (isHHMMSSFormat) {
int hour = Integer.valueOf(matcher.group(1));
int minute = Integer.valueOf(matcher.group(2));
int second = Integer.valueOf(matcher.group(3));
chronometerTimeMs = (hour * DateUtils.HOUR_IN_MILLIS)
+ (minute * DateUtils.MINUTE_IN_MILLIS)
+ (second * DateUtils.SECOND_IN_MILLIS);
} else {
int minute = Integer.valueOf(matcher.group(1));
int second = Integer.valueOf(matcher.group(2));
chronometerTimeMs = (minute * DateUtils.MINUTE_IN_MILLIS)
+ (second * DateUtils.SECOND_IN_MILLIS);
}
}
return chronometerTimeMs;
}
}
You should save the elapsedMillis into shared preferences and when the device restarts and you set the base of the chronometer you should do the followgin
chronometer.setBase(SystemClock.elapsedRealtime() - millis)
where millis is the value you have in the preferences

The time difference in Java

I'm looking for some solution which will be faster than mine. I get a time difference between current time and my saved, next step is to put the time in TextView. This solution works but it makes my app very slowly. Does anyone know faster solution?
Thread counter = new Thread(){
public void run()
{
long saved
long difference;
while(true)
{
saved = Long.parseLong(getString(c, "0", "saved"));// sharedPreferences
difference = System.currentTimeMillis() - saved;
seconds = (int) (difference / 1000) % 60;
difference-=seconds;
minutes= (int)((difference/ 60000 ) % 60);
difference=minutes;
hours = (int) ((difference/ 3600000) % 24);
days = (int) ((difference/86400000) % 30);
difference-=days;
months= (int) ((difference/2592000)/1000);
runOnUiThread(new Runnable() {
#Override
public void run() {
myTextView5.setText(Integer.toString(seconds));
myTextView4.setText(Integer.toString(minutes));
myTextView3.setText(Integer.toString(hours));
myTextView2.setText(Integer.toString(days));
myTextView1.setText(Integer.toString(months));
}
});
Your precision is 1s - so you can Thread.sleep (1000) in the while without missing a beat.
I would recommend the use of JodaTime library.
DateTime saved = //getSaved;
DateTime diff = DateTime.now().minus(saved);
//update TextView
txtView.setText(diff.getSecondsOfMinute().toString());
According to my understanding you are using runOnUiThread that created temporary shortlife objects that is the main reason your code is running slow because in each iteration it does it created a new instance of Runnable class and then updates your UI.
Read this topic to get a good understanding of Communication with Ui Thread
http://developer.android.com/training/multiple-threads/communicate-ui.html
You can use Handlers to overcome this issue all you need to do is pass message to handler and it will do the job for you.
This is how you do it.
First of all create a custom handler class
public class CustomMessageHandler extends Handler {
private IUpdateAudioProgressListView iUpdateRef;
public void setOnProgressUpdatedListner(IUpdateAudioProgressListView ref) {
this.iUpdateRef = ref;
}
#Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
YOUR HANDLING CODE HERE ......................
}
}
then in order to send message to UI thread from a custom thread you need to do following things
initialize a class level variable in your thread class like
public class Test {
CustomMessageHandler handler;
public Test() {
handler = new CustomMessageHandler();
Thread counter = new Thread() {
public void run() {
long saved
long difference;
while (true) {
saved = Long.parseLong(getString(c, "0", "saved"));// sharedPreferences
difference = System.currentTimeMillis() - saved;
seconds = (int) (difference / 1000) % 60;
difference -= seconds;
minutes = (int) ((difference / 60000) % 60);
difference = minutes;
hours = (int) ((difference / 3600000) % 24);
days = (int) ((difference / 86400000) % 30);
difference -= days;
months = (int) ((difference / 2592000) / 1000);
Message msg = handler.obtainMessage();
msg.obj = // send all your variables via a class or whatever logic you use
handler.sendMessage(msg);
}
}
};
}
}
If you don't want to use an external library, I would suggest the use of java.util.Calendar (Don't forget to import that!). For your solution, every time your value in SharedPreferences is changed, just run the code below.
Code to calc diff
Calendar c = Calendar.getInstance();
c.setTimeInMillis(difference);
int months = c.get(Calendar.MONTH);
int days = c.get(Calendar.DAY_OF_MONTH);
int hours = c.get(Calendar.HOUR_OF_DAY);
int minutes = c.get(Calendar.MINUTE);
int seconds = c.get(Calendar.SECOND);
myTextView5.setText(Integer.toString(seconds));
myTextView4.setText(Integer.toString(minutes));
myTextView3.setText(Integer.toString(hours));
myTextView2.setText(Integer.toString(days));
myTextView1.setText(Integer.toString(months));
Detect change in preferences
public class MyPreferences extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
// handle the preference change here
}
}

Keep running Multiple countdown timers and multiple stopwatches in background using Android

I am new to Android and Java and I have been trying to solve an issue on timers.Please help
I have an App where the user can create multiple countdown timers and multiple stopwatches.
Example code of countdown timer is given below .(Stop watch is also implemented in a similar fashion using handler). I want the timers and stopwatches to run in the background even when the user leaves the app.And the current state of timers should be shown when the user comes back to the app again,rather than showing the initial state.
The problem is my timers and stopwatches are running when I leave the app,but the results are not published into the UI when the user comes back to the app. A new instance is created and the fresh timers with 00:00:00 are shown again,while the old timers keep running in the background and goes on without being able to stop.Also in the following code I have a listener which publishes the result into the UI in its callback.This interface is implemented in my activity. So can anyone please suggest a solution for this ?
public class CountDownTimerService {
public interface CounterTimeChangeListener {
public void onCounterTimeChange(String time,Boolean counterFinished);
}
CounterTimeChangeListener listener;
MyCountDownTimer myCountDownTimer;
String output;
int length;
long startTime = 0;
long currentTime = 0;
long timeElapsed = 0;
long timeRemaining = 0;
long prevTimeRemaining = 0;
public CountDownTimerService(int countDownFutureTime)
{
myCountDownTimer= new MyCountDownTimer(countDownFutureTime,1000);
length=countDownFutureTime;
}
// code for countdown timer
// this function format the time to hours seconds and minutes format
public String formatTime(long mills)
{
output = "";
long seconds = mills / 1000;
long minutes = seconds / 60;
long hours = minutes / 60;
seconds = seconds % 60;
minutes = minutes % 60;
hours = hours % 60;
String secondsD = String.valueOf(seconds);
String minutesD = String.valueOf(minutes);
String hoursD = String.valueOf(hours);
if (seconds < 10)
secondsD = "0" + seconds;
if (minutes < 10)
minutesD = "0" + minutes;
if (hours < 10)
hoursD = "0" + hours;
output = hoursD +":" +minutesD +":"+ secondsD;
return output;
}
// this function is called on start button click
public void CountDownControl(int state) {
if(state==0)
{
startTime = System.currentTimeMillis();
myCountDownTimer.start();
}
else if(state==1)
{
// when the pause is clicked
myCountDownTimer.cancel();
currentTime = System.currentTimeMillis();
timeElapsed = currentTime - startTime;
if (prevTimeRemaining == 0)
timeRemaining = length - timeElapsed;
else
timeRemaining = prevTimeRemaining - timeElapsed;
prevTimeRemaining = timeRemaining;
myCountDownTimer= new MyCountDownTimer(timeRemaining,1000);
if (listener!=null) {
listener.onCounterTimeChange(formatTime(timeRemaining), false);
}
}
}
// this function is called on reset button click
public void resetInitial()
{
prevTimeRemaining = 0;
myCountDownTimer.cancel();
if (listener!=null) {
listener.onCounterTimeChange(formatTime(length),false);
}
myCountDownTimer= new MyCountDownTimer(length,1000);
}
public class MyCountDownTimer extends CountDownTimer {
public MyCountDownTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
public void onTick (long millisUntilFinished) {
// calls the fragment's callback function passing the time value
Log.e("in counter","1");
if (listener!=null) {
Log.e("in counter","2");
listener.onCounterTimeChange(formatTime(millisUntilFinished), false);
}
}
public void onFinish() {
/*
* write code for an alarm when timer times out
*
* */
prevTimeRemaining = 0;
if (listener!=null) {
listener.onCounterTimeChange(formatTime(length),true);
}
myCountDownTimer= new MyCountDownTimer(length,1000);
}
}
public void setCounterTimeChangeListener(CounterTimeChangeListener listener) {
this.listener = listener;
}
}

Android Studio When clicking on imageview reduce time from the timer

This is the first time I am posting something on StackOverflow and that it only because I felt like this is one of those times I was not able to find what I needed from the vast Internet!
I am currently making an Android Application that is a game where I have an ball that is an imageview and each time I click on the ball, it moves to a random location with this method I've built:
private void changePos() {
RelativeLayout gameLayout = findViewById(R.id.gameFrame);
int frameHeight = gameLayout.getHeight();
int frameWidth = gameLayout.getWidth();
Random ballLocationY = new Random();
int ballY = ballLocationY.nextInt(frameHeight);
Random ballLocationX = new Random();
int ballX = ballLocationX.nextInt(frameWidth);
gameLayout.setY(ballY);
gameLayout.setX(ballX);
}
So what I am struggling with is to reduce the timer with each click.
What I am trying to do is to reduce the timer with each click on the ball by a certain percentage.
Basically each time the user clicks on the ball, the timer starts off from 0 and counting upwards in seconds and milliseconds, and at 3 second mark the game is over.
This is the approach I am playing around with:
Runnable updateThreadTimer = new Runnable() {
#Override
public void run() {
timeInMilliseconds = System.Clock.uptimeMillis() - startTime();
updateTime = timeSwapBuff + timeInMilliseconds;
int secs = (int) (updateTime / 1000);
countDownText.setText("" + String.format("%2d", secs) + ":"
+ String.format("%3d", timeInMilliseconds));
mHandler.postDelayed(this, 0);
if (secs == 3 && timeInMilliseconds >= 3000) {
timeSwapBuff += timeInMilliseconds;
mHandler.removeCallbacks(updateThreadTimer);
}
}
}
Variables necessary:
long startTime = 0L, timeInMilliseconds = 0L, timeSwapBuff = 0L, updateTime = 0L;
Handler mHandler = new Handler();
And then I have this in the Overridden onCreate method:
ball.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
changePos();
startTime = SystemClock.uptimeMillis();
mHandler.postDelayed(updateThreadTimer, 0);
}
return true;
}
}
So what I get is a timer that gets reset to 0 with each click on the button and starts again. And the timer displays in seconds and milliseconds: 0:0000, which is what I wanted, but I wanna reduce a certain percentage with each click and update the time.
So let's say the counter starts with 3 seconds limit, after clicking on the ball couple of times, the timer should eventually come down and the game should fail if the timer goes above that time.
Obviously I have simplified the code quite a lot to get straight to the point.
I was wondering if anyone has any suggestions on how I could approach the problem I have.
I also want to apologize if the question is not asked properly, being the first time posting, leave suggestions if theres any hatin' going on!
And I also want to mention it one more time, I've looked around for a solution like this, and the code I have put together is from lots of different sources, so I feel like I've done my research, and not being able to find something, hence I am turning to StackOverflow!
So I guess I am going to answer my own question as I have solved it now and also in hope that this may solve problems for some.
I redid some parts of the code and scratched the Runnable way, instead I took an approach that uses CountDownTimer class.
private long currentTime;
private long maxTimer = 3000;
private double fivePercent = .05;
private CountDownTimer myTimer = null;
protected void onCreate(Bundle savedInstanceState) {
// Some code...
// Assign 3000 to currentTime
currentTime = maxTimer;
ball.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
if (myTimer != null) {
// Cancel timer
myTimer.cancel();
// Calculating 5 % from maxTimer
long a = (long) (maxTimer * fivePercent);
maxTimer -= a;
// Storing new maxTimer in currentTime
currentTime = maxTimer;
}
myTimer = new CountDownTimer(currentTime, 1) {
#Override
public void onTick(long millisUntilFinished) {
countDownText.setText("Time: " + String.valueOf(millisUntilFinished));
currentTime = millisUntilFinished;
}
#Override
public void onFinish() {
Intent intent = new Intent(getApplicationContext(), ResultsActivity.class);
GameActivity.this.startActivity(intent);
}
}.start();
changePos();
scoreLabel.setText("Score: " + score++ + "");
}
return true;
}
});
}
I have simplified the code for demonstration purpose, but basically what I did was to create a CountDownTimer, and whenever I click on the ball, the CountDownTimer will get cancelled, and invoke a new one, before creating a new CountDownTimer it will calculate off 5 % and put the result into the new CountDownTimer.

Categories

Resources