Precision of delay - android

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();

Related

High frequency UI update - Android

I want to make 8 squares change colors between red/black periodically.
I acomplish this using timer.schedule with period time in milliseconds and it work
BUT then I realized that I need to use small time between this transitions (example nanoseconds).
To accomplish that I wrote this code:
timerTask = new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run(){
//CODE OF THE TASK.
}
});
}
};
//To make schedule this task in 5 nanoseconds I use this!
exec = new ScheduledThreadPoolExecutor(1);
exec.scheduleAtFixedRate(timerTask, 0, 5, TimeUnit.NANOSECONDS);
But when I run this, the UI is not updating (seems to be stuck), but in logcat, all the logs are printing very fast. How can I achieve to make a task periodically x nanoseconds?
The entire Android UI runs at 60Hz- 60 updates per second. This means the minimum time between redraws is 16 ms. You cannot run it at a higher framerate. Nor are human eyes capable of seeing changes at a much higher frequency than that.
iOS and most video game consoles also work on a 60 Hz refresh rate. You'd find very few to no systems that go faster.
I'm not sure what exactly you're trying to accomplish, but I'm fairly certain you're trying to do it the wrong way.
ALSO: I notice your timer task posts to a handler. That means your timer task is going to tell the main thread to run something, and the timer task is running in nanoseconds. YOu're basically going to choke your main thread full of "run this task" messages, then eventually crash with an OOM error when the event queue becomes so massive it can't add any more (which may take several minutes), because there's no way you're processing them fast enough with the thread switching overhead.
After doing a lot of research, I realized that in order to get the view to refresh so quickly, I needed the use of SurfaceView and a Thread to make the UI redraw very fast, I really had no knowledge of this. Thanks for the help

System.currentTimeMillis() work wrong

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?

Android - Scheduling an Events to Occur Every 10ms?

I'm working on creating an app that allows very low bandwidth communication via high frequency sound waves. I've gotten to the point where I can create a frequency and do the fourier transform (with the help of Moonblink's open source code for Audalyzer).
But here's my problem: I'm unable to get the code to run with the correct timing. Let's say I want a piece of code to execute every 10ms, how would I go about doing this?
I've tried using a TimerTask, but there is a huge delay before the code actually executes, like up to 100ms.
I also tried this method simply by pinging the current time and executing only when that time has elapsed. But there is still a delay problem. Do you guys have any ideas?
Thread analysis = new Thread(new Runnable()
{
#Override
public void run()
{
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
long executeTime = System.currentTimeMillis();
manualAnalyzer.measureStart();
while (FFTransforming)
{
if(System.currentTimeMillis() >= executeTime)
{
//Reset the timer to execute again in 10ms
executeTime+=10;
//Perform Fourier Transform
manualAnalyzer.doUpdate(0);
//TODO: Analyze the results of the transform here...
}
}
manualAnalyzer.measureStop();
}
});
analysis.start();
I would recommend a very different approach: Do not try to run your code in real time.
Instead, rely on only the low-level audio code running in real time, by recording (or playing) continuously for a period of time encompassing the events of interest.
Your code then runs somewhat asynchronously to this, decoupled by the audio buffers. Your code's sense of time is determined not by the system clock as it executes, but rather by the defined inter-sample-interval of the audio data you work with. (ie, if you are using 48 Ksps then 10 mS later is 480 samples later)
You may need to modify your protocol governing interaction between the devices to widen the time window in which transmissions can be expected to occur. Ie, you can have precise timing with respect to the actual modulation and symbols within a "packet", but you should not expect nearly the same order of precision in determining when a packet is sent or received - you will have to "find" it amidst a longer recording containing noise.
Your thread/loop strategy is probably roughly as close as you're going to get. However, 10ms is not a lot of time, most Android devices are not super-powerful, and a Fourier transform is a lot of work to do. I find it unlikely that you'll be able to fit that much work in 10ms. I suspect you're going to have to increase that period.
i changed your code so that it takes the execution time of doUpdate into account. The use of System.nanoTime() should also increase accuracy.
public void run() {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
long executeTime=0;
long nextTime = System.nanoTime();
manualAnalyzer.measureStart();
while (FFTransforming)
{
if(System.nanoTime() >= nextTime)
{
executeTime = System.nanoTime();
//Perform Fourier Transform
manualAnalyzer.doUpdate(0);
//TODO: Analyze the results of the transform here...
executeTime = System.nanoTime() - executeTime;
//guard against the case that doUpdate took longer than 10ms
final long i = executeTime/10000000;
//set the timer to execute again at the next full 10ms intervall
nextTime+= 10000000+ i*10000000
}
}
manualAnalyzer.measureStop();
}
What else could you do?
eliminate Garbage Collection
go native with the NDK (just an idea, this might as well give no benefit)

Problem synchronizing sound and display

I have an app that plays an mp3 file and I'm trying to update a custom field in synchrony with certain times we have tabulated for the sound playback (kind of like a karaoke effect). I'm using a Handler to schedule these updates. In my custom field class, I define a Runnable that is supposed to run the update at the right time:
private final Runnable mTrigger = new Runnable() {
#Override
public void run() {
int now = mPlayer.getCurrentPosition();
if (mState == STATE_PLAYING && mUpdateAction != null) {
if (mTriggerTime - now > MAX_PREMATURE_TRIGGER) {
// Sound is lagging too much; reschedule this trigger
mHandler.postDelayed(this, mTriggerTime - now);
} else {
// Run the update
mUpdateAction.run();
}
}
}
};
When I call mPlayer.start() I schedule the first update by calling mHandler.postDelayed(mTrigger, timeToFirstUpdate). Each update action decides what the next update will be and schedules it (by calling mHandler.postDelayed(mTrigger, timeToNextUpdate)). The updates times are typically a few hundred milliseconds apart.
The problem is that, while some updates are happening promptly at the scheduled times, others can be delayed by 200 milliseconds or more, which is quite noticeable to the user. I'm not doing anything in my app between these updates other than playing the sound. (No background worker threads; no other display updates.) The delays appear to be random and vary considerably each time through.
I didn't think that the timing for postDelayed would be this imprecise! I don't know if this is an emulator issue or a problem with my approach. Does sound playback screw up the timing of the UI thread loop? Should I move the timing into a background thread (and is it safe to call mPlayer.getCurrentPosition() from a background thread)? Something else?
After much experimenting, it seems like the problem is the emulator. When I ran everything on a speedier workstation, the problem seems to have gone away.

Metronome Timer slowdown (via Handler, or Threads too)

I have a simple, classic, statement that every 200 milliseconds plays a sound (a metronome).
I wrote it using Handlers, and then in another way, using Threads.
The problem is the same in both ways: when I press hardware home button, or also simply when I press a button to open a ListView, the metronome terribly slowdown for a while.
This problem (not so strong, but however present) presents also doing nothing and leaving the application in foreground.
Any ideas?
Here's the code:
public class Metronome implements Runnable{
private Handler mHandler = new Handler();
public static long mStartTime;
Main mainContext;
public Metronomo(Main context) {
mainContext = context;
}
public void play() {
mStartTime = System.currentTimeMillis();
mHandler.postDelayed(this, 100);
}
public final void stop(){
mHandler.removeCallbacks(this);
}
public void run(){
//play the ogg file in position 1
mSoundManager.playSound(1);
//reschedule the next playing after 200ms
mHandler.postAtTime(this, SystemClock.uptimeMillis() + 200);
}
};
Are you using some kind of pause statement to wait between beats? You could try basing the timing on multiples of a system clock value instead. That way you may still get beats that occur late (or not at all) but you wouldn't get a slow down. Hope that makes some kind of sense.
This is more of a comment but I don't have enough rep to leave comments just yet.
My phone seems to be able to play midi files, which are a pretty compact way to represent sound, perhaps you could dynamically create one and use that for the metronome? I'm assuming that the synthesis is handled at a lower level than would ordinarily be accessible to you so that the timing would be better, but I don't know that for a fact.
When this play sound is called
mSoundManager.playSound(1);
Android waits until that call is finished, then you call
mHandler.postAtTime(this, SystemClock.uptimeMillis() + 200);
however, if you reverse those calls, you may find that the timing is more accurate.
mHandler.postAtTime(this, SystemClock.uptimeMillis() + 200);
mSoundManager.playSound(1);
You can't count on your sound taking exactly the same amount of time to play, so telling the handler to post first is a bit better. Still not ideal, however.
Another consideration is that you're re-computing uptime and adding some more time to that (200 in this case). Why not use the modulus operator on your uptime, to ensure that your next requested post time is more precisely scheduled?
long divisions = SystemClock.uptimeMillis() % 200; // precisely scheduled event timings since system boot.
long nextDivision = divisions + 1; // the next desired event timing
mHandler.postAtTime(this, nextDivision * 200); // scaled back up to number of milli seconds
// now do more heavy lifting that would otherwise have affected uptimeMillis call
mSoundManager.playSound(1);

Categories

Resources