Android problems with out-of-order multithreaded processing and dialogs - android

I seem to have consistent problems with timing threads and dialog windows. I've tried using a thread, or onCreate/onPrepare, or an AsyncTask to do some downloading/processing in the background. More often than not, when the background processing completes and dismisses the dialog window, control seems to return to the root thread (Activity/UI thread?) before the dialog is gone or the onPostExecute-like process is done. This makes me think I'm doing it incorrectly. Here is a typical structure (pseudo-code):
public class X {
protected String result = null;
protected ProgressDialog progressDialog;
public void onCreate() {
...
new XTask().execute();
progressDialog.show();
// result is null here, should be "hi"?
// do things with result, like barf on a NPE...sigh
}
private class XTask extends AsyncTask {
protected doInBackground() {
// Get URL.
// Look at contents, takes a few seconds.
// Return the result (should get sent to onPostExecute).
}
protected onPostExecute(r) {
result = r;
progressDialog.dismiss();
}
}
}
I would think that, after doPostExecute sets result and dismisses the dialog, processing then continues in the onCreate method. However, result is often (not always) null at this point in onCreate. Is there a better way to do this? Is this just due to the general crappiness of the emulator?
Thanks.
Edit: To be more concrete, my task (in doInBackground) fetches a URL and does a little processing on the response. This process takes 1-3 seconds. Then, theoretically, onPostExecute sets X.result to what was fetched. I know the URL content is valid and the response is good (not null). The problem is that during those 1-3 seconds, control returns to onCreate, as if the progressDialog never lived at all (it doesn't get displayed in the emulator at all, but that's normal I guess).
I had thought that calling dialog.show() was a blocking method, i.e., the dialog appeared and that method wouldn't continue until it disappeared, but that doesn't seem to be the case. Either my progressDialog.dismiss() is getting called before it should, before setting X.result, or not getting called at all, or dismiss() is happening faster/before the assignment, or something else entirely is going wrong...
Changing the order of the execute and progressDialog doesn't help, nor does moving it into onPreExecute(). Strangely, onPostExecute doesn't get called until I return in onCreate. If I have a Thread.sleep loop after execute (I thought giving it time would help), it never finishes the task until that loop finishes and I return. e.g.:
new XTask().execute();
int z=0;
while (response == null && z < 50) {
Thread.sleep(500);
z++;
}
if (response == null) return;
The task's onPostExecute method doesn't get called until "return". Hmmm...maybe being in onCreate is affecting it.

A ProgressDialog is usually used to block user interaction during loading or heavy processing but the main UI thread will continue to execute.
If you wish to perform some operation on the result you must do it in either onPostExecute of XTask or after you have gotten the result in doInBackground.
private class XTask extends AsyncTask {
#Override
protected void onProgressUpdate(/*params*/){
//modify UI
}
protected doInBackground() {
// Get URL.
// Look at contents, takes a few seconds.
//Option A: Now have the result, do some other processing here
//Cant modify UI components from here, If you need to modify a UI component from
//here call publishProgress() and modify the component in onProgressUpdate()
// Return the result (should get sent to onPostExecute).
}
protected onPostExecute(r) {
result = r;
//Option B do some processing on the result
//You can modify UI components from here
progressDialog.dismiss();
}
}

I would show the progress dialog before triggering the AsyncTask. Normally, when an AsyncTask gets executed, it takes a while to finish itself and in that time, the rest of the task calling method has already run. But in your case the task returns instantly which is probably why the dialog shows up AFTER the postexecute gets called under the AsyncTask.

I would think that, after doPostExecute sets result and dismisses the dialog, processing then continues in the onCreate method.
This is not true, when you call new XTask().execute() in UI thread, application create a worker thread and start running whatever you defied in AsyncTask.doInBackground() on this work thread, at this point (after calling new XTask().execute()), UI thread continue execute code after new XTask().execute().
The point you are talking about where your work thread finish and return to UI thread is AysncTask.onPostExecute(), this method is guaranteed to be called on UI thread after AsyncTask finish. this is the reason why it is called AsyncTask. Both of UI thread and work thread are running asynchronously.
If you want to make your UI thread blocked and wait for AsyncTask finish after XTask().execute(), you can to this:
XTask xTask = new XTask();
xTask.execute();
progressDialog.show();
xTask.get() // <-- this will make your UI thread blocked and wait for AsycnTask at this point
// result is null here, should be "hi"?
This is possible but not a good practice, as AsyncTask.get() will block execution on calling thread so probably get ANR exception.
To sum up
1. AysncTask.onPostExecute() is where process return from worker thread to UI thread, we don't care where and when it will be called on UI thread, we just need ensure it will be called on UI thread properly at some point in the future.
2. AsyncTask.get() by calling this method actually make you AsyncTask running synchronously with the calling thread.

Putting code into the task's onPostExecute should work, a simple test suggests it will (for me). However, I ended up writing a different solution which also works. I put most of the code into a Handler on the activity, which separates it from the UI thread entirely. My onCreate simply shows the loading ProgressDialog window and that's it--it just sits there, "loading". The background task does its thing and when finished, sends a message to the handler. This message tells the handler to dismiss the loading dialog and populate the list. If there are errors, different messages are sent and the handler shows an error dialog.

Related

What is the correct way to pause AsyncTask from the UI-thread

my AsyncTask should wait till event in the UI-thread happen.
so, I started to have simple while loop. However, in some of the devices that caused the UI thread to freeze. so after reading the following answer:
Fatal Spin-On-Suspend/Stuck on ThreadID
[However, it is not quite the same - i put the while in the async-task not in main-activity]
I added Thread.sleep - and it seem to indeed solve the problem.
However, I feel like I'm doing something wrong here...I wonder what is the right way to do it.
Do not ever sleep or block the UI thread. Wait in the background thread of the AsyncTask.
One way is as suitianshi is pointing out with wait()/notifyAll(). Another one is to use a CountDownLatch:
In the UI thread create a latch: CountDownLatch latch = new CountDownLatch(1);
Subclass AsyncTask so that it takes a latch in the constructor and save it to a reference mLatch
in doInBackground(), when you need to wait call mLatch.await(). This will block the AsyncTask
in the UI, when the event you're waiting happens, call latch.countDown()
You should be good to go from here.
My opinion is going to be different...
my AsyncTask should wait till event in the UI-thread happen.
AsyncTask's are great for long running operations like http downloads, long i/o operations, image resizing, or any cpu intensive operation that would freeze the UI thread.
However, Android runs AsyncTasks sequentially and not in a pool by default. More details here.
So if you have an AsyncTask that runs indefinitely, such as waiting for a UI action, you could likely block other AsyncTasks from running. Leading to more deadlock and threading problems.
I would suggest any of the following:
Use a different Executor for your AsyncTask so it runs similarly as it does today, but not to conflict with other AsyncTask items. This is the easiest approach.
Split your AsyncTask up into multiple tasks. The first one does whatever your current AsyncTask does up until the wait. The second one does whatever your current one does after the UI event. The latter task gets queued by the UI that generated the event.
Use a dedicated Thread. Use the Handler class to marshall events back from the thread to the UI thread as appropriate.
AsyncTask is introduced for running things which takes long time. In earlier android OS, it can be done in main thread or UI thread. But now android forces us to do long running things in AsyncTask to make UI thread responsive. If you want during AsyncTask your android UI do nothing then you can simply add progress Dialog during it. Start progress Dialog in onPreExecute() & end it in onPostExecute(String[] result).
Sample code : in AsyncTask
#Override
protected void onPreExecute() {
dialog = new ProgressDialog(MainActivity.this);
dialog.setMessage("Loading, please wait...");
dialog.setIndeterminate(true);
dialog.show();
}
#Override
protected void onPostExecute(String[] result) {
if (dialog.isShowing()) {
dialog.dismiss();
}
// do something with result
}
Thanks

Android Threading (AsyncTasks) acting a little weird

From my main thread, I start an AsyncTask which will go through a list of images and for each image, it will do some processing on it. So basically, there's a for loop and inside it, another AsyncTask is called. I use an instance of a class which holds the boolean value for checking if each image is done with its processing, its called a dummyStructure.
Code of the main thread:
new BatchProcessor().execute()
the doInBackground of the BatchProcessor:
protected Void doInBackground(Void... params){
while(dummyStructure.isWorking())
{
//Try loop
thread.sleep(1000);
}
dummyStructure.setIsWorking(true); //basically sets the flag to true
for(String s: pictureList)
{
RunTheProcessingLoop().execute();
}
The Problem:
I tried debugging, and here's what the problem is imo, if I remove the line just outside the while loop dummyStrucutre.setIsWorking(true) then there are multiple asyncTasks called even before it finishes, and basically everything gets screwed up. However, if I don't remove that line, then the BatchProcessor AsyncTask gets caught in the while loop, while as the RunTheProcessingLoop AsyncTask never executes beyond its onPreExecute()(debugged to know that, I used Log.e() in every method of that asyncTask).
Definitely I'm missing something, any help? Thanks a lot! :)
What you are encountering is asynctasks getting piled up because you are starting one from another and not exiting the first. This is because the asynctasks are handled serially by a single thread by default. If you want to use multiple threads in parallel, you'd need to use your own thread executor. See the AsyncTask documentation for more details.
So after 2 days of posting this question and finding out more about what people posted, I figured this:
My main thread called for an AsyncTask and I wanted to wait for that AsyncTask to finish. So I used a boolean flag which the AsyncTask sets to false once it is done and I can queue another task. Here's the code:
class mExecutor implements Executor {
public void execute(Runnable r) {
new Thread(r).start();
}}
Now, all you need to do is, whatever task/method/etc you want to run Asynchronously, simply create a thread and push it in that class, example:
Thread t = new Thread(new Runnable() {
public void run() {
new someshit().execute();
}
});
new mExecutor().execute(t);
and Tada! Now they both won't be queued/synchronized but would run in parallel.
If I am wrong, please correct me! Thanks! :)

What can cause a AsyncTask not to execute?

I have a very sporadic failure in my app I'm trying to resolve. On entry to the app, at one point the main UI thread processing ends and passes control to a background thread to retrieve some data. When the data is retrieved, control passes back to the main UI thread to process it for display. However, on some rare occassions (it works 99% of the time), the AsyncTask seems to be failing to be called leaving the app in a poor static state forever waiting for the AsyncTask to complete.
Here's a snapshot of the code in the Activity:
//method call from main UI thread
private void fetchSomeData() {
Log.d("myTag", "In fecthSomeData()");
new ReadFileAsyncTask<DataModel>().execute(this);
}
Here's the ReadFileAsyncTask implementation:
public class ReadFileAsyncTask<A> extends AsyncTask<I_ReadFileListener<A>, Void, A>
{
I_ReadFileListener<A> listener;
#Override
#SuppressWarnings("unchecked")
protected A doInBackground(I_ReadFileListener<A>... params)
{
listener = params[0];
Log.d("mytag", "BACKGROUND: Loading " + listener.getFilename() + " from disk");
A fileContents = (A) FileUtils.readDataFromInternalStorage(listener.getContext(), listener.getFilename());
return fileContents;
}
#Override
protected void onPostExecute(A result)
{
Log.d("myTag", "FOREGROUND: Executing onFileRetrieved listener");
listener.onFileRetrieved(result);
}
}
Capturing the logs on this rare failure yeilds:
In fetchSomeData()
...
(Other log messages from other interactions with the activity such as menu creation and navigation initialization)
but, crucially, not the log statement from the second line of code in the doInBackground method. One thought I had was that this log statement was failing, but I'm not seeing any force stop messages, error in my logs or ACRA crash reports. The application is still active (I can navigate to other activities and back) so I'm at a loss as to what might stop this background thread from running properly. Any ideas?
Sadly AsyncTask is not suitable for critical code execution since, depending on the ThreadPool base and max size, your AsyncTask may never execute.
Moreover, the onPostExecute method could be called when the Activity it is referring (i.e. its creating context) has already been destroyed. You have no way to synchronize with it rather then maybe using join() on the AsyncThread from the UI Thread.
Even though I've seen doing this also in the Android Camera App it isn't a good idea to block the UI Thread waiting for an event since you coulg get an ANR (Application Not Running) notification.
Take a look at this: Is AsyncTask really conceptually flawed or am I just missing something?
Consider using IntentServices, HandlerThread or ThreadPoolExecutors if you need a possibly better way to synchronize your worker thread with your your UIThread.
From http://developer.android.com/training/run-background-service/create-service.html:
Also, an IntentService isn't affected by most user interface lifecycle events, so it continues to run in circumstances that would shut down an AsyncTask

Waiting till the async task finish its work

I'm very new to programming and I have some doubts.
I have a AsyncTask which is I call as RunInBackGround.
and I start this process like:
new RunInBackGround().execute();
But I wish to wait until this call is finish its executing, before proceeding to the other statements of code.
How can I do that?
Are there any way for it?
wait until this call is finish its executing
You will need to call AsyncTask.get() method for getting result back and make wait until doInBackground execution is not complete. but this will freeze Main UI thread if you not call get method inside a Thread.
To get result back in UI Thread start AsyncTask as :
String str_result= new RunInBackGround().execute().get();
Although optimally it would be nice if your code can run parallel, it can be the case you're simply using a thread so you do not block the UI thread, even if your app's usage flow will have to wait for it.
You've got pretty much 2 options here;
You can execute the code you want waiting, in the AsyncTask itself. If it has to do with updating the UI(thread), you can use the onPostExecute method. This gets called automatically when your background work is done.
If you for some reason are forced to do it in the Activity/Fragment/Whatever, you can also just make yourself a custom listener, which you broadcast from your AsyncTask. By using this, you can have a callback method in your Activity/Fragment/Whatever which only gets called when you want it: aka when your AsyncTask is done with whatever you had to wait for.
In your AsyncTask add one ProgressDialog like:
private final ProgressDialog dialog = new ProgressDialog(YourActivity.this);
you can setMessage in onPreExecute() method like:
this.dialog.setMessage("Processing...");
this.dialog.show();
and in your onPostExecute(Void result) method dismiss your ProgressDialog.
AsyncTask have four methods..
onPreExecute -- for doing something before calling background task in Async
doInBackground -- operation/Task to do in Background
onProgressUpdate -- it is for progress Update
onPostExecute -- this method calls after asyncTask return from doInBackground.
you can call your work on onPostExecute() it calls after returning from doInBackground()
onPostExecute is what you need to Implement.
I think the easiest way is to create an interface to get the data from onpostexecute and run the Ui from interface :
Create an Interface :
public interface AsyncResponse {
void processFinish(String output);
}
Then in asynctask
#Override
protected void onPostExecute(String data) {
delegate.processFinish(data);
}
Then in yout main activity
#Override
public void processFinish(String data) {
// do things
}

Threads and ProgressDialog

I am developing my first Androïd application and I'm facing a problem when I want to display a ProgressDialog to indicate that a process is being run.
In my application, the user triggers a time consuming task by pressing a Button. The "OnClick" function of my "OnClickListener" is called when the user presses the Button. In this function, here is what I'm currently doing :
- creation and configuration of an instance of the ProgressDialog class,
- creation of a thread dedicated to the time consuming task,
- attempt to display the ProgressDialog using the "show" method,
- start of the thread,
- main Activity suspended (call of the "wait" function)
- wake up of the main Activity by the thread when it is finished
- removal of the ProgressDialog by calling the "dismiss" function.
Everything works fine (the result of the long task is correct) but the ProgressDialog nevers appears. What am I doing wrong?
Thanks in advance for the time you will spend trying to help me.
You should not call wait() to the Main Activity/UI thread, because this is actually freezing the UI including your ProgressDialog, so it has no time to fade in and will never be shown.
Try to use multithreading correctly: http://developer.android.com/resources/articles/painless-threading.html
final Handler transThreadHandler = new Handler();
public void onClick(View v) {
// show ProgressDialog...
new Thread(){
public void run(){
// your second thread
doLargeStuffHere();
transThreadHandler.post(new Runnable(){public void run(){
// back in UI thread
// close ProgressDialog...
}});
}
}.start();
}
I would suggest using AsyncTask, as it's purpose is exactly to handle this kind of problem. See here for instructions how to use it. Note that the linked page in Floern's answer also recommends the use of AsyncTask.
You would need to do the following:
subclass AsyncTask
override it's onPreExecute() method to create and show a ProgressDialog. (You could hold a reference to it in a member of your subclass)
override it's doInBackground() method to execute your time consuming action.
override it's onPostExecute() method to hide your dialog.
in your activity, create an instance of your subclass and call execute() on it.
If you make your subclass an inner class of your activity, you can even use all of your activity's members.

Categories

Resources