AsyncTask: Task 6 to 15 not starting (but running) - android

I was testing AsyncTask details and stumbled on the issue that when I start muliple tasks, the tasks 6 to 15 (10 tasks always) are in status RUNNING, but do not get into doInBackground (where the start time is set). The next 100 tasks are started immediately.
(source: beadsoft.de)
The tasks are started pretty simple:
int tasksToStart = TASKS_TO_ADD_ON_CLICK;
while (tasksToStart > 0) {
tasksToStart--;
mTask = new MyTask(TASK_RUNNING_TIME);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
mTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
mTask.execute();
tvTaskInfo.setText("Task " + mTask.id + " requested.");
}
This leads to the situation that all later started tasks have to be finished (meaning total running tasks is less than 5) before tasks 5 actually starts doing something.
a) Is there a way to force start the tasks?
b) Why is the status RUNNING if it does not do anything. Should it not be PENDING?
I do not have an android 4.x real device and cannot test there. In the emulator same limitations apply.
Anyone interested can download this sample project here.

If you wish to run multiple AsyncTasks more than 5 (which is the default Executor limit), you need to start it with a different Executor, like this:
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
The THREAD_POOL_EXECUTOR Allows you to execute up to 15 parallel AsyncTasks, whereas SERIAL_EXECUTOR only allows up to 5, in serial order.

Related

Scheduling a background task periodically on Android

I'm working on an app where I have to read data from multiple sensors and send it to a remote server every 15 minutes. This has to be done when the app is closed/killed as well and I also have to be sure it always executes. I also want to be sure it happens (almost) exactly every 15 minutes (+-1 minute difference is the upper limit).
At this point, I've found 3 options: using Workmanager, Alarmmanager or using a foreground service. Following the documentation, Workmanager seems the way to go for background tasks, however, after having done some reading, Alarmmanager seems to be a safer choice (Workmanager sometimes has troubles with doze mode, and the timing isn't exact because it uses a flex period of at least 5 minutes). And a foreground service is not really allowed for this kind of task (it's not really long running, it's just a periodic task) and is being limited in newer Android versions. Do you think it would be a good idea to use an Alarmmanger for this task, or should I use something else? Thanks!
TODO Background scheduling.. You can use this method todo your stuff..
KOTLIN;
val service = Executors.newSingleThreadScheduledExecutor()
val handler = Handler(Looper.getMainLooper())
service.scheduleAtFixedRate({
handler.run {
// Do your stuff here, It gets loop every 15 Minutes
}
}, 0, 15, TimeUnit.MINUTES);
JAVA;
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
Handler handler = new Handler(Looper.getMainLooper());
service.scheduleAtFixedRate(() -> {
handler.post(() -> {
// Do your stuff here, It gets loop every 15 Minutes
});
}, 0, 15, TimeUnit.MINUTES);

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

Android NDK Sensor strange report interval to event queue

I try to access the accelerometer from the NDK. So far it works. But the way events are written to the eventqueue seems a little bit strange.
See the following code:
ASensorManager* AcquireASensorManagerInstance(void) {
typedef ASensorManager *(*PF_GETINSTANCEFORPACKAGE)(const char *name);
void* androidHandle = dlopen("libandroid.so", RTLD_NOW);
PF_GETINSTANCEFORPACKAGE getInstanceForPackageFunc = (PF_GETINSTANCEFORPACKAGE) dlsym(androidHandle, "ASensorManager_getInstanceForPackage");
if (getInstanceForPackageFunc) {
return getInstanceForPackageFunc(kPackageName);
}
typedef ASensorManager *(*PF_GETINSTANCE)();
PF_GETINSTANCE getInstanceFunc = (PF_GETINSTANCE) dlsym(androidHandle, "ASensorManager_getInstance");
return getInstanceFunc();
}
void init() {
sensorManager = AcquireASensorManagerInstance();
accelerometer = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_ACCELEROMETER);
looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
accelerometerEventQueue = ASensorManager_createEventQueue(sensorManager, looper, LOOPER_ID_USER, NULL, NULL);
auto status = ASensorEventQueue_enableSensor(accelerometerEventQueue,
accelerometer);
status = ASensorEventQueue_setEventRate(accelerometerEventQueue,
accelerometer,
SENSOR_REFRESH_PERIOD_US);
}
That's how I initialize everything. My SENSOR_REFRESH_PERIOD_US is 100.000 - so 10 refreshs per second. Now I have the following method to receive the events of the event queue.
vector<sensorEvent> update() {
ALooper_pollAll(0, NULL, NULL, NULL);
vector<sensorEvent> listEvents;
ASensorEvent event;
while (ASensorEventQueue_getEvents(accelerometerEventQueue, &event, 1) > 0) {
listEvents.push_back(sensorEvent{event.acceleration.x, event.acceleration.y, event.acceleration.z, (long long) event.timestamp});
}
return listEvents;
}
sensorEvent at this point is a custom struct which I use. This update method gets called via JNI from Android every 10 seconds from an IntentService (to make sure it runs even when the app itself is killed). Now I would expect to receive 100 values (10 per second * 10 seconds). In different tests I received around 130 which is also completly fine for me even it's a bit off. Then I read in the documentation of ASensorEventQueue_setEventRate that it's not forced to follow the given refresh period. So if I would get more than I wanted it would be totally fine.
But now the problem: Sometimes I receive like 13 values in 10 seconds and when I continue to call update 10 secods later I get the 130 values + the missing 117 of the run before. This happens completly random and sometimes it's not the next run but the fourth following or something like that.
I am completly fine with being off from the refresh period by having more values. But can anyone explain why it happens that there are so many values missing and they appear 10 seconds later in the next run? Or is there maybe a way to make sure I receive them in their desired run?
Your code is correct and as i see only one reason can be cause such behaviour. It is android system, for avoid drain battery, decreases frequency of accelerometer stream of events in some time after app go to background or device fall asleep.
You need to revise all axelerometer related logic and optimize according
Doze and App Standby
Also you can try to work with axelerometer in foreground service.

Need help understanding 'RejectedExecutionExemption'

I am running some async tasks and 1 of my users is crashing with a RejectedExecutionExemption:
Stack Trace
stackTrace: java.util.concurrent.RejectedExecutionException: Task android.os.AsyncTask$3#5e2675f rejected from java.util.concurrent.ThreadPoolExecutor#f5f25ac[Running, pool size = 9, active threads = 9, queued tasks = 128, completed tasks = 240]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2014)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:794)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1340)
at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:607)
The Line causing the exception
new SetDownloadStatusTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
Two Part question here really..
I'd like like some help understanding the first line of the exception:
ThreadPoolExecutor#f5f25ac[Running, pool size = 9, active threads = 9, queued tasks = 128, completed tasks = 240]
pool size vs. active threads vs quad tasks.. I assume I am executing too many tasks, but am unsure how to determine this really for those three variables. If someone could break that down for me, Id appreciate it.
If this is the case that I am running out of threads, should I increase the amount allowed and if so how, or is there a better solution.
Custom AsyncTask
private class SetDownloadStatusTask extends AsyncTask<Void, Void, DownloadStatus> {
#Override
protected DownloadStatus doInBackground(Void... params) {
return bookDownloadManager.status(product);
}
#Override
public void onPostExecute(DownloadStatus downloadStatus) {
updateMenuForDownloadStatus(downloadStatus);
}
}
I assume I am executing too many tasks
Correct.
If someone could break that down for me, Id appreciate it
AsyncTask.THREAD_POOL_EXECUTOR, on a quad-core CPU, will support nine parallel threads (pool size = 9). That is backed by a LinkedBlockingQueue of maximum length 128. And, you have requested your 138th simultaneous task, so we are out of threads (active threads = 9) and the queue is full (queued tasks = 128).
should I increase the amount allowed and if so how, or is there a better solution
You should be asking yourself "why in the name of all that is holy am I trying to download 138 things at once?".
If there is a legitimate need for that, use your own custom Executor, rather than THREAD_POOL_EXECUTOR. If there is not a legitimate need for 138+ simultaneous downloads — and, frankly, that number seems insane — then change your code to avoid doing that, such as cancelling tasks that you no longer need.

Android Dev: Timer not honoring dynamic interval period

im working on a audio profile switcher for android and as part of the entire project, i have a service that is running in the background using the following timer code:
timer.scheduleAtFixedRate( new TimerTask() {
public void run() {.....}, 0, nextUpdateInterval);
what im noticing is that the timer is not honoring the dynamically generated next update interval period...the nextUpdateInterval is declared as private static long which is initialized to 30000 (30 seconds) for the first run....then once a profile is found, i do some math and update the nextUpdateInterval...i have converted the nextUpdateInterval value back out to hours/minutes for debugging purpose, and the calculation is working as expected...like it shows me in hours and minutes, when the next timer execution should take place...
nextUpdateInterval calculation: long entirePeriodDiff = toTimeMiliseconds - fromTimeMiliseconds;
then once a profile is found, i calculate the elapsedTime like so: long elapsedTime = rightNowDate.getTime() - fromDate.getTime();
and then i update the nextUpdateInterval: nextUpdateInterval = entirePeriodDiff - elapsedTime;
one example scenario: Profile of 'Work' is set from 9AM to 4:30PM, the service/app is executed at 2:02PM (EST), my toast message is executing constantly and is acting as a count down telling me how much time is left...in this case 2:28 and decreasing...ideally this should not display until the 2:28 is up...any ideas?
As per android doc:
With fixed-rate execution, the start time of each successive run of a task is scheduled without regard for when the previous run took place. This may result in a series of bunched-up runs (one launched immediately after another) if delays prevent the timer from starting tasks on time.
I think that could be the reason, may be you need to consider alternative 'fixed period'

Categories

Resources