How can I stop asynctask in android when back button is pressed? - java

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.

Related

Terminating Android Timer if user doesn't use the App(Prevent running in the background)

I have a Timer in my App that infinitely runs an Animation. like this:
Timer t = new Timer();
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
//Running Animation Code
}
});
}
}, 1000, 1000);
Now I realized that this code runs even if user click Back Button of android. if fact it runs in the background and it seems uses a lot of memory.
I need this code run ONLY if user in the app. In fact when user click on Back Button, this Timer goes to end and if user clicks on Home Button, after a while that user doesn't use the App, terminates this Timer.
What I need is to prevent using memory. Because i realized if this codes runs a while, App freezes! I need a normal behavior.
If your Activity is the last element in the BackStack, then it will be put in the background as if you pressed the Home button.
As such, the onPause() method is triggered.
You can thus cancel your animation there.
#Override protected void onPause() {
this.timer.cancel();
}
You should as well start your animation in the onResume() method.
Note that onResume() is also called right after onCreate(); so it's even suitable to start the animation from a cold app start.
#Override protected void onResume() {
this.timer.scheduleAtFixedRate(...);
}
onPause() will be also called if you start another Application from your app (e.g: a Ringtone Picker). In the same way, when you head back to your app, onResume() will be triggered.
There is no need to add the same line of code in onBackPressed().
Also, what's the point in stopping the animation in onStop() or onDestroy()?
Do it in onPause() already. When your are app goes into the background, the animation will already be canceled and won't be using as much memory.
Don't know why I see such complicated answers.
You can do it like this, in onBackPressed() or onDestroy(), whatever suits you.
if (t != null) {
t.cancel();
}
If you need, you can start timer in onResume() and cancel it in onStop(), it entirely depend on you requirement.
If a caller wants to terminate a timer's task execution thread
rapidly, the caller should invoke the timer's cancel method. - Android Timer documentation
You should also see purge and
How to stop the Timer in android?
Disclaimer: This might not be the 100% best way to do this and it might be considered bad practice by some.
I have used the below code in a production app and it works. I have however edited it (removed app specific references and code) into a basic sample that should give you a very good start.
The static mIsAppVisible variable can be called anywhere (via your App class) in your app to check if code should run based on the condition that the app needs to be in focus/visible.
You can also check mIsAppInBackground in your activities that extend ParentActivity to see if the app is actually interactive, etc.
public class App extends Application {
public static boolean mIsAppVisible = false;
...
}
Create a "Parent" activity class, that all your other activities extend.
public class ParentActivity extends Activity {
public static boolean mIsBackPressed = false;
public static boolean mIsAppInBackground = false;
private static boolean mIsWindowFocused = false;
public boolean mFailed = false;
private boolean mWasScreenOn = true;
#Override
protected void onStart() {
applicationWillEnterForeground();
super.onStart();
}
#Override
protected void onStop() {
super.onStop();
applicationDidEnterBackground();
}
#Override
public void finish() {
super.finish();
// If something calls "finish()" it needs to behave similarly to
// pressing the back button to "close" an activity.
mIsBackPressed = true;
}
#Override
public void onWindowFocusChanged(boolean hasFocus) {
mIsWindowFocused = hasFocus;
if (mIsBackPressed && !hasFocus) {
mIsBackPressed = false;
mIsWindowFocused = true;
}
if (!mIsWindowFocused && mFailed)
applicationDidEnterBackground();
if (isScreenOn() && App.mIsAppVisible && hasFocus) {
// App is back in focus. Do something here...
// this can occur when the notification shade is
// pulled down and hidden again, for example.
}
super.onWindowFocusChanged(hasFocus);
}
#Override
public void onResume() {
super.onResume();
if (!mWasScreenOn && mIsWindowFocused)
onWindowFocusChanged(true);
}
#Override
public void onBackPressed() {
// this is for any "sub" activities that you might have
if (!(this instanceof MainActivity))
mIsBackPressed = true;
if (isTaskRoot()) {
// If we are "closing" the app
App.mIsAppVisible = false;
super.onBackPressed();
} else
super.onBackPressed();
}
private void applicationWillEnterForeground() {
if (mIsAppInBackground) {
mIsAppInBackground = false;
App.mIsAppVisible = true;
// App is back in foreground. Do something here...
// this happens when the app was backgrounded and is
// now returning
} else
mFailed = false;
}
private void applicationDidEnterBackground() {
if (!mIsWindowFocused || !isScreenOn()) {
mIsAppInBackground = true;
App.mIsAppVisible = false;
mFailed = false;
// App is not in focus. Do something here...
} else if (!mFailed)
mFailed = true;
}
private boolean isScreenOn() {
boolean screenState = false;
try {
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
screenState = powerManager.isInteractive();
} catch (Exception e) {
Log.e(TAG, "isScreenOn", e);
}
mWasScreenOn = screenState;
return screenState;
}
}
For your use you might want to create a method in your activity (code snippet assumes MainActivity) that handles the animation to call the t.cancel(); method that penguin suggested. You could then in the ParentActivity.applicationDidEnterBackground() method add the following:
if (this instanceof MainActivity) {
((MainActivity) this).cancelTimer();
}
Or you could add the timer to the ParentActivity class and then not need the instanceof check or the extra method.

AsyncTask connection timeout not cancelling the task

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");
}
}

Android SDK: Handler causing crash on some devices

I have a handler used to display images in a specified interval loop, on reaching the last image, it goes back to the first image which is the correct. However, i'm having problems with it as it's causing some devices to crash and makes the CPU usage go up significantly, i'm just wondering what is wrong with the code?
I instantiate it like the following at the top of the fragment:
final public static Handler handler = new Handler();
boolean isRunning = false;
Then in the onPostExecute part of an AsyncTask, I have this code:
#Override
protected void onPostExecute(Void v) {
if(!isRunning) {
Runnable runnable = new Runnable() {
#Override
public void run() {
anImageView.setVisibility(View.VISIBLE);
isRunning = true;
counter++;
//imageDownloader.download(data.get(i).getImageURL(), anmageView);
if(TabsViewPagerFragmentActivity.theImages !=null && TabsViewPagerFragmentActivity.theImages.size() > 0){
Bitmap anImage = TabsViewPagerFragmentActivity.theImages.get(i);
anImageView.setImageBitmap(anImage);
}
i++;
if(i>TabsViewPagerFragmentActivity.theImages.size()-1)
{
i=0;
}
handler.postDelayed(this, 1500);
}
};
handler.postDelayed(runnable, 0);
}
}
The above AsyncTask is called within the onCreate() method.
Secondly, I have a refresh button which re-downloads these images in order to get the latest ones as they change periodically. Therefore I have an onClick() event attached to the refresh button. This also works fine but here is the code which is called:
#Override
protected void onPostExecute(Void v) {
for(int i=0;i<data.size()-1;i++) {
Bitmap anImage = getBitmapFromURL(data.get(i).getImageURL());
theImagesRefreshed.add(anImage);
}
if(!isRunning) {
Runnable runnable = new Runnable() {
#Override
public void run() {
anImageView.setVisibility(View.VISIBLE);
isRunning = true;
counter++;
//imageDownloader.download(data.get(i).getImageURL(), anImageView);
if(theImagesRefreshed !=null && theImagesRefreshed.size() > 0){
Bitmap anImage = theImagesRefreshed.get(i);
anImageView.setImageBitmap(anImage);
}
i++;
if(i>theImagesRefreshed.size()-1)
{
i=0;
}
handler.postDelayed(this, 1500);
}
};
handler.postDelayed(runnable, 0);
}
}
I think that the handler is not setup right and is causing the performance issues. Can anyone see anything wrong with this code?
Thanks in advance!
You need to call Looper.prepare() while using handlers in threads .So write Looper.prepare() after you are creating instance of Runnable

Change color with delay

I want to change the background color of a textview when I press a button. It should do this: first be white for 10ms, and then just the regular color. Is there some kind of delay function or do I need to write my own function for this using a loop or some kind? Any tip is greatly appreciated :)
At this moment I just use
button.setBackgroundColor(Color.parseColor("#ffa500"));
every view have post and postDelayed methods to respectively post a runnable to the UI thread or post delayed it.
button.postDelayed(new Runnable() {
#Override
public void run() {
// change color in here
}
}, 10);
edit:
if you're going to be calling this very often, you can do it even better with something like this:
int currentColor;
private Runnable changeColorRunnable = new Runnable() {
#Override
public void run() {
switch(currentColor){
case Color.RED: currentColor = Color.BLACK; break;
case Color.BLACK: currentColor = Color.RED; break;
}
button.setBackgroundColor(currentColor);
}
};
and then:
button.postDelayed(changeColorRunnable, 10);
this will avoid unnecessary object creation and garbage collection
The easiest way to do that would be to create an handler and to execute it with postDelayed :
http://developer.android.com/reference/android/os/Handler.html#postDelayed(java.lang.Runnable, long)
private class ButtonColorChange extends AsyncTask<String, Void, String>
{
protected void onPreExecute()
{
//do
}
protected String doInBackground(String... params)
{
try
{
Thread.sleep(10000); //waiting here
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(String result)
{
button.setBackgroundColor(Color.parseColor("#ffa500"));
}
}
use this method whenever you click on button as
ButtonColorChange btc = new ButtonColorChange();
btc.execute();

Cancelling AsyncTask in Android

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.

Categories

Resources