Time an Android thread in a better way? (runs out of sync) - android

Hey I am currently designing an app where some code gets executed every 200ms. The thread I use for this looks like this (simplified):
final Handler handler = new Handler();
Runnable runnable = new Runnable()
{ public void run()
{
handler.postDelayed(this, 200);
switch (status){
case 1: check(1);p2.setBackgroundColor(0x00000000); p1.setBackgroundColor(0xDDCC0000); status = 2; break;
case 2: check(2);p1.setBackgroundColor(0x00000000); p2.setBackgroundColor(0xAAAA0000); status = 1; break;
}
}
}; runnable.run();
check() contains some non-UI code lines.
The problem is, that the postDelayed-200-ms start, when the queue is fully executed and not at the beginning so all time that the system needs to execute the commands stacks and stacks all the time so these are actually ~210-230ms (depending on CPU load)
Then I tried to get the system date at the beginning of the thread and add 200ms to it but this results in some other, "heavier" errors.
I have no problem with more than 200ms delay, I just want to get it running stable.
I hope you understand my problem and can give some advice to me.
EDIT: I know got to know that the Handler runs acceptable (delay of 4ms on 200ms). The problem are the methods I am calling then. I will open a new question

If check() contains non-ui code lines then you should run those in a separate thread.
The bottom line is that the UI thread is *really busy, so, you can ask it to do something every 200ms but you aren't guaranteed any precision since the Device is doing its best to do all sorts of other things. When you say "heavier problems" what do you mean exactly?
I would try to start a Thread and just Log every 200ms to see if the device is willing to accurately do *anything at the rate you wish. If it does, then you can send messages to the UI thread to draw and if you find that its the drawing that is delayed, then perhaps you need to reduce your delay to give the UI thread time to finish drawing? (obviously this is also highly imprecise and will vary wildly from device to device).

Did you try doing it using Timers? A basic implementation would look like
new Timer().scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
// TODO Auto-generated method stub
}
}, 200, 200);
You can try using the alarm service as well. that should give you accurate (or at least consistent) results.

Related

How to add a delay inside the Executor bound to CameraX's analyzer?

Inside my overridden analyze() I need to add some kind of throttle before performing an IO operation. Without the throttle, this operation gets executed immediately at each call of analyze() and it actually completes quickly, but apparently the calls are too fast and after a while the camera preview freezes for eternity (the app is still running because Logcat keeps displaying new messages).
I'm currently investigating if it has something to do with my code, like forgetting to call imageProxy.close(). So far everything seems fine and I'm afraid the device that performs the IO operation is raising too many interrupts for the CPU to handle, or something along the lines.
I've tried the good old Thread.sleep() but obviously it blocks the main thread and freezes the UI; I've seen some examples with Handler#postDelayed() but I don't think it does what I want; I've tried wrapping the IO call in a coroutine with a delay() at the beginning but again I don't think it does what I want. Basically I'd like to call some form of sleep() on the Executor thread itself, from within the code executed by it.
after a while the camera preview freezes for eternity
I've seen this issue occur many times, and it's usually due to an image that the Analyzer doesn't close. Are you seeing the issue even when the image analysis use case isn't used?
I've tried the good old Thread.sleep() but obviously it blocks the main thread and freezes the UI
Why's that? This shouldn't be the case if you're adding the call to Thread.sleep() inside Analyzer.analyze(), since it'll block the thread of the Executor you provided when calling ImageAnalysis.setAnalyzer(), which shouldn't be tied to the main thread.
One option to perform analysis fewer times is to drop images inside the Analyzer, something like the following:
private static final int ANALYSIS_DELAY_MS = 1_000;
private static final int INVALID_TIME = -1;
private long lastAnalysisTime = INVALID_TIME;
public void analyze (ImageProxy image) {
final long now = SystemClock.uptimeMillis();
// Drop frame if an image has been analyzed less than ANALYSIS_DELAY_MS ms ago
if (lastAnalysisTime != INVALID_TIME && (now - lastAnalysisTime < ANALYSIS_DELAY_MS)) {
image.close();
}
lastAnalysisTime = now;
// Analyze image
image.close();
}
There is one more way, This is how I am doing it in a local project. So in my Image Analyzer, I am rebinding the camera using Handler#PostDelayed and this gives a small black screen in preview, but it won't process the next image that quickly.
My use case was that I had to continuously scan barcodes, but the scanning was too fast and it kept on scanning one code many times. So, I just needed 100ms wait. So this works out for me.
try {
cameraProvider.unbindAll()
Handler(Looper.getMainLooper()).postDelayed({
cameraProvider.bindToLifecycle(
this, CameraSelector.DEFAULT_BACK_CAMERA, useCaseGroup.build())
}, 100)
}
catch(exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}

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

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

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.

what to substitute for thread.sleep

I have a for loop as part of a background thread in my code. Part way through execution of the code within the loop I want a wait period so I call thread.sleep. I've discovered that if the phone display closes during the wait period the wait time becomes erratic. According to the documentation sleep is not time reliable. So I am wondering what to substitute. As far as I can see if I create a post delayed sub thread I will loose the continuity within the for loop. I hope I am wrong and have'nt understood the mechanics properly - any help appreciated.
Ron
One way to deal with the unreliability of sleep() is to add code to measure the actual time you slept. This is often done in animations where a decision can be made to, for instance, skip some number of frames to catch up to real time.
Can you just use Handler and call postDelayed? I honestly can't claim how reliable that will be or if it fits your problem but I use it for small regular updates.
You might also look into Partial Wake Locks to see if that might give you more reliable performance.
You need something like this:
(...)
Message msg = new Message();
try {
myHandler.sendMessageDelayed(msg,1000);
} catch (Exception e) {
Log.d(TAG,"Hum?",e);
}
}
}
private Handler myHandler= new Handler() {
/*
* (non-Javadoc)
*
* #see android.os.Handler#handleMessage(android.os.Message)
*/
#Override
public void handleMessage(Message msg) {
//DO WHAT YOU WANT..
}
};

Categories

Resources