I am using AsyncTask in my Android application.
Here is my task:
public class MyTask extends AsyncTask<String, String, Boolean> {
private ProgressDialog progressDialog;
private boolean isCancelled = false;
public MyTask(ProgressDialog progressDialog) {
this.progressDialog = progressDialog;
}
#Override
protected Boolean doInBackground(String... params) {
try {
if (!isCancelled()) {
isCancelled = false;
} else
isCancelled = true;
} catch (Exception e) {
isCancelled = true;
}
return isCancelled;
}
#Override
protected void onCancelled() {
super.onCancelled();
isCancelled = true;
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
progressDialog.dismiss();
if (!isCancelled) {
// start an activity
}
}
}
I want to cancel this task when pressing device's back button and also cancel the ProgressDialog, but this task executes quickly. When the back button is pressed, the ProgressDialog is cancelled, but the task completes.
This AsyncTask is invoked from an activity like this:
ProgressDialog progressDialog = new ProgressDialog(this);
progressDialog.setMessage("Loading");
progressDialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
if (myTask!= null
&& myTask.getStatus() != AsyncTask.Status.FINISHED
&& !myTask.isCancelled()) {
myTask.cancel(true);
}
}
});
progressDialog.show();
myTask = new MyTask(progressDialog);
myTask.execute();
When logging, I found that the dialog is dismissed (invokes onDismissListener) after executing the condition of onPostExecute(). How can I cancel this task properly?
My intention is cancel the task with back button press whether the task completes or not. Is it possible to cancel an AsyncTask from its onPostExecute()?
Actually, your code looks right,
In ProgressDialog's OnCancel()
After invoking myTask.cancel(true); method, onCancelled(Object), instead of
onPostExecute(Object) will be invoked after doInBackground(Object[]).
Note:
If you call cancel(true), an interrupt will be sent to the background thread,
which may help interruptible tasks. Otherwise, you should simply make sure to check
isCancelled() regularly in your doInBackground() method.
You can see examples of this at http://code.google.com/p/shelves.
But I suggest you to not canceling AsyncTask and just maintain your boolean Flag only dismiss the dialog on back pressed and onPostExecute() of AsyncTask decide what to do with result using your boolean flag condition.
Related
I am running an AsyncTask and it is taking a little time to load. In that period of time, if I am pressing back button then it does not respond. It responds only after a few seconds. So how can I kill or pause or override AsyncTask to go back? Or is there any other way to do something similar?
if (mainContent != null) {
mainContent.post(new Runnable() {
#Override
public void run() {
Bitmap bmp = Utilities.getBitmapFromView(mainContent);
BlurFilter blurFilter = new BlurFilter();
Bitmap blurredBitmap = blurFilter.fastblur(bmp,1,65);
asyncTask = new ConvertViews(blurredBitmap);
asyncTask.execute();
}
});
My AsyncTask:
class ConvertViews extends AsyncTask<Void,Void,Void> {
private Bitmap bmp;
public ConvertViews(Bitmap bmp){
this.bmp = bmp;
}
#Override
protected Void doInBackground(Void... params) {
try {
//Thread.sleep(200);
if(mainViewDrawable == null) {
mainViewDrawable = new BitmapDrawable(getResources(), bmp);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
My onBackPressed():
public void onBackPressed() {
super.onBackPressed();
asyncTask.cancel(true);
finish();
}
there is no way that you can stop a asynch task instantly.Every AsynchTask has a boolean flag property associated with it so if cancel_flag =True mean task has been canceled and there is a cancel() function which can be called on aasynchtask object like this
loginTask.cancel(true);
but all this cancel() function does is ,it will set a cancel boolean(flag ) property of asynch task to True so , you can check this property with isCancelled() function inside doInBackGround and do something ,like
protected Object doInBackground(Object... x) {
while (/* condition */) {
// work...
if (isCancelled()) break;
}
return null;
}
and if it is True then you can use break the loops(if you are doing a long task) or return to go quickly out of doInBackground and calling cancel() on asynchtask will skip the execution of onPostExecute().
and the other option is ,if you want to stop multiple running asynch task in background then calling cancel on each one can be tedious so in this case you can have a boolean flag in container class(of asynchtask) and skip the working inside asynchtask if the flag has been set to True ,like
protected Object doInBackground(Object... x) {
while (/* condition */) {
// work...
if (container_asynch_running_flag) break;
}
return null;
}
but make sure to also put a check in onpostExecute in this case because it won't stop the execution of onpost.
You can stop it instantly calling asyncTask.cancel(true).
But it is not recommended to do because it can lead to memory leaks. Better to call asyncTask.cancel(false) and exit from doInBackground function manually checking isCancelled() value as #Pavneet advised.
I have shown one progress bar on API call like below :
// prepare for a progress bar dialog
progressBar = new ProgressDialog(context);
progressBar.setCancelable(false);
progressBar.setMessage(context.getResources().getString(R.string.please_wait));
progressBar.setProgressStyle(ProgressDialog.STYLE_SPINNER);
But when I cancel or dismiss the progress dialogue created above it has no effect.
progressBar.cancel();
progressBar.dismiss();
Above two calls are in success & failure callback methods :
#Override
public void success(RockAPI.CallResult result) {
progressBar.cancel();
progressBar.dismiss();
....
}
#Override
public void failure(RockAPI.CallResult result) {
progressBar.cancel();
progressBar.dismiss();
......
}
I debugged the application at both success & failure points these lines of code getting executed but still progress dialogue persists. I have checked all the code there is no other place from which this progress bar show() is getting called. Its the same progress dialogue but just not getting canceled.
create such alike functions and call whenever needed..
ProgressDialog progressDialog;
public void showPD(String message) {
if (progressDialog == null) {
progressDialog = new ProgressDialog(getContext());
//progressDialog.setProgressNumberFormat(null);
//progressDialog.setProgressPercentFormat(null);
//progressDialog.setIndeterminate(true);
//progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressDialog.setMessage(message);
progressDialog.setCancelable(false);
progressDialog.setCanceledOnTouchOutside(false);
progressDialog.show();
}
}
public void hidePD() {
if (progressDialog != null) {
progressDialog.dismiss();
progressDialog = null;
}
}
You are setting cancelable as false so dont call progressBar.cancel(). Skip that and directly call progressBar.dismiss(). It should work. If it doesnt we will dig deeper.
Use true instead of false in your setCancelable and it will work .
progressBar.setCancelable(true);
I have created a simple AsyncTask and I want to cancel the same if it takes more than 3 seconds. This is what I have done after following this post :
Async Caller:
execTask = new StartParseDownload();
execTask.execute();
//new StartParseDownload(this).execute();
Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
#Override
public void run() {
if ( execTask.getStatus() == AsyncTask.Status.RUNNING )
execTask.cancel(true);
}
}, 300 );
The task:
public class StartParseDownload extends AsyncTask<String, Void, Boolean> {
private ProgressDialog dialog;
private boolean result = false;
public StartParseDownload() {
}
protected void onPreExecute(){
}
#Override
protected void onPostExecute(final Boolean success){
super.onPostExecute(success);
}
#Override
protected void onCancelled() {
Log.e("Task cancelled", "Task cancelled");
}
protected Boolean doInBackground(final String... args){
parObj.saveInBackground(new SaveCallback() {
#Override
public void done(com.parse.ParseException e){
if (e == null) {
result = true;
goIntoMainScreen();
} else {
result = false;
}
if (e != null) {
}
}
});
return false;
}
}
Where am I going wrong? Why is the onCancelled() not getting called?
1 .Your value is 300 , not 3000(3 Seconds)
2 .Also check like :
if ( execTask.getStatus() == AsyncTask.Status.RUNNING ){
boolean s = execTask.cancel(true);
Log.e("Taskcancelled", "Task cancelled " +s);
}else{
Log.e("Taskcancelled", "Task cancelled already");
}
May be your task already completed before call to cancel.
Inside your doinbackground you have to check if the AsyncTask gets cancelled.
You call cancel but the AsyncTask will continue running if it's still in the dounbackground state. Then after it's done onCancel gets called. Perhaps in your case it doesn't get called after 3 seconds because your doinbacground method takes longer than 3 seconds...or quicker!
By the way I think you mean to run the Handler for 3000 not 300
This answer might help.
The documentation states about the two variants:
Added in API level 11:
protected void onCancelled (Result result)
Added in API level 11
Runs on the UI thread after cancel(boolean) is
invoked and doInBackground(Object[]) has finished.
The default implementation simply invokes onCancelled() and ignores
the result. If you write your own implementation, do not call
super.onCancelled(result).
Added in API level 3:
protected void onCancelled ()
Added in API level 3
Applications should preferably override
onCancelled(Object). This method is invoked by the default
implementation of onCancelled(Object).
Runs on the UI thread after cancel(boolean) is invoked and
doInBackground(Object[]) has finished.
I haven't tested this, but you might want to try implementing both overrides:
#Override
protected void onCancelled() {
Log.e("Task cancelled", "Task cancelled");
}
#Override
protected void onCancelled(Boolean result) {
Log.e("Task cancelled", "Task cancelled, result: " + result);
}
It might also help to log the result of cancel() to make sure that you are successfully canceling the AsyncTask.
if ( execTask.getStatus() == AsyncTask.Status.RUNNING ){
boolean cancelled = execTask.cancel(true);
if (cancelled){
Log.d("cancel", "Task cancelled");
}
else{
Log.e("cancel", "Task not cancelled");
}
}
My application has a ViewFlipper with 3 ViewGroups in it. Each ViewGroup interaction is dependent on data from a database. I'm using an AsyncTask to read from a database and return a Cursor when it's done. Before the AsyncTask is executed, I just want to display a single View in the ViewFlipper saying "Loading data, please wait.", is this possible somehow?
Show the progress dialog in your onPreExecute() and dismiss it in the onPostExecute(). Something like this,
private class MyAsyncTask extends AsyncTask<Integer, Integer, Integer[]> {
private ProgressDialog myWait = null;
// This is on the UI thread itself
protected void onPreExecute() {
myWait = new ProgressDialog(MainActivity.this);
myWait.setMessage("Loading data, please wait");
myWait.setCancelable(false);
myWait.show();
}
// Separate worker thread is used here
protected Integer[] doInBackground(Integer...params) {
//do the database loading
return <your result - goes to onPostExecute>;
}
// This is on the UI thread itself
protected void onPostExecute(Integer[] resultCell) {
if (myWait != null) {
myWait.dismiss();
}
}
}
yes you can make use of progressDialog. Do it like this,
progressDiaolg=ProgressDialog.show(Activity.this,"","Loading Images...");
final Thread t= new Thread(new Runnable() {
public void run() {
Log.i("Inside Thread", "Downloading Images...");
downloadImages();
handler.sendEmptyMessage(0);
}
});
t.start();
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
try {
progressDiaolg.dismiss();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
};
I don't have idea with Asynctask. So try modifying this snippet accordingly.
I'm writing an app that at many points will attempt to retrieve account information from a website. I'd like to write a single function ("getAccount()") to do the following:
Show a ProgressDialog
Make the call to the website
Wait for a response
Clear the ProgressDialog
Return control to the calling function after the first four steps are done
I'm not having a problem with getting the data from the page; the problem I have is with the whole "show dialog / wait for completion / return control to the calling function" portion. Either the ProgressDialog doesn't show at all, or the function returns to the caller immediately after making the data request from the site, without giving it enough time to retrieve the data.
Any help would be most appreciated.
EDIT: I'm adding a bit of code below for what I have with AsyncTask. Notice that I have the line MsgBox("done") inside grabURL(); this is simply a Toast call. When I run this code, "done" pops up while the HTTP request is still being made. This MsgBox line only exists so I can see if grabURL is properly waiting for GrabURL to finish (which it isn't).
public void grabURL() {
new GrabURL().execute();
MsgBox("done");
}
private class GrabURL extends AsyncTask<String, Void, Void> {
private ProgressDialog Dialog = new ProgressDialog(MyContext);
protected void onPreExecute() {
Dialog.setTitle("Retrieving Account");
Dialog.setMessage("We're retrieving your account information. Please wait...");
Dialog.show();
}
protected Void doInBackground(String... urls) {
try {
// Get account info from the website
String resp = GetPage(ThePage); // I have this classed out elsewhere
// Some other code that massages the data
AccountRetrievalSuccess = true;
} catch (Exception e) {
AccountRetrievalSuccess = false;
}
return null;
}
protected void onPostExecute(Void unused) {
Dialog.dismiss();
}
}
The message box done appears because AsyncTask is using a separate thread(s) to run doInBackground. The call to execute does NOT block. You could move message box done to onPostExecute following the call to dismiss. Tip. You may want to call progress.cancel in onPause or you may get unwanted behaviour on orientation change. Finally, if you are retrieving info in doInBackground, consider returning the info in doInBackground. The info will be passed to onPostExecute. So if the info is object MyInfo consider:
private class GrabURL extends AsyncTask<String, Void, MyInfo> {
Can't say for sure without seeing some code but sounds like you are making a asynchronous call to the website when you want to make a synchronous call (which will block and wait for return data) to the website instead.
You want to use an AsyncTask, generate a non-user-cancellable ProgressDialog in the onPreExecute, do your work in doInBackground, and dismiss it in onPostExecute.
Something like this:
public class MyApp extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// blah blah blah
URL url;
try
{
url = new URL("http://example.com");
new MyTask().execute(url);
}
catch (MalformedURLException e)
{
}
}
protected void doSomeStuff()
{
// stuff to do after the asynctask is done
}
protected void throwAWobbly()
{
// stuff to do if you didn't get the data
}
// inner class to do the data getting off the UI thread,
// so android doesn't "not responding" kill you
private class MyTask extends AsyncTask<URL, Void, Boolean>
{
private ProgressDialog dialog;
private boolean gotData = false;
protected void onPreExecute()
{
// create a progress dialog
dialog = ProgressDialog.show(MyApp.this, "",
"Doing stuff. Please wait...", false, false);
}
protected Boolean doInBackground(URL... urls)
{
// get your data in here!
return gotData;
}
protected void onPostExecute(Boolean result)
{
// get rid of the progress dialog
dialog.dismiss();
if (true == result)
{
// got all data!
doSomeStuff();
}
else
{
// oops!
throwAWobbly();
}
}
}
}