I have a puzzle game for android. When the puzzle starts I take the current time:
long startTime = System.currentTimeInMillis()
When the player completes the puzzle, I take the time again, subtract the starting time and work out the elapsed time. This is all ok.
My problem is what to do when the application is interrupted. For example by a phone call. At the moment, the puzzle remains in it's previous state automatically (as it is in a view). However, the calculation completionTime = currentTime - startTime will now be invalid.
I have tried saving the elapsed time using onSaveInstaceState(Bundle). However its counterpart, onRestoreInstanceState(Bundle) is not called when re-entering the app. Rather, the onResume() method is called instead? I have read this is because the app has not been 'killed', rather it is still in memory. In the case of a 'kill', I'd imagine the state of the View will also be lost? I don't think it's terribly necessary to keep track of the view in this case, so I won't worry about the time either.
Is there a way to read a bundle from onResume(), should I just implement a shared preference?
I'd like to avoid updating the elapsed time in the game loop as this seems inefficient.
I would advice not using a SharedPreference at all.
You will only need 2 fields: startTime and elapsedTime
When the player starts, initialise elapsedTime to 0 and startTime to System.currentTimeMillis()
When onPause() is called, initialise elapsedTime using
elapsedTime = elapsedTime + (System.currentTimeMillis() - startTime);
When onResume() is called, initialise startTime to System.currentTimeMillis()
When the player is done, the time is
elapsedTime = elapsedTime + (System.currentTimeMillis() - startTime);
Please, if the logic has a flaw, comment (:
Note: There exists a way to use only one field.! But we'll keep that for the reader to discover.
shared preference seems a better idea to me.
calculate the time difference in onPause() , when the game goes to background, assuming user is already playing game. Add this difference to the previous time in the shared preference and store it again.
start the clock again on onResume() and repeat step 1 if necessary.
I hope you get the idea.
Related
I have been reading up on game loops and am having a hard time understanding the concept of interpolation. From what I seen so far, a high level game loop design should look something like the sample below.
ASSUME WE WANT OUR LOOP TO TAKE 50 TICKS
while(true){
beginTime = System.currentTimeMillis();
update();
render();
cycleTime = System.currentTimeMillis() - beginTime;
//if processing is quicker than we need, let the thread take a nap
if(cycleTime < 50)
Thread.sleep(cycleTime);
)
//if processing time is taking too long, update until we are caught up
if(cycleTime > 50){
update();
//handle max update loops here...
}
}
Lets assume that update() and render() both take only 1 tick to complete, leaving us with 49 ticks to sleep. While this is great for our target tick rate, it still results in a 'twitchy' animation due to so much sleep time. To adjust for this, instead of sleeping, I would assume that some kind of rendering should be going on within the first if condition. Most code samples I have found simply pass an interpolated value into the render method like this...
while(true){
beginTime = System.currentTimeMillis();
update();
render(interpolationValue);
cycleTime = System.currentTimeMillis() - beginTime;
//if processing is quicker than we need, let the thread take a nap
if(cycleTime < 50)
Thread.sleep(cycleTime);
)
//if processing time is taking too long, update until we are caught up
if(cycleTime > 50){
update();
//handle max update loops here...
}
interpolationValue = calculateSomeRenderValue();
}
I just don't see how this can work due to the 49 tick sleep time? If anyone knows of an article or sample I can check out please let me know as I am not really sure what the best approach to interpolation is...
I know its a bit late, but hopefully this article will help
http://gameprogrammingpatterns.com/game-loop.html
It explains game time scheduling very well. I think the main reason you are a bit confused is because of passing the render function the current elapsed time. Oh course this depending on which system you are using but conventionally the render doesn't modify the Scene in any way, it only draws it, therefore it doesn't need to know how much time has passed.
However the update call modifies the objects in the scene, and in order to keep them in time (e.g. playing animations, Lerps ect...) then the update function needs to know how much time has passed either globally, or since the last update.
Anyway no point me going to fair into it.... that article is very useful.
Hope this helps
I have an application in which I'm displaying a chronometer to the user for what he's doing.
Whenever the activity goes to the background (wether by home button, or back) I save that time (in seconds) and when the activity is brought back, I want to continue the chronometer running from the same time. The user might select a different item from the list, and the time is different, and also he might turn off the phone...
I can save the time of the chronometer, however I can't set it with a start time.
From the Chornometer API, the method setBase() states:
Set the time that the count-up timer is in reference to.
On my understanding, this means that if I set this value to currentTime, it'll start counting with 0.
Now, if I want it to start with the value 17s I thought about setting the base to the currentTime less the time 17 seconds ago. So something like:
setBase(system.currentTimeMillis() - (17 * 1000)).
However this doesn't work, and the it starts always with 0!
I read a few other threads around here, and none of the answers helped. It always starts with 0!
Thanks in advance.
I think you're going to have to keep track of some time marks yourself.
Chronometer myChrono;
long baseTime;
long stopTime;
long elapsedTime;
When you set the base time, you want to use:
baseTime = SystemClock.elapsedRealtime() - stopTime;
myChrono.setBase(baseTime);
When you want to see how much time has passed, use:
elapsedTime = SystemClock.elapsedRealtime() - myChrono.getBase();
Take a look at the SystemClock doc.
setBase(system.currentTimeMillis() - (17 * 1000))
Should be changed to
setBase(SystemClock.elapsedRealtime() - (17 * 1000))
In general:
mChronometer.setBase(SystemClock.elapsedRealtime() - (nr_of_min * 60000 + nr_of_sec * 1000)))
Hopefully this will save lots of u folks some time :)
Ive got an app with a class that implements Runnable. Where a thread is started and the run() methid overridden. This runs my graphics.
1.st question : how often is the run() called upon? i havent set a time for this so it must be a default value?
2.nd question : i want stuff to be done after a certain amount of time (2min,5min,10min) etc. What would be the best way to go about doing this, i was thinking about using an int as an counter and once it hits a specific value does what i want.
1.st question : how often is the run() called upon? i havent set a time for this so it must be a default value?
The run() method in your Thread is called when you call it eg. yourThread.start();
2.nd question : i want stuff to be done after a certain amount of time (2min,5min,10min) etc. What would be the best way to go about doing this, i was thinking about using an int as an counter and once it hits a specific value does what i want.
There are to options. Either you could call Thread.sleep() method (NB: Never do this in your UI thread).
Or you can do it the way you described above. So in your run() method you would have a while() loop and check on every iteration if the difference of the lastUpdate and the current time in milli seconds is bigger than the wanted period eg. 2 min, 5 min or 10 min.
I hope this helps.
Regarding question 2 - use ScheduledExecutor
1.st question : how often is the run() called upon?
You can find out for yourself, put this at the start of your Runnable:
Log.v("Running Runnable", System.currentTimeMillis() + "");
2.nd question : i want stuff to be done after a certain amount of time (2min,5min,10min) etc.
Extend a HandlerThread (it initializes the Looper for you!), add a Handler as a class variable, and use the Handler's postDelayed() or postAtTime() methods.
The exact amount of time in between calls to run() depends on the processor. The time between each call is the sort of thing that's really visible by the nanosecond. If you're trying to create a timer, I'd recommend using System.currentTimeMillis(), calling it in the run() method, and once the difference is greater than or equal to 1000 milliseconds, the actual timer decrements by one. This will keep track of seconds, and you can use it as a base for minutes and generating other events at specific times.
How to start the chronometer with a specific time other than default 00:00? Is it possible to set chronometerObj.setBase(startTime) ?
ch.setBase(SystemClock.elapsedRealtime()-anylongvalue);
ch.start(); can I set start time, if I put anylongvalue?
In general:
mChronometer.setBase(SystemClock.elapsedRealtime() - (nr_of_min * 60000 + nr_of_sec * 1000)))
Chronometer object, when instantiated, defaults to the base time being set to now ('now' as in the value you get from SystemClock.elapsedRealtime()).
You can change the base time (00:00 time) by calling setBase(<some other value>).
Presumably, although I haven't tried the experiment, you could see the elapsed time since last system boot using setBase(0).
So you can use chronometer to see the elapsed time since any arbitrary call you made in the past to SystemClock.elapsedRealtime(). The trick is that you need to have stored that value somewhere you can dependably get it back despite app and phone state changes. (See Android: chronometer as a persistent stopwatch. How to set starting time? What is Chronometer "Base"? for example.)
Many answers suggest persisting that arbitrary time-in-the-past in an intent. but, at best, this only keeps the timer counting up while the phone stays on.
I already am using a database and store my starting time in there. I created a one-column table for it and store a single record in it. My starting time for the chronometer survives a phone reboot.
I collect some information inside a Spinner and this information can change
for example something may disappear or something new may come
I want the application to store this information every 100 seconds in a database
is it possible to do something like this?
I'm thinking of creating a database and within this database storing this information
but I'm not sure about this "every 100 seconds" part, how would I do this?
I'm thinking that maybe I will have to create a process that will be running in parallel, this process will have a time counter and when 100 seconds have passed, the function that will store the information in the database will be called
But I'm not sure if this is possible. I mean, creating such a counter that will run in parallel with the other application.
maybe there is something easier
thanks in advance
On Second Thought:
This is probably not the way to go(AlarmManager). A much better way would be to bind a listener to the spinner. That way you will only react and save data when there is new data to save.
Can you provide some details on the Spinner you are using and perhaps we can work out the event binding.
For the storage, use SQlite: http://developer.android.com/reference/android/database/sqlite/package-summary.html
For the 100 second interval, use the AlarmManager:
This class provides access to the system alarm services. These allow
you to schedule your application to be run at some point in the
future. When an alarm goes off, the Intent that had been registered
for it is broadcast by the system, automatically starting the target
application if it is not already running. Registered alarms are
retained while the device is asleep (and can optionally wake the
device up if they go off during that time), but will be cleared if it
is turned off and rebooted.
http://developer.android.com/reference/android/app/AlarmManager.html
Take a look at this answer for a code sample and further discussion: Android: How to use AlarmManager
I have some same requirement and done this in My application using CountDownTimer
and Created one Custom Class extending CountDownTimer and in that when Finish, I just did perform my data loading and initialized the same object agian to run after using Start
public class MyCounter extends CountDownTimer {
public MyCounter(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onFinish() {
MCObject.cancel();
MCObject = new MyCounter(_intMCCounter, 1000);
MCObject.start();
new tempAysnc().execute(paramList); // code to get data or store data write your code to insert data into database
}
#Override
public void onTick(long millisUntilFinished) {
}
}
In your Activity onCreate() write this code to initiate it first time.
_intMCCounter = 60000 * 5; //set interval to every 5 minutes
MCObject = new MyCounter(_intMCCounter, 1000);
MCObject.start();
and in onDestroy of your Activity write this code to cancel the Timer.
MCObject.cancel();
I think better way is to create a Listener which will check for the data change. If it founds any change of data then it make a function call which will store data in database.
You can use SQLite
I don't see any reason why this couldn't be done. (Only problem is maybe you run out of storage space after a while if you are planning to insert new data constantly)
Check ScheduledThreadPoolExecutor
http://developer.android.com/reference/java/util/concurrent/ScheduledThreadPoolExecutor.html
Android natively supports SQLite so you can use it as your database.