Android Async task slowing down my UI Thread - android

I am new to Android Application development and was having a problem with Async tasks.
So I'm trying to create an ECG graphing application that does some background processing while the graphing is happening.
I've defined the following Async task -
private class Erosion extends AsyncTask <Void,Void,Void> {
#Override
protected Void doInBackground(Void...unused ) {
int i,tempIndex;
double[] tempArray = new double[13];
double min = ecgSamples[ecgSampleForErosionIndex] - gArray[0];
while (ecgIncoming)
{
if (ecgSampleForErosionIndex > 179999)
{
ecgSampleForErosionIndex = 0;
}
for(i= 0;i<13;i++)
{
tempIndex = ecgSampleForErosionIndex + i;
if (tempIndex > 179999)
{
tempIndex = (ecgSampleForErosionIndex + i) - 180000;
}
tempArray[i] = ecgSamples[tempIndex] - gArray[i];
if (tempArray[i] < min)
{
min = tempArray[i];
}
}
//min needs to be stored in the erosionFirst Array
if (erosionFirstArrayIndex > 179999)
{
erosionFirstArrayIndex = 0;
}
ecgErosion[erosionFirstArrayIndex] = min;
erosionFirstArrayIndex++;
ecgSampleForErosionIndex++;
}
return null;
}
} //End of Async Task
So all I'm trying to do is modify the content of a particular array in the async task - i dont need to update the UI (at least not for now)
However, when I run this async task my ECG graphing slows down and becomes jerky. When I comment out the "new Erosion().execute();" part in the code where I start the Async task, the graphing becomes normal again.
Isn't an async task supposed to be on a separate thread and so not affecting how things are happening on my UI thread? What am I doing wrong?

Even if you run a heavy piece of code on a background thread it will still affect the CPU load of the device and therefore might cause delays in your UI thread as well, specially if the device has single-core CPU.
It seems like you have a very heavy loop in you doInBackground method, which runs constantly and just use the CPU nonstop, which overloads it. I'm not sure what this loop is for, but if it doesn't have to refresh constantly you might want to consider adding a thread sleep, allowing other threads to get more CPU time :
while (ecgIncoming)
{
... do your thing ...
Thread.sleep(100); // wait for 100 milliseconds before running another loop
}
Obviously the "100" is just a number, if the array can update once a second, make it a 1000, etc...

By any chance are you running new Erosion().execute(); multiple times? That might cause it because you are allocating a new AsyncTask multiple times.

Related

Updating a chart from an ArrayList over time?

I have an ArrayList of values, and I would like to iterate through the ArrayList. For every new value, I would like to update the chart with that value, and then wait a set amount of time before doing the same thing to the next value.
At the moment, my log says that all of the values are being iterated over. However, on my testing device, the chart does not update until the very end; at that point, all of the values are loaded at once, so there is no desired "slideshow" effect.
When I want to start playing back the values in my ArrayList, this method is called:
public void playback(){
if(ret != null) {
for (int x = 0; x < ret.size(); x++) {
addEntry(ret.get(x));
try {
Thread.sleep(100);
} catch (Exception e){
//Do nothing
}
}
} else {
Log.d(LOG_TAG, "ret was null.");
}
}
What can I do so that the values are displayed on my chart, one after another, with a certain amount of time between each value?
Edit: Here was the solution I ended up implementing with help from Shadab Ansari:
public void playback(){
if(ret != null) {
addEntry(0);
} else {
Log.d(LOG_TAG, "ret was null.");
}
}
private void addEntry(int index) {
final int in = index;
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
yVals1.get(0).setVal(ret.get(in).intValue());
RadarDataSet set1 = new RadarDataSet(yVals1, "Set 1");
// And other UI stuff
// Recursive call!
if(in < ret.size() - 1){
addEntry(in + 1);
}
}
}, 100);
}
In case it was not clear, ret was a global variable that contained the arrays that I was going to be inserting. yVals1 was an ArrayList of Entries to populate the radar chart.
The end result is that, in this example code, the chart is updated with the next value in my ArrayList every 100 milliseconds. During this time I can still zoom in/out of the chart and rotate it with no problems.
If your addEntry() performs a UI operation then let me explain your problem -
Explanation -
Android is an event based system. Something happens on the device (the screen is touched, a key is pressed, etc.) and Android raises an event. An App is notified of an event and when one occurs that it needs to respond to it does so, often running the code that you have written. Your App runs its code in a loop under the control of the Android Operating Systems (OS). This code loop is referred to as the App's thread of execution. There is only one thread and it is responsible for both running the App code and updating the display.
So the UI update does not happen immediately and your making the UI thread sleep for 100 ms every time the loop runs. And when Android tries to update the UI, you make the thread sleep which means during this time period UI thread will not do anything. And this happens till your loop finishes. After your loop ends, the final event gets executed and you will see your UI updated by the call of addEntry() with the latest value passed.
Solution -
You can use postDelayed()-
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//Perform your task and it will be executed after 100 ms
}
},100);

Android AsyncTask waiting/queued

I have a class extending an AsyncTask that sends messages to a WCF web service. Simple messages one by one will work fine, but if I send a message on a new thread that takes 30 seconds to complete, then midway through that I send a quick request it won't execute the AsyncTask until the long one has returned.
I thought the whole idea of AsyncTask was these two messages would run on different threads and therefore wouldn't stack?
Here is my code:
private class RunnableTask extends AsyncTask<RunnableObj, RunnableObj, RunnableObj> {
#Override
protected RunnableObj doInBackground(RunnableObj... params) {
try {
if (params[0].requestBody != (null)) {
params[0].request.body(new JSONObject(params[0].requestBody));
}
params[0].request.asVoid();
return params[0];
}
catch (Throwable e) {
params[0].handler.onFailure(e);
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(RunnableObj runnableObj) {
super.onPostExecute(runnableObj);
runnableObj.handler.onSuccess();
}
}
This is my AsyncTask above.
public void put(final String urlStr, final String requestBody, final HttpResponseHandler httpResponseHandler) {
RunnableObj obj = new RunnableObj();
obj.handler = httpResponseHandler;
obj.request = webb.put(urlStr)
.header(ServiceConstants.SessionTokenHeader, MyApplication.getSessionToken())
.ensureSuccess();
obj.requestBody = requestBody;
new RunnableTask().execute(obj);
}
This is the method I use to call the Async.
As you can see in the method I use to call the service, I initialise a new instance of RunnableTask each time.
How it performs:
The long request will go to the web service and start it's 30 seconds of doing things.
10 seconds later my quick little PUT creates it's object, then the last thing the debugger shows is the break point on the "new RunnableTask().execute(obj);" line and then it just disappears.
20 seconds later the first line of my RunnableTasks doInBackground method will hit and it will perform the PUT.
Please can someone help? Or at least tell me I'm doing something very stupid..
You can execute multiple AsyncTask by using executeOnExecutor
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
new MyAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
new MyAsyncTask().execute();
}
For more check the AsyncTask documentation
According to the AsyncTask Docs:
When first introduced, AsyncTasks were executed serially on a single
background thread. Starting with DONUT, this was changed to a pool of
threads allowing multiple tasks to operate in parallel. Starting with
HONEYCOMB, tasks are executed on a single thread to avoid common
application errors caused by parallel execution.
If you truly want parallel execution, you can invoke
executeOnExecutor(java.util.concurrent.Executor, Object[]) with
THREAD_POOL_EXECUTOR.
As you can see, AsyncTasks currently only operate on a single background thread, meaning multiple queued tasks will have to fire one after another. If you would like to execute concurrent tasks, you'll want to follow the instructions above.

When to use AsyncTask and When to use Thread in Android

When to use AsyncTask and When to use Thread as both do work in background and both can manipulate controls in UI Thread by some mechanism..
May this help you:
For long-running tasks, we use Java threads, and Android's native AsyncTask.
Basically Use AsyncTask for:
Simple network operations which do not require downloading a lot of data
Disk-bound tasks that might take more than a few milliseconds
And Use Java threads for:
Network operations which involve moderate to large amounts of data (either uploading or downloading)
High-CPU tasks which need to be run in the background
Any task where you want to control the CPU usage relative to the GUI thread
For more information refer
Mohit's answer Click Here
Edit:
Service is like an Activity but has no interface. Probably if you want to fetch the weather for example you won't create a blank activity for it, for this you will use a Service. Service is access to a Context object which has an independent life cycle. This allows for reuse of common code by many activities and, in the case of public or exposed services in many applications.
A Service runs on the main thread of the calling Component’s process by default (and hence can degrade responsiveness and cause ANRs), hence you should create a new Thread to perform long running operations.
A Thread is a Thread, probably you already know it from other part. You need to know that you cannot update UI from a Thread. You need to use a Handler for this and stopping a thread sometime become problematic also. A thread is a mechanism for doing work without blocking other work...
A service does not imply a thread and a thread does not imply a service. Both are different from eachother..
An AsyncTask is an intelligent Thread that is advised to be used. Intelligent as it can help with it's methods, and there are two methods that run on UI thread, which is good to update UI components.
AsyncTask is just a "helper" class provided with Android SDK to make it easier to skip to the UI thread after the background task is finished. It is built over the standard Java threading API. It does not give antyhing that cannot be done with Threads only. It addresses the common scenario of switching between the short task run background thread and UI thread.
Generally it is convenient to use AsyncTask when you must "skip back" to UI thread when the background task is done or when you have to give some feedback to UI thread during task execution. Otherwise it's just overhead.
You are not forced to use AsyncTask. If you as a developer prefer using Threads directly or Futures you may use it and skip to UI thread on your own manually after the background task is done.
EDIT:
Some other answers here suggest that using AsyncTask should be limited to short tasks. Allegedly because it uses a common pool. However it is no longer true since API Level 11 (so, for quite a long time). You can use executeOnExecutor instead of execute to execute AsyncTask's in dedicated thread pool. See http://developer.android.com/reference/android/os/AsyncTask.html#executeOnExecutor%28java.util.concurrent.Executor,%20Params...%29
Because examples are usually more communicative look at the example below.
Let's assume that we have a static function to do some heavy task and a TextView which we want to display progress and final status of the task declared as below:
static Object doHeavyTask(String string) throws Exception;
TextView progressInfo;
Execution of the task in background thread using async task would look like:
new AsyncTask<String, Integer, Exception>() {
#Override
protected Exception doInBackground(String... params) {
for (int i = 0; i < params.length; i++) {
try {
doHeavyTask(params[i]);
} catch (Exception e) {
return e;
}
publishProgress(i, params.length);
}
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
progressInfo.setText("Executed " + values[0] +
" of " + values[1] + " tasks.");
}
#Override
protected void onPostExecute(Exception result) {
if (result == null) {
progressInfo.setText("Heavy background job done successfully!");
}
else {
progressInfo.setText("Heavy background job failed!" +
"Exception message: " + result.getMessage());
}
}
}.execute("input1", "input2", "input3");
Exactly the same can be achieved with Thread:
final Handler handler = new Handler(Looper.getMainLooper());
final String[] params = { "input1", "input2", "input3" };
new Thread() {
#Override
public void run() {
for (int i = 0; i < params.length; i++) {
try {
doHeavyTask(params[i]);
} catch (final Exception e) {
handler.post(new Runnable() {
#Override
public void run() {
progressInfo.setText("Heavy background job failed!" +
"Exception message: " + e.getMessage());
}
});
return;
}
final int currentIndex = i;
handler.post(new Runnable() {
#Override
public void run() {
progressInfo.setText("Executed " + currentIndex +
" of " + params.length + " tasks.");
}
});
}
handler.post(new Runnable() {
#Override
public void run() {
progressInfo.setText(
"Heavy background job done successfully!");
}
});
}
}.start();
As you see above using the AsyncTask is simply a bit more convenient. But there is no other advantage, just this convenience :).
If you prepared your own task encapsulating Thread (and a Handler to skip back to the UI thread) then maybe your class will be more efficient/comfortable for you to use.
That's all :).
You can run multiple threads concurrently. But asynctask is queued, meaning it is running one task at a time.

Async Task Memory Cleanup

I am having a bit of trouble with how to cleanup the memory used in my AsyncTask when the user forces the application to quit or go to the background.
Specifically, I have an app that is using an AsyncTask to record audio data and graph the signal in realtime. For the recording I am using the AudioRecord class, which requires you to start a recording, and then stop and release the recording object. My problem is that I do not know how to stop and release this object.
Options I have thought about and tried:
Stopping the releasing the object in the onPause, onStop, and onDestroy methods, but this causes an exception.
Stopping and releasing the object in the onPostExecute method of AsyncTask. The problem with this is I am not sure if this method is ever called when the user force quits the app, since the doInBackground method is never finished. I have not been able to find any documentation concerning this.
My AsyncTask looks as follows:
AsyncTask<Void, Void, Void> drawer = new AsyncTask<Void, Void, Void>() {
#Override
protected void onPreExecute() {
super.onPreExecute();
recorder.startRecording();
}
#Override
protected Void doInBackground(Void... arg0) {
while(true) {
int nRead = 0;
int offset = 0;
while(nRead != readSize) {
nRead += recorder.read(buffer, offset + nRead, readSize - nRead);
}
for(int i = 0; i < readSize; i++) {
data[i] = buffer[i];
}
publishProgress();
}
}
#Override
protected void onProgressUpdate(Void... arg0) {
view.setData(data);
view.invalidate();
}
};
The code works great, I am just unsure the best way to make sure I properly clean up the recording object and don't leak at all. My confusion is just as to what happens to an AsyncTask when the UI Thread is paused or stops, and additionally, if you are able to stop an AudioRecord Object from a different Thread you stared it.
Any help would be greatly appreciated.
Thank you,
OnPostExecute will not be called because you never finish your background loop. You need to have a condition on which you exit your loop. You can have a variable you set in the UI and then check in the background task, or use the ability to cancel AsyncTask.
For example, in your onPause() method, you can cancel the task with drawer.cancel(true);
Then, in your doInBackground loop, check to see if the task has been cancelled.
if (isCancelled()) {
// clean up here
break;
} else {
publishProgress();
}
This works as long as you do not need to touch the UI for clean up. If you need to do UI clean up, then you can override the onCancelled method.
Note, for long running tasks, it is recommended that you do not use AsyncTask. So you may want to look into using threads. From AsyncTask documentation,
AsyncTasks should ideally be used for short operations (a few seconds
at the most.) If you need to keep threads running for long periods of
time, it is highly recommended you use the various APIs provided by
the java.util.concurrent pacakge such as Executor, ThreadPoolExecutor
and FutureTask.

Android: Pause the thread for several seconds

ExecutorService exec = Executors.newFixedThreadPool(8);
List<Future<Object>> results = new ArrayList<Future<Object>>();
// submit tasks
for(int i = 0; i < 8; i++) {
results.add(exec.submit(new ThreadTask()));
}
...
// stop the pool from accepting new tasks
exec.shutdown();
// wait for results
for(Future<Object> result: results) {
Object obj = result.get();
}
class ThreadTask implements Callable<Object> {
public Object call() {
// execute download
//Inside this method I need to pause the thread for several seconds
...
return result;
}
}
As shown above in the comment I need to pause the thread for several seconds. Hope you can help me with this.
Thanks for your time!
Just call Thread.sleep(timeInMillis) - that will pause the current thread.
So:
Thread.sleep(5000); // Sleep for 5 seconds
Obviously you shouldn't do this from a UI thread, or your whole UI will freeze...
Note that this simple approach won't allow the thread to be woken up other by interrupting it. If you want to be able to wake it up early, you could use Object.wait() on a monitor which is accessible to whichever code needs to wake it up; that code could use Object.notify() to wake the waiting thread up. (Alternatively, use a higher-level abstraction such as Condition or Semaphore.)
you could implement a new thread, which is not the UI thread..
something like this might do it for you..
class ThreadTask implements Callable<Object> {
public Object call() {
Thread createdToWait= new Thread() {
public void run() {
//---some code
sleep(1000);//call this function to pause the execution of this thread
//---code to be executed after the pause
}
};
createdToWait.start();
return result;
}

Categories

Resources