Handling exceptions in AsyncTask.doInBackground in an Activity? - android

I am following the guide on Processes and Threads to implement an AsyncTask in an android activity in which I will perform some database access. However, my code has to handle an exception in doInBackground.
My current thinking is to provide a Toast popup to inform the user of this exception, but now I am afraid this too "violates the second rule of the single-threaded model: do not access the Android UI toolkit from outside the UI thread" (as per the guide).
Would I be wrong in providing a Toast popup? Is there a better way to handle exceptions in the doInBackground method?

Will the exception cause you to stop what doInBackground is processing?
If yes, store what exception you encountered, exit doInBackground and show the Toast in onPostExecute
If no, pass the exception information to onProgressUpdate with publishProgress.
Trying to pop-up the Toast in doInBackground will not work.

You can use runOnUIThread to update UI from background thread
#Override
protected void doInBackground(Void... params) {
try{
// do some stuff
}catch(Exception ex){
ex.printStackTrace();
final String message = ex.getMessage();
yourActivity.runOnUiThread(new Runnable() {
public void run() {
// show toast
Toast.makeText(getApplicationContext, message, Toast.LENGTH_SHORT).show();
}
});
}
}

Related

how android oncreate works?

On executing the following code, i found that the entire app freezes for 10000ms before showing anything on the emulator's screen. I would have expected the first Toast message to appear , followed by the app to freeze for 10000ms and the second toast message to appear. makes me wonder if android piles up all the code in the 'oncreate' method before executing it. is it supposed to be that way?
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toast.makeText(this, new ServiceCode("Hi").s, Toast.LENGTH_SHORT).show();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Toast.makeText(this, new ServiceCode("Hello").s, Toast.LENGTH_SHORT).show();
}
It behaves as expected. There is a single thread responsible for UI updates. It's called main thread. This thread shows toast messages too. When you call Toast.show(), Android schedules a new task for the main thread. When main thread is done with onCreate(), it will execute this task and show the toast. But because you blocked main thread for 10 seconds, no toasts are show. There is no one free, who can show this message. But then, 10 seconds later, both toasts will appear one after another, because main thread is free to show them.
Best practice is to never block the main thread. Otherwise your application will freeze and users will see ANR (application nor responding) message. If you need to execute something later in time, you need to post this task to the main thread's task queue for been executed later.
The code below will behave as you expect.
public class MainActivity extends Activity {
private Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// show first toast immediately
Toast.makeText(this, new ServiceCode("Hi").s, Toast.LENGTH_SHORT).show();
// schedule second toast to appear 10 sec later
handler.postDelayed(new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this,
new ServiceCode("Hello").s, Toast.LENGTH_SHORT).show();
}
}, 10000);
}
}
When an Activity is created, the system-process would send a message to the UI thread of the Activity. The UI thread of the the Activity received the message and then executes "onCreate" method.
Here you make a toast in the "onCreate" method. That will not show the toast immediately. It only sends a message to the message queue of the UI thread. After you UI thread have fininshed the "onCreate" "onStart" "onResume" method, it receives the message of "Toast". At that moment, the Toast is actually showed on the screen.
The reason is simple, the show method of the Toast class might not be a synchronous call "internally", what I mean is, the main-thread is very unlikely to wait until the Toast is actually shown and rendered to continue, hence, it might start a functionality to start rendering the Toast BUT since you immediately after that force the main-thread to stop, it doesn't handle that request since main thread have the highest priority.
Hope it helps!
Regards!
check these links to know about the Android Life-Cycle
http://developer.android.com/training/basics/activity-lifecycle/index.html
Android activity life cycle - what are all these methods for?
your creating a Splash Screen,
if not remove
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
you App won't freeze.
Try this :
Toast.makeText(this, new ServiceCode("Hi").s, Toast.LENGTH_SHORT).show();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
Toast.makeText(this, new ServiceCode("Hello").s, Toast.LENGTH_SHORT).show();
}
}
The display of Toast is an asynchronous call.Thus, once the toast request is executed, the operating system jumps to the next operation and meanwhile the toast is prepared and displayed.
In your case since the next operation blocks the UI Thread for 10 sec the toast is not displayed until the UI Thread is released.

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.

how to pause AsyncTask for asking details from user?

I want to ask user for some details while doing some work in doInBackground() of AsyncTask (showing to user some dialog with choices in UI-thread), and after users choice continue the job in doInBackground() with chosen parameters from dialog.
What is a best mechanism of transfer this parameter to doInBackground()? How I should pause (and continue) thread doing doInBackground() (maybe object.wait() and notify()?)? Should I use a Handler for this purpose?
I would ask user for input before actually starting background task. If this is not possible there are couple possibilities:
You can use lock object and do usual wait()/notify() stuff on it. You still need to pass data from UI thread to your background thread though
I would use queue to pass data from UI thread to background thread and let it handle all the locking.
Something like this (kind of pseudo-code)
class BackgroundTask extends AsyncTask<BlockingQueue<String>, ...> {
void doInBackground(BlockingQueue<String> queue) {
...
String userInput = queue.take(); // will block if queue is empty
...
}
}
// Somewhere on UI thread:
BlockingQueue<String> queue = new ArrayBlockingQueue<String>(1);
BackgroundTask task = new BackgroundTask<BlockingQueue<String>,....>();
task.execute(queue);
....
....
String userInput = edit.getText().toString(); // reading user input
queue.put(userInput); // sending it to background thread. If thread is blocked it will continue execution
You can use a Callable, submit it to an Executor, the Executor will return FutureTask then you will wait in a while loop until FutureTask.isDone == true;
This here is an example http://programmingexamples.wikidot.com/futuretask
I hope my answer will solve your problem surely.
//DO ALL BELOW CODE IN doInBackground() method of AsyncTask
String userInput="";
YouActivity.this.runOnUiThread(new Runnable() {
public void run() {
//SHOW YOUR DIALOG HERE
}
});
while("".equals(userInput))
{
YouActivity.this.runOnUiThread(new Runnable() {
public void run() {
userInput=editText.getText().toString();//fetching user input from edit Text
}
});
}
Thanks :)

Asyntask: why update UI Thread in doInbackground will meet error?

when I read document about asyntask, they say that: "should not" update UI thread in doInbackground because doInbackground work on different thread.
that means : this action will dangerous because UI Thread isn't thread-safe. I understand it. but when I try for test what happen when I update UI Thread in this function. I receive error: (but error doesn't not look like because aysnchonize, but because we CANNOT do it)
(TextView)((Activity)context).findViewById(R.id.text)).setText("StackOverFlow");
//context: reference of context object of UI Thread
Please explain for me. Does we shouldn't or mustn't .
thanks :)
what I have understand so far with android is...,
we can't update UI thread from background thread.
May be it is the case they have stopped us to update UI from background thread.
The reason for that is very clear... # OS level there will be so many thread will be running.
And also
different thread from different application, And in that case It will be chaos on the screen, if we can update UI from bg-thread
Inside the doInBackgroundyou will not get the UI access. If You Want to take UI access publishProgress from doInBackgroundyou will go to the onProgressUpdate from there do what you wan to show on UI.
Below is the Code you will check for your reference :
class DownloadAsyncTask extends AsyncTask
{
ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = ProgressDialog.show(Login.this, "", "Please Wait ...");
}
#Override
protected Void doInBackground(String... arg0) {
int status1 = validationuser(username);
Log.i("MyLog", "Inside the doInBackground is came"+status1);
if(status1 == 1)
{
publishProgress(status1+ "Valid User Code","1",""+status1);
}
else
{
publishProgress(status1+ " Invalid Valid User Code","0",""+status1);
}
return null;
}
#Override
protected void onProgressUpdate(String...values){
super.onProgressUpdate(values);
int index = Integer.parseInt(values[2]);
if(index == 1)
{
USERIDLOGIN = edittextuserName.getText().toString();
Intent intent=new Intent(Login.this, CollectionModuleandDownload.class);
/*Toast.makeText(Login.this, "Valid User Password", Toast.LENGTH_SHORT).show();*/
startActivity(intent);
progressDialog.dismiss();
}
else
{
Toast.makeText(Login.this, "Invalid Username & Password", Toast.LENGTH_SHORT).show();
progressDialog.dismiss();
}
}
#Override
protected void onPostExecute(Void result){
super.onPostExecute(result);
/*if(progressDialog != null)
{
progressDialog.dismiss();
}*/
}
}
so you have to update ui only on the OnPostExecute & OnPreExecute.
here's a good example of asynctask. give it a try
you call it by
new SaveProfile().execute();
then this...
private class SaveProfile extends AsyncTask<String, Void, Boolean>{
#Override
protected Boolean doInBackground(String... params) {
//---------- so your stuff here.... non ui related
Log.v("response from saving",response);
if(response.equals("1")){
return true;
}else{
return false;
}
}
protected void onPostExecute(Boolean result) {
if(result) {
//------ UPDATE UI HERE
Toast.makeText(ProfileCompanyActivity.this, "profile saved", 2500).show();
}else{
Toast.makeText(ProfileCompanyActivity.this, "an error occured", 2500).show();
}
}
}
When you create a Aysnc task the doInBackground method runs in the separate thread from UI thread. So you cannot update the UI from this method.
The OnPostExecute and onPreExecute method execute in the same thread as UI thread. For further reading go here
If only one thread is allowed to touch the user interface, Android can guarantee that nothing vital is changed while it’s measuring views and rendering them to the screen
It is because .. User Interface can be updated only on mainthread..all the user interface objects in your screen are maintained by this mainthread....now if you try to change the user interface from some other thread(do in background)in this case.. it causes error because..for example.. if you try to change the seekbar(some widget) value from other than main thread.. and the user is trying to put a different value...then it is ambiguous for android.. as to which thread it should listen... hope it clarifies your doubt..
So, it is like we should'nt try to.. and because of its security.. we cannot try also.. as it gives error.. =]
doInBackground is used to perform heavy calculations or any background work you want to perform in your activity.
when the operation in your doinbackground method finished the on postexecute methods upadates your ui..
in short doinbackground is not used to update ui.
I think the answer is that we mustn't
It just doesn't seem logical to me..
its like trying to change the radio station at another car driving beside you..
the architecture just doesn't work that way.. you can decide on a radio station before you set off to your road trip or when you stop driving and theoretically you can yell to him and ask him to change the station but you cannot do it yourself.
As doInBackground() runs on separate thread and onPostExecute runs on UIMain thread and as per constraint provided by Android you cannot update UIMain Thread from other thread.
Because of above mentioned reason you are getting mentioned message while you are running your application.

To invoke a method of the main Thead From child thread

In my app i am using soap webservice call , based on the webservice call reply i have to display some messages .,
But after the reply i could not able to do this from the spawned child thread
So how to get back to the main thread and display this after the reply i got
Hope this is clear.. help me how to achieve my requirement
{
Thread t1 = new Thread() {
public void run() {
String threadName = Thread.currentThread().getName();
// There will be delay in this statement while fetching a data from webservice
String returnfromWebservice = webservice(xmlDetails, "generateid");
Log.v("returnfromWebservice",returnfromWebservice);
if( ! returnfromWebservice.equalsIgnoreCase("nil")){
gotid = returnfromWebservice;
gotReply=true;
// dothis();// I could able to do this because this method contains widgets
// I am gettin the error : Only the original thread that created a view hierarchy can touch its views.
//I understand this is because childthread has no controls on widget
/**Suggest me how to get back to main thread*/
}
}};
t1.start();
dothis();// so i am doin here after the completion of it
}
public void dothis{
if(gotReply){
idtext.setText(gotid);
genId.setEnabled(false);
Toast.makeText(WelcomeScorer.this, "Generated ", 500).show();
}
else{
Toast.makeText(WelcomeScorer.this, "Try Once More ", 500).show();
idtext.setText(gotid);
}
}
I am new to android, Is there any best approach in android api to handle this situation ??
You should use the following code to touch your ui elements from another thread
youractivityname.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
}
});
If your thread is in same activity you can use this. Otherwise you should use your activity class object to run the above method.From your code you should call dothis(); after thread has done its job. From your it will call the dothis method immediately after thread has started it wont care whether thread has done its job or not.
The various methods are documented in this article. Using runOnUiThread is probably the simplest.

Categories

Resources