Show result of long task after a ProgressDialog - android

I have an application which runs a long task and returns a value. While the task is running, a ProgressDialog shows the progress. After the task is done I want to show the result in a TextView. I run the task in a FutureTask.
My problem is that if I try to get the result, the .get() method of FutureTask blocks the UI Thread and I don't see the ProgressDialog (the TextView displays the result propertly).
My code for the task (pool is ExecutorService):
final FutureTask<String> future = new FutureTask<String>(new Callable<String>() {
#Override
public String call() {
return myLongTask();
}
});
pool.execute(future);
And afterwards I call updateProgressBar() in a Runnable which updates the ProgressDialog with a Handler:
Runnable pb = new Runnable() {
public void run() {
myUpdateProgressBar();
}
};
pool.execute(pb);
Now I'm getting the result, which blocks the UI Thread preventing the ProgressDialog to show up:
String result = future.get()
If I try to put the result inside the updateProgressBar() method (by passing the future as a parameter) after the ProgressDialog dismisses, an Exception is thrown:
Only the original thread that created a view hierarchy can touch its views.
Any ideas how to solve this problem? (I've heard about AsyncTasks but I can't figure out how to use them propertly.)

You are correct that you need either an AsyncTask or a Thread/Handler combination in order to not block the UI.
Neither approach is that tricky, and there are some good guides around that lay out how to do them. Here are some links that I'd recommend.
AsyncTask
Painless threading
Threading
Designing for responsiveness
Thread documentation
Handler documentation

Yes, I had similiar problem when implementing ExecutorService, the following code block the UI thread and need to be run on a separated thread:
String result = future.get()
Just create a class extending AsyncTask to handle the future.get() method like the following code example:
private class FutureTask extends AsyncTask<Future<String>, Void, String>{
#Override
protected PhotoToView doInBackground(Future<String>... params) {
Future<String> f = params[0];
try {
return f.get(30, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String futureResult) {
super.onPostExecute(futureResult);
// this method is run on UI thread
// do something with the result
// or simply hide the progress bar
// if you had previously shown one.
}
}
And run the future thread with:
FutureTask ft = new FutureTask();
ft.execute(future);
Hope this helps.

Related

AsyncTask update UI multiple times

I'm trying to update the UI multiple times in an AsyncTask.
First of all the UI should update, if a request was accepted and later it should run the publishProgress, but If I return a value in the requestAccepted method the other acceptedFiles method will never be executed, but I want it to execute and update the UI before from this task
#Override
protected Void doInBackground(FileInformationHandler... params) {
try {
handler.createSecureSocket("192.168.3.29", 7431);
ProtocolHandler phandler = new ProtocolHandler(handler.getInputStream(), handler.getOutputStream());
phandler.sendInitialisation();
ConfirmationHandler cHandler = new ConfirmationHandler(handler.getInputStream(), handler.getOutputStream());
cHandler.addListener(new ConfirmationReceivedListener() {
#Override
public void requestAccepted(boolean b) {
// Update UI without stopping the asynctask
}
#Override
public void acceptedFiles(int[] ints) {
fileSender.addListener(new ProcessListener() {
#Override
public void processChanged(int i, long l) {
publishProgress(i);
}
});
}
});
} catch (IOException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
First of all you don't need to use an Async task if you are anyways doing the long running operation in a separate thread and have callbacks for different states.
So in your case why can't you simply so all of this in the main thread and in the callbacks just update the UI.
But if you still want to use the Async task then since the doInBackground executes in a separate thread, you can do whatever long running operation is in the method serially and keep using the publishProgress method to update the UI whenever you want. since you are using the callback interface in your case the method will return null and the control with go into the 'onPostExecute'.
IMO using a callback interface in the doInBackground method is not the right approach and defeats the purpose of asyncTask async task.

make asynctask return results when time is exceeded

I have some asynctasks in my application that do network functions (download/upload files,http requests) in the background.While these actions are in progress I use ProgressDialog in order to display messages about the progress of the task. However some tasks may require more time to complete (for example downloading a file on a slow network) and this is something unwanted in the application.
How can I set a parameter to control the duration of each asynctask? I want the asynctask to complete at some point regardless of the completion of the job in the task. I have to make the asynctask call the onPostExecute method.
I read about this http://developer.android.com/reference/android/os/AsyncTask.html#get%28long,%20java.util.concurrent.TimeUnit%29
This was not very helpful because the UI would freeze and there was no actual control of the duration of the asynctask
This is a part of my code
public void downloadFiles(String address) {
String mainUrl =address;
//// I overrride the onPostExecute to get
/// results and call another asynctask
new Downloader(this){ //<--asynctask
#Override
protected void onPostExecute(String result){
super.onPostExecute(result);
TestResults=result;
//another method called that creates another asynctask
uploadFiles(mainUrl);
}
}.execute(mainUrl);
}
I also tried to use a Handler like this
But it didn't work either.
Is there a way to make the asynctask return results (which means to make asynctask call onPostExecute method) after a period of time ?
Using a while loop in the doInBackground method of asnctask is not the solution. I guess I need a timer from the mainUI to make the asynctask return results.
PS I have my application using fragments, that is why I call new Downloader(this) to pass the gui from the fragment.
Just tried this:
public void downloadFiles(String address) {
String mainUrl =address;
final Downloader tempObject =new Downloader(this){
#Override
protected void onPostExecute(String result){
super.onPostExecute(result);
downloadResults=result;
}
};
try {
tempObject.execute(mainUrl).get(3000L, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
This would make the UI freeze for 3 seconds and then the task would be evoked.... Which is not what I want.
Also tried out this:
Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
#Override
public void run() {
if ( tempObject.getStatus() == Downloader.Status.RUNNING )
tempObject.cancel(true);
}
}, 5000 );
This would cause the message of onProgressUpdate of asynctask to stop, however the asynctask keeps running....
Any ideas ?
The methodology of the Handler function needs something additional to work. The solution to the problem lies here
AsyncTask may be canceled, however the doInbackground method is still running. Actually the task is set to value "cancel", but the doInbackgroung will still be running until it finishes. To solve this we must periodically check within a loop in doInbackground to see whether the task was set to cancel. Although this is not exactly what I wanted to do, this seems to be the only solution.
In doInBackground we have to check for the status of the task to see whether it was cancelled or not. So actually ,someone could just have the timer inside the doInbackground and make life easier without using the handler class.
I find it disappointing that one can not just terminate the execution of a synctask at will..... If anyone has a better idea, please let me know.

Where does control return to after onPostExecute() method of AsynchTask?

I have an AsynchTask which is called from with in a function in my MainActivity.
After the onPostExecute method is executed ,the control doesn't seem to return to the function where I called the AsynchTask.
public class MainActivity extends FragmentActivity {
private class GetPlaces extends AsyncTask<AsynchInput,Void,AsynchOutput>{
protected AsynchOutput doInBackground(AsynchInput... placesURL) {
...
}
protected void onPostExecute(AsynchOutput result) {
....
}
}
public void showInterestingPlacesNearby(GoogleMap myMap,Location loc){
....
...
new GetPlaces().execute(new AsynchInput(myMap,placesSearchStr));
}
}
The code I write after the new new GetPlaces().execute doesn't execute. How do I continue after the AysnchTask returns.
edit: I used the AsynchTask as an inner class for my MainActivity.
AsyncTask is used to run code on the background thread from the UI thread. This does not behave like a function call, and execution continues immediately with the statement following the .execute() call. At the same time, the code in doInBackground of your AsyncTask is executed on the background thread and runs without blocking the UI thread. This is the intended behaviour, and without it using AsyncTask would be pointless.
The only way to respond to the end of the async operation is to do that within onPostExecute - you can also take action within onProgressUpdate if you need to take some action in response to your background code.
So your showInterestingPlacesNearby() method does not need to do anything after the .execute call - the code you want to execute there should probably go into onPostExecute.
Alternatively, you could use onProgressUpdate to process items as they are found, instead of waiting for the entire async operation to complete before showing everything at once. For this you need to use publishProgress in your doInBackground whenever something is found.
a possibile solution could be:
take the codes you entered after .execute and put that in a private method
private void AfterTask() {
//your code written after .execute here
}
in the onPostExecute, just call that method
protected void onPostExecute(AsynchOutput result) {
AfterTask();
}
myTask.execute("url");
String result = "";
try {
result = myTask.get().toString();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

Android thread sometimes does not start

I must use Thread in an Android project. Sometimes, it works corectly, however sometimes does not; it does not start (does not call SendToServer() method)or it starts but return to another function suddenly (return updated; line)before the thread does not finish.
Note: affected value is bigger than 0, it gives condition and it goes to if statement.
Here is the my code sample;
public static Boolean MyUpdateFunction(MyObject myobject){
Boolean updated=false;
//Code for updating local database
int affected= SqliteDb.update(....);
if(affected>0)
{
//Send updated data to server
//For this I must use Thread(I can't use AsyncThread)
updated=true;
SendToServer();
}
return updated;
}
public static void SendToServer()
{
try{
;
Thread th=new Thread(new Runnable() {
public void run() {
try {
//Create data and send it to server
//.......
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
th.start();
th.join();
}
catch(SQLException e)
{
Toast.makeText(myContext,"ERROR: "+e.getMessage(), Toast.LENGTH_LONG).show();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Other people are correct in that an AsyncTask is the way forward, but the direct problem due to what you're experiencing is this (and as such, I would recommend reading up on how Threading works):
When you start the thread, it begins a new process. The UI thread (which is generally where the majority of your code is) continues. So your code will fire the thread with SendToServer(), and then by definition will immediately return updated, as the UI thread immediately goes to the next line.
What you need is a callback from your Thread, which is handled in the onPostExecute() method of an AsyncTask. There's a good tutorial on how to use them and what they do here
Edit:
I've just seen from a comment above that you can't use Asynctasks, fair enough, but you still need a callback/event fired from your Thread to return any results
Instead of using threads and your variables (updated and affected), you can use AsyncTasks: see: http://developer.android.com/reference/android/os/AsyncTask.html
With AsyncTask, you have some methods which are doing exactly what you want:
onPreExecute
doInBackground
onPostExecute
So, what you can do is to check your condition in onPreExecute, then do your SendToServer in the doInBackground and onPostExecute do what you need.

How can I create a 2nd thread, have progressdialog and pause the main thread?

Sorry, I am new to Android programming. I have an xml parser that I don't want running in the UI thread. I want to display a progressdialog while the parser is running in its own thread but I don't want the main thread to start the next Activity until the parser is finished. I have code but the progressdialog doesn't display for the full duration. In place of the while loop, i've tried parserThread.join() with the same results. Also, I want to avoid timing out the UI thread. Any help is appreciated.
My method that invokes the thread, followed by the class that implements Runnable:
private void parseGasStationData() {
gasStations = null;
StationParser sp = new StationParser(activity);
Thread parserThread = new Thread(sp);
parserThread.start();
while (parserThread.isAlive()) {
// do nothing
}
gasStations = sp.getList();
Log.v("Parser-Status", "xml parsed successfully: "
+ (gasStations != null));
}
public class StationParser implements Runnable {
private Activity activity;
private final ProgressDialog pd;
public StationParser(Activity activity) {
this.activity = activity;
pd = ProgressDialog.show(activity, "", "Parsing data...", true, false);
}
#Override
public void run() {
try {
runParser();
} catch (XmlPullParserException e) {
Log.e("Parser-Error", "XmlPullParserException", e);
e.printStackTrace();
} catch (IOException e) {
Log.e("Parser-Error", "IOException", e);
e.printStackTrace();
} catch (ParseException e) {
Log.e("Parser-Error", "ParseException", e);
e.printStackTrace();
}
pd.dismiss();
}
In android we use the AsyncTask class to make background operations an show the results. See the main document page here the first example seems pretty useful for you, just change the doInBackground method for your parser.
This code:
while (parserThread.isAlive()) {
// do nothing
}
needs to go. As long as you have that, you might as well not be using a separate thread at all. (In fact, it's worse, because it's a "busy wait" that hogs the CPU.)
The right way to do this is with a call-back. When the parsing thread is done, it can call post(Runnable) to run a process on the UI thread that will make the progress dialog go away. You can use AsyncTask to help with this. See the guide topic Processes and Threads for more information.

Categories

Resources