I am working on an Android application and I just want to know when a function hasn't been called. For example, lets say you have the function
void foo()
{
...//do something here;
}
What I want to do is time if the function hasn't been called for lets say, 10 seconds, and then record the time after that 10 seconds. After that, if the function is invoked and it is called, I want to record the time when it function begins again. I was thinking of using the Timer function but I wasn't exactly sure on how to test whether or not a function has been invoked.
I am working on an application in which you see whether or not a person starts or stops walking. For example, if someone has stopped walking for 10 seconds, I want to record that time. When they resume walking, I also want to record that time. Hope this makes better sense. Any help would be appreciated! Thanks!
One possible solution is to add a boolean flag to your code; maybe call it fooWasCalled. Initialize this variable to false and set it to true inside foo(). Then you can simply check the flag when you need to know whether or not the function was called.
This is a very common idiom to check whether some action has occurred.
p.s. Since you are using a Timer, you probably need to synchronize access to this boolean flag or use some other thread-safe mechanism.
This is probably what you want (not completer code, just idea)
protected boolean mIsCountDownOn;
private class CountDownTimer mCountDownTimer = new CountDownTimer(10000, 10000)
{
#Override
public void onTick(long millisUntilFinished)
{
}
#Override
public void onFinish()
{
mIsCountDownOn = false;
}
};
In foo
foo
{
if (mIsCountDownOn)
{
// less than 10 seconds since the last time foo is called
mCountDownTimer.cancel();
}
else
{
// more than 10 seconds since last call
mIsCountDownOn = true; // will start the timer at the end of foo body
// Code to save mTime to wherever you want to save it.
}
// Whatever else foo supposes to do
mTime = // get the time now
mCountDownTimer.start();
}
Related
The following code is from Head First Android. It is for a stopwatch app.
I have a few questions in the following code:
The code runs like -> OnCreate -> runTimer() (skips handler.post()) -> OnStart -> onResume -> Comes back to handler.post().
Why does it skip hander.post() in the first place?
I have two textView.setText(). But the first one doesn't work. It's always the last one. I put the second one just to see what the code does after postDelay() method.
Why doesn't the first one work? I am expecting the text to jump back and forth from "hello" to "hh:mm:ss".
So what exactly happens during the 1-second delay after postdelay() is executed.
Does the code starts running normally and when its 1 second the postDelay() is called?
why is this used in postDealy(this, 100). shouldn't it be this.run()?
public class MainActivity extends AppCompatActivity {
private boolean running = false;
private int counter = 0;
private Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
runTimer();
}
public void onClickStart(View view){
running = true;
}
public void runTimer(){
final TextView textView = findViewById(R.id.timer);
handler.post(new Runnable() {
#Override
public void run() {
int hours = counter/3600;
int minutes = (counter%3600)/60;
int secs = counter%60;
String time = String.format("%d:%02d:%02d", hours, minutes, secs);
textView.setText(time); // Doesn't set it to this - see last line
if(running){
counter++;
}
handler.postDelayed(this,1000); // what does happens between next one second
textView.setText("hell0"); // Always set it to this
}
});
}
Why does it skip hander.post() in the first place?
It is not skipped, it will be executed after onResume() returns. All the Runnables, queued though a Handler associated with the main thread, start their execution only after onResume() returns.
Why doesn't the first one work?
It does work. You just can't visually see it because the two method calls, textView.setText(), are invoked "almost" at the same time.
The following sequence of calls happen at each run():
textView.setText(time),
the same Runnable is posted to the queue with handler.postDelayed(this,1000). Immediately after that
textView.setText("hell0") is called
Why doesn't the first one work? I am expecting the text to jump back and forth from "hello" to "hh:mm:ss".
You should implement an extra logic to switch between time and "hell0" at each run() execution.
E.g. create a boolean flag in the Activity and set either time or "hell0" depending on the flag value (don't forget to change the flag value at each run() execution).
why is this used in postDelay(this, 100). shouldn't it be this.run()?
No, this.run() is executed synchronously (and immediately) and is of type void. The code won't compile as postDelay() expects the Runnable type, not void.
handler.postDelayed(this,1000);
This used to run your function after 1 second. It is a delay for 1 second.
The code written in your handler will execute after a second. That's all.
I am trying to write an app that shows the user a string on textview, and replace the text due to user input. This should happen on time intervals of 60 seconds.
I tried to use a countdown timer, which sets a boolean var to false on it's onFinish method. While this boolean is true, I am trying to change the strings in the textview (further work will be to change the text due to the user actions, but I'm still trying to get this work for simple actions).
For now, the app seems to be stucked and nothing happens, but if I am removing the while loop, there is a single text on the screen (as it should be).
Is there a problem using a while loop for that purpose? Is there a different way to work along with the timer?
(p.s I know there are some problems in the code, but this is just for isolating the problem. Thanks!)
EDIT:
I will try to clarify my intentions:
I want to give the user tasks, which he should perform in a given time. I want to display the time remaining on the screen, along with the task to perform. When the user finishes the task, if there is still time on the clock, he will press a button and another task will appear. The goal is to finish as many tasks as possible in the given time.
My code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start_game);
Bundle b = getIntent().getExtras();
game = b.getParcelable("game_record");
figuresList = new ArrayList<String>(game.getFiguresList());
clockView = (TextView) findViewById(R.id.clockView);
figureText = (TextView) findViewById(R.id.figureText);
timer = new CountDownTimer(10000, 1000) {
public void onTick(long millisUntilFinished) {
clockView.setText(Long.toString(millisUntilFinished / 1000));
}
public void onFinish() {
clockView.setText("done!");
isTurn = false;
}
};
playRound();
}
private void playRound() {
figuresIterator = figuresListUsage.iterator();
isTurn = true;
String nextFigure = figuresIterator.next();
timer.start();
while (isTurn == true) {
figureText.setText(nextFigure);
nextFigure = figuresIterator.next();
}
}
It's a little difficult to understand your games logic but the main problem i see with your code is that you are entering the loop in a lifecycle event handler. Take a look at this lifecycle description. You are stopping it in onCreate and there is still work to be done before the activity will finish its lifecycle handling.
I suggest you try making play round event bound or use a diffrent thread for it. there are alot of threading APIs for android and as i dont know the nature of your game rounds i cant recommend any.
I'm making an application and a certain part in my application I store a list of prices along with the time that the prices last for (they do not all last the same amount of time). So a price lasts a certain time then once that price's time is up it changes to another price (this part changes the UI or basically it updates a textview with the new price). So what I need is a timer that sets the timer again with the new time length and once it's done make the UI change. For instance say that each of the pairs represent the price amount and the time (in seconds): { {$2.53,1.4s}, {$4.57,4.45s}, {$1.23,3.6s}...}
So when the timer starts off the textview displays $2.53 and the timer lasts 1.4s and then it should grab the next price $4.57 and be set again but this time for 4.45s. This process continues on and on until the game is finished. I was thinking of using the CountDownTimer and resetting itself once the onFinish() method is called (I haven't verified if this idea works yet). Are there any other ideas?
You can use a countdown timer and onFinish method you call back the function and it starts another timer:
private void startWheatPrices(long gameTime)
{
//other stuff executed
StartWheatTimer(GameTimeDifference);//starts the timer for the first time
}
private void StartWheatTimer(long TimerAmount)
{
WheatTimer = new CountDownTimer(TimerAmount, 10) {
public void onTick(long millisUntilFinished)
{
}
public void onFinish()
{
//other stuff executed
WheatPricesTV.setText(Float.toString(PriceList.get(0).get(WheatPriceIndex).price));//price is changed
if(InGameplayMode)
StartWheatTimer(convertToMilliseconds(PriceList.get(0).get(WheatPriceIndex).timeLength));//call back the function to start the timer again
}
}.start();
}
I have been using countdowntimer and it has performed perfectly. Now I want to implement the opposite (Something like stop watch) in which the time updates the screen every second and it increments forever till I stop.
Is there a way (similar in simplicity) that does the job sort of like Countdowntimer? I know I can use Timer and Timertask but this creates new thread and I read that it is not that reliable (or recommended).
Thank you
Looks like a Chronometer object is what you need.
By setting a tick listener, you will get a tick every second (unfortunately that's the minimum precision available, but from the question it looks like it's enough for your needs).
If you add the following class to you project, you can use it just like the CountDownTimer class:
public abstract class Stopwatch extends Thread {
int tickFreq;
public Stopwatch(int tickFreq) {
this.tickFreq = tickFreq;
}
abstract void onTick();
#Override
public void run() {
onTick();
try {
Thread.sleep(tickFreq);
}
catch (InterruptedException e) {
e.printStackTrace();
}
super.run();
}
}
And to use it, you would write:
new Stopwatch(1000){
#Override
void onTick() {
// Do whatever you want to do in here
}
}.start();
The param that's passed to the constructor (1000) is how often it should call onTick(). In this case, it's every 1000 milliseconds, i.e. every 1 second.
I have a timer that counts up from the time a user encounters that activity
I am currently using a Chronometer set during onCreate (initially started only when certain conditions are met). But I need the chronometer to keep counting upward until the app and all its views are closed (I have an "Exit" function to do that).
The problem is that the Chronometer gets reset to zero on every time I look at another tab and come back to its activity. (This has to do with the oncreate, but I dont know the way around it)
I didn't find an intuitive way to save the chronometer's state or countup in the background on its own (or to perhaps keep track of the time on my own and update the chronometer visually at a different point in time)
One idea I had was to start the Chronometer with a service and let the service keep counting , while having a textview in the existing activity update using the chronometer's current time tally as a string
any insight on a known approach to this problem be appreciated!
This is further complicated because this is an activity in a tabhost, and tabhosts call both onPause and onResume every time you load a view, so this breaks lifecycle functions.
There are a number of ways to persist the time. The easiest one I have found is to store the time in the Intent that was used to create the original activity via getIntent().putExtra("START_TIME", floatvalue). You may retrieve the value with getIntent().getFloatExtra("START_TIME", 0f). Doing it this way has a number of benefits:
It doesn't break the Activity LifeCycle and does not require a Context.
It can be passed easily between other Activities and Applicaitons.
It persists among Pauses and Stops.
It doesn't require special listeners.
It doesn't create any new objects (the Intent is the one used to create the Activity the first time).
This solution is great for persisting in a Tabbed Activity, or across Dialogs, etc. It has some limitations if leaving the Application to a more memory intensive one, but only if your Activity is destroyed (due to memory).
Because of my Tabhost, the lifecycle functions could not be relied on.
What I did was make the chronometer a static global in a central class, and added a ontabchangedlistener within my tabhost that checked to see if the tab being changed to was the tab with the chronometer. If this was true then it stores the Long value of the chronometer's current time.
tabHost.setOnTabChangedListener(new OnTabChangeListener(){
#Override
public void onTabChanged(String arg0) {
// TODO Auto-generated method stub
if(arg0.contentEquals("homeGroup"))
{
//store time in centralhelper.java
//stopWatch is of type Chronometer
//stopWatchLastTime is of type Long and is initially set to zero. Chronometer uses milliseconds to determine time, will never be zero after set
CentralHelper.stopWatchLastTime = CentralHelper.stopWatch.getBase();
}
}
});
When my homeGroup view loads, the onResume() function is called, there is a condition here to retrieve the time for the chronometer to resume counting from. Despite the fact that a tabhost will call both onPause() and onResume() in EVERY load outside of normal lifecycle functions, they still get called before onCreate()
public void onResume(){
super.onResume();
//update Chronometer with time stored in tabchangelistener
if(CentralHelper.stopWatchLastTime!=0)
CentralHelper.stopWatch.setBase(CentralHelper.stopWatchLastTime);
}
this allowed me to do a similar check in onCreate()
if(CentralHelper.stopWatchLastTime!=0)
{
CentralHelper.stopWatch.start(); //this is where it resumes counting from the base set in onResume()
}
else
{
CentralHelper.stopWatch.start();
CentralHelper.stopWatch.setBase(SystemClock.elapsedRealtime());
}
When you switch to a different activity the previous one is paused (onPause, asand so on, in attached image) when you came back to the activity it is resumed, but occasionaly when dalvik runs out of memory your Activity object can be deleted when ton showing.
If you keep your application data in the Activity instance you might loose it accidentally, please read this Activity Lifecycle http://developer.android.com/reference/android/app/Activity.html
This approach is tested and it works really well.
Try this:
Take a boolean volatile variable which will control your thread(start/stop). Take three text views, hour, min and sec text views, and remove chronometer completely. Update your UI using a Handler Write the following code.
public void timeUpdate()
{
timerThread = new Thread(new Runnable() {
#Override
public void run() {
while(continueThread){
Date newDate = new Date();
if(((newDate.getTime()) - date.getTime()) > 1000){
secondCounter = secondCounter+1;
mHandlerUpdateSec.post(mUpdateSec);
System.out.println("Inside the Theread ..."+secondCounter);
if(secondCounter > 59){
minuteCounter = minuteCounter + 1;
mHandlerUpdateMinute.post(mUpdateMinute);
secondCounter = 0;
if(minuteCounter > 59){
hourCounter = hourCounter + 1;
mHandlerUpdateHour.post(mUpdateHour);
minuteCounter = 0;
}
}
}
try{
timerThread.sleep(1000);
}catch (Exception e) {
// TODO: handle exception
}
}
}
});
timerThread.start();
}
The continueThread is a boolean volatile variable. Setting it to false will stop the thread. The timerThread is an instance of thread. There are three counters, hour, min and sec counters which will give you the latest time values. The handlers are updated as follows.
final Handler mHandlerUpdateSec = new Handler();
final Runnable mUpdateSec = new Runnable() {
public void run() {
String temp = "" + secondCounter;
System.out.println("Temp second counter length: " + temp.length());
if(temp.length() == 1)
secTextView.setText("0" + secondCounter);
else
secTextView.setText("" + secondCounter);
}
};
final Handler mHandlerUpdateMinute = new Handler();
final Runnable mUpdateMinute= new Runnable() {
public void run() {
String temp = "" + minuteCounter;
System.out.println("Temp second counter length: " + temp.length());
if(temp.length() == 1)
minTextView.setText("0" + minuteCounter);
else
minTextView.setText("" + minuteCounter);
}
};
final Handler mHandlerUpdateHour = new Handler();
final Runnable mUpdateHour = new Runnable() {
public void run() {
String temp = "" + hourCounter;
System.out.println("Temp second counter length: " + temp.length());
if(temp.length() == 1)
hourTextView.setText("0" + hourCounter);
else
hourTextView.setText("" + hourCounter);
}
};
Now, whenever you want to start the timer, set continueThread to true and call timeUpdate(). To stop it, just do continueThread = false. To start the thread again, set continueThread to true and call timeUpdate() again. Make sure you update the counters accordingly while you start/stop the timer.
You could save the start time in a sharedpreferences (or file, etc.) and establish your count-up from that (rather than starting at 0) in onResume().
Your UI may need some changes to handle the fact that you will have to reset the start time, since it could theoretically count forever.