System.currentTimeMillis() work wrong - android

I need stopWatch and I used http://www.goldb.org/stopwatchjava.html
It did not work well so I tried write out the value every 1000ms:
stopWatch.start();
HandlerScrollBar.postDelayed(TtScroll, 1000);
private Runnable TtScroll = new Runnable() {
public void run() {
long time = stopWatch.getElapsedTime();
HandlerScrollBar.postDelayed(TtScroll,(long) 1000);
Log.d(TAG, Long.toString(time));
}
};
I can see value of time every second in CatLog and this is result:
Real time is max +5ms but in Column it is at least +3 seconds! How is it possible? It is the same with
new Date().getTime().
Is there some StopWatch class which will pass this test as expected?
Thank you.

If you are measuring elapsed time, and you want it to be correct, you must use System.nanoTime(). You cannot use System.currentTimeMillis(), unless you don't mind your result being wrong.
The purpose of nanoTime is to measure elapsed time, and the purpose of currentTimeMillis is to measure wall-clock time. You can't use the one for the other purpose. The reason is that no computer's clock is perfect; it always drifts and occasionally needs to be corrected.
Since nanoTime's purpose is to measure elapsed time, it is unaffected by any of these small corrections.I would suggest to pick the nanoTime() as it has better accuracy in those microcalculations.
for extremely precise measurements of elapsed time. From its javadoc:
long startTime = System.nanoTime();
// ... the code being measured ...
long estimatedTime = System.nanoTime() - startTime;

Seems impossible. I've never had System.currentTimeMillis() act that way. Also, you're logging out as Log.d() but the logcat you show indicates a Log.e(). You sure that's the right logcat?

Related

Mana recovery issue

We're making a game in Android Studio and we got stuck. The resource (mana) used for specific spells should recover on time, e.g. 1 mana point per 5 minutes. We don't really get how to make it recover while the game is off. Is there a method to check current date/time and count the amount of mana replenished? Converting date and time to String and comparing it with the new date/time seems to be an "exciting" work to do, but we would bypass these mechanics if there is a way.
Thank you in advance.
The best way to do this in the background is to register a receiver in your manifest. This means the receiver will keep listening for broadcasts even if the app is off.
What you need is this particular action when registering your receiver Intent.ACTION_TIME_TICK
There is a more detailed answer about this matter here Time change listener
Another solution is to use the Calendar class in java. With it you can get the exact minutes passed from a point in the past to this moment. This way you don't have to worry about parsing dates and similar. I can't provide you specific examples because me myself have not used the Calendar class very much, but I'm sure you can find lots of stuff in the official documentation and on stackoverflow about it.
No need to work with Date objects, the simple usage of System.currentTimeMillis() should work. Here's a basic outline:
long mLastManaRefreshTime = System.currentTimeMillis();
void refreshMana()
{
long timeDelta = System.currentTimeMillis() - mLastManaRefreshTime;
mLastManaRefreshTime = System.currentTimeMillis();
float totalManaToRefresh = (float)AMOUNT_TO_REFRESH_IN_ONE_MINUTE * ((float)timeDelta / 60000f);
mMana += totalManaToRefresh;
if (mMana > MAX_MANA)
mMana = MAX_MANA;
}
This method is of course just an outline. You will need to call this once every update cycle. It will calculate how much time passed since the last time refreshMana was called, and replenish the required amount.
If you need this to work while the game is off, you can save the mLastManaRefreshTime to a SharedPreferences object and reload it when the game loads up again.
With System.currentTimeMillis() you can a current time-stamp in milliseconds.
You could save the latest time-stamp in your Preferences with every 5 min tick of the running game. For the other case, when your App comes back from a state where it does not do this (i.e. called the first time, woken up etc.).
Something like this:
int manacycles = ((int) (((System.currentTimeMillis() - oldtimestamp) / 1000) / 60) ) % 5;
would give you the number of Mana points you would have to add.
Alternately you could do the same thing with the Calendar class.
Also keep in mind players could cheat this way by simply changing their time. If your game is online you could get the time from the internet, with something like this:
try {
TimeTCPClient client = new TimeTCPClient();
try {
// Set timeout of 60 seconds
client.setDefaultTimeout(60000);
// Connecting to time server
// Other time servers can be found at : http://tf.nist.gov/tf-cgi/servers.cgi#
// Make sure that your program NEVER queries a server more frequently than once every 4 seconds
client.connect("nist.time.nosc.us");
System.out.println(client.getDate());
} finally {
client.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}

How to make Android custom clock time accurate?

I made a appWidget which show the current time of the server(2012-08-29, 12:00:08 for example). I request the server time every fix duration(1 hour for example). If receives the server time, updates the appWidget display. During the duration, I launch a Handler to update the time like this:
mTick = new Runnable() {
public void run() {
mMillis += 1000;
long now = SystemClock.uptimeMillis();
long next = now + (1000 - now % 1000);
mHandler.postAtTime(mTicker, next);
}
}
mTicker.run();
My questions:
1 After a long time(one day elapsed), The time displayed in AppWidget is slow than the real server time.
I doubt that my method used above is not accurate enough to update the time.
Any suggestions about this problem?
You should not use SystemClock.uptimeMillis() because it does not include time spent in deep sleep, thats why your app widget is out of sync.
You should use SystemClock.elapsedRealtime() call instead
Upd: sorry, I think I misunderstand the problem here. What you are trying to do is to use postAtTime to post runnable after some time in future. Please notice that postAtTime does not include time when device is in deep sleep.
What you need is to track accurate ammount of deltas between redrawing of your widget. You should use SystemClock.elapsedRealtime() for that.
Algorithm should be like this:
long serverTime = getServerTime();
long lastTime = SystemClock.elapsedRealtime();
// Somewhere in updateWidget() or call on timer:
serverTime = serverTime + SystemClock.elapsedRealtime() - lastTime;
lastTime = SystemClock.elapsedRealtime();
// At this moment in serverTime variable you have "server" time adjusted by the time which passed on device, including time spent in deep sleep

Precision of delay

I have a problem with this code used for Android (Java)
handler.postDelayed(new Runnable(){
public void run(){
// Your code goes here...
}
}, 500);
If the delay is about 500ms then the program seems to repeat the task at 0.5s, but if I change to less than 100ms or even less it does not follow any more. I test the brightness change and for a while it can repeat the change of brightness at that rate, but then slow down and come back to normal flash rate again. It seems unstable. Do you have any code that give exact delay regardless of the load of the phone's CPU.
Many thanks
Not from Java, no; stock Java isn't a real-time system.
Timing precision is subject to the whims of the JVM and the OS's scheduler. You may be able to get incrementally more precise, but there's no guarantee of the kind of precision you're looking for.
You might be able to do something more precise if you use a CountDownTimer which has a periodic tick. Essentially you set it to count down for a period which can be hours if need be, and there are two methods one method is called on each tick, and the other at the end of the timer at which point you could start another one. Anyway you could set the tick to be very fast, and then only kick off the code at the delay point by check the actual time difference in the click. I think thats about the best you could do. Essentially inside the tick you would issue a signal if the right amout of time had actually passed. That signal would either kick off the thread or release something the already running thread was waiting on. What is the value of the CountDownTimer, I guess its just that you can do a very frequent polling, and elapsed time check. Although its not guaranteed, the time between the ticks you can set it to a high frequency and check/poll very frequently. This could lead to a smooth performance not unlike a realtime system. Its more likely to be accurate because its just issuing a signal and not taking up the resources of threading just to issue the signal. You might also try an IntentService to perform the tasks and just call startService(intentToIntentService) each call. See if the threading works better inside a service like IntentService which does queue them up I believe.
Date startDate = new Date();
long startTime = startDate.getTime();
// Tick called every 10th of a second. OnFinish called at Signal.
CountDownTimer ctDownTimer = new CountDownTimer(30000, 100) {
long startIntervalTime=startTime;
public void onTick(long millisUntilFinished) {
Date now = new Date();
long nowTime = now.getTime();
if ((startIntervalTime - nowTime) > 100)
{
issueSignal();
intervalStartTime=nowTime;
}
now=null;
}
public void onFinish() {
Log.d("MyClass", "Done") // Maybe start out.
}
}.start();

Android Sensor Timestamp reference time

I'm reading timestamp values from SensorEvent data but I can't work out the reference time for these values. Android documentation just says "The time in nanosecond at which the event happened" As an example:
My current Android device date, October 14th 2011 23:29:56.421 (GMT+2)
System.currentTimeMillis * 1000000 (nanosec) = 1318627796431000000 (that's ok)
sensorevent.timestamp (nanosec) = 67578436328000 = 19 hours 46 min ????
May you help me?
thanks
It appears that what you are dealing with is the number of nanoseconds since the operating system started, also known as "uptime".
Further info on the issue: http://code.google.com/p/android/issues/detail?id=7981
I should add that the linked question SensorEvent.timestamp to absolute (utc) timestamp? deals with the same issue and is where I found the answer.
I know that it's a very old question, but, I'm also struggling for converting SensorEvent.timestamp to a human readable time. So I'm writing here what I've understood so far and how I'm converting it in order to get better solutions from you guys. Any comments will be welcomed.
As I understood, SensorEvent.timestamp is an elapsed time since the device's boot-up. So I have to know the uptime of the device. So if there is an API returning device's boot-up, it will be very easy, but, I haven't found it.
So I'm using SystemClock.elapsedRealtime() and System.currentTimeMillis() to 'estimate' a device's uptime. This is my code.
private long mUptimeMillis; // member variable of the activity or service
...
atComponentsStartUp...() {
...
/* Call elapsedRealtime() and currentTimeMillis() in a row
in order to minimize the time gap */
long elapsedRealtime = SystemClock.elapsedRealtime();
long currentTimeMillis = System.currentTimeMillis();
/* Get an uptime. It assume that elapsedRealtime() and
currentTimeMillis() are called at the exact same time.
Actually they don't, but, ignore the gap
because it is not a significant value.
(On my device, it's less than 1 ms) */
mUptimeMillis = (currentTimeMillis - elapsedRealtime);
....
}
...
public void onSensorChanged(SensorEvent event) {
...
eventTimeMillis = ((event.timestamp / 1000000) + mUptimeMillis);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(eventTimeMillis);
...
}
I think this works for Apps that a millisecond time error is okey. Please, leave your ideas.

How to limit framerate when using Android's GLSurfaceView.RENDERMODE_CONTINUOUSLY?

I have a C++ game running through JNI in Android. The frame rate varies from about 20-45fps due to scene complexity. Anything above 30fps is silly for the game; it's just burning battery. I'd like to limit the frame rate to 30 fps.
I could switch to RENDERMODE_WHEN_DIRTY, and use a Timer or ScheduledThreadPoolExecutor to requestRender(). But that adds a whole mess of extra moving parts that might or might not work consistently and correctly.
I tried injecting Thread.sleep() when things are running quickly, but this doesn't seem to work at all for small time values. And it may just be backing events into the queue anyway, not actually pausing.
Is there a "capFramerate()" method hiding in the API? Any reliable way to do this?
The solution from Mark is almost good, but not entirely correct. The problem is that the swap itself takes a considerable amount of time (especially if the video driver is caching instructions). Therefore you have to take that into account or you'll end with a lower frame rate than desired.
So the thing should be:
somewhere at the start (like the constructor):
startTime = System.currentTimeMillis();
then in the render loop:
public void onDrawFrame(GL10 gl)
{
endTime = System.currentTimeMillis();
dt = endTime - startTime;
if (dt < 33)
Thread.Sleep(33 - dt);
startTime = System.currentTimeMillis();
UpdateGame(dt);
RenderGame(gl);
}
This way you will take into account the time it takes to swap the buffers and the time to draw the frame.
When using GLSurfaceView, you perform the drawing in your Renderer's onDrawFrame which is handled in a separate thread by the GLSurfaceView. Simply make sure that each call to onDrawFrame takes (1000/[frames]) milliseconds, in your case something like 33ms.
To do this: (in your onDrawFrame)
Measure the current time before your start drawing using System.currentTimeMillis (Let's call it startTime)
Perform the drawing
Measure time again (Let's call it endTime)
deltaT = endTime - starTime
if deltaT < 33, sleep (33-deltaT)
That's it.
Fili's answer looked great to me, bad sadly limited the FPS on my Android device to 25 FPS, even though I requested 30. I figured out that Thread.sleep() works not accurately enough and sleeps longer than it should.
I found this implementation from the LWJGL project to do the job:
https://github.com/LWJGL/lwjgl/blob/master/src/java/org/lwjgl/opengl/Sync.java
Fili's solution is failing for some people, so I suspect it's sleeping until immediately after the next vsync instead of immediately before. I also feel that moving the sleep to the end of the function would give better results, because there it can pad out the current frame before the next vsync, instead of trying to compensate for the previous one. Thread.sleep() is inaccurate, but fortunately we only need it to be accurate to the nearest vsync period of 1/60s. The LWJGL code tyrondis posted a link to seems over-complicated for this situation, it's probably designed for when vsync is disabled or unavailable, which should not be the case in the context of this question.
I would try something like this:
private long lastTick = System.currentTimeMillis();
public void onDrawFrame(GL10 gl)
{
UpdateGame(dt);
RenderGame(gl);
// Subtract 10 from the desired period of 33ms to make generous
// allowance for overhead and inaccuracy; vsync will take up the slack
long nextTick = lastTick + 23;
long now;
while ((now = System.currentTimeMillis()) < nextTick)
Thread.sleep(nextTick - now);
lastTick = now;
}
If you don't want to rely on Thread.sleep, use the following
double frameStartTime = (double) System.nanoTime()/1000000;
// start time in milliseconds
// using System.currentTimeMillis() is a bad idea
// call this when you first start to draw
int frameRate = 30;
double frameInterval = (double) 1000/frame_rate;
// 1s is 1000ms, ms is millisecond
// 30 frame per seconds means one frame is 1s/30 = 1000ms/30
public void onDrawFrame(GL10 gl)
{
double endTime = (double) System.nanoTime()/1000000;
double elapsedTime = endTime - frameStartTime;
if (elapsed >= frameInterval)
{
// call GLES20.glClear(...) here
UpdateGame(elapsedTime);
RenderGame(gl);
frameStartTime += frameInterval;
}
}
You may also try and reduce the thread priority from onSurfaceCreated():
Process.setThreadPriority(Process.THREAD_PRIORITY_LESS_FAVORABLE);

Categories

Resources