AsyncTask doesn't stop even after cancelling it - android

I have an AsyncTask inside a fragment, which is being executed every second using a Timer. The AsyncTask loads data into a ListView, and when the user clicks on a ListView item, it switches to another fragment.
The timer doesn't stop, so it keeps executing itself and finally, gives me an error when it tries to load the data into the ListView.
I already tried looking for answers, and have implemented those in my code-
class HttpGetAsyncTask extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onCancelled() {
Log.d("PORTS Cancelled","cancelled");
}
#Override
protected String doInBackground(String... q) {
String v = null, c = null;
for(int countervar=0;countervar<1;countervar++){
if(load.isCancelled())
break;
//All my code here
}
return c;
}
protected void onPostExecute(String result) {
if(isCancelled()||!isAdded()){
return;
}
else{
SimpleAdapter adapter = new SimpleAdapter(getActivity(),
ports, R.layout.playout, new String[] { "name",
"code", "type" }, new int[] { R.id.portn, R.id.portc,
R.id.portv });
adapter.notifyDataSetChanged();
lv.setAdapter(adapter);
}
}
}
#Override
public void onPause() {
super.onPause();
timer.cancel(); //timer is the name of the Timer
doAsynchronousTask.cancel(); //doAsynchronousTask is the TimerTask
if(load!=null) //load is the AsyncTask
if(!load.isCancelled())
load.cancel(true);
}
#Override
public void onDestroy() {
super.onDestroy();
timer.cancel();
doAsynchronousTask.cancel();
if(load!=null)
if(!load.isCancelled())
load.cancel(true);
}
The timer (Called in onCreateView)-
handler = new Handler();
doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
try {
load = new HttpGetAsyncTask();
load.execute();
} catch (Exception e) {
// TODO Auto-generated catch block
}
}
});
}
};
timer.schedule(doAsynchronousTask, 0, 10000);
Please let me know where I'm going wrong and what I can do to fix this problem. Thanks.

When the doAsynchronousTask task is scheduled the load variable is replaced with a new HttpGetAsyncTask. So more than one AsyncTask can run a the same time, and when you stop the task, calling:
load.cancel(true);,
you are only cancelling the AsyncTask referenced by load variable, but others tasks can continue to work in backgroud (without any handle for stopping them).
A solution can be, to stop the AsyncTask before start another one.

What about adding a boolean flag in the loop as the condition controlling the loop?
Then you can set it to false to stop the task in onPause()

Related

How to call AsyncTask method for a regular time interval?

I need to send one command to the server from an android activity at regular intervals of time and then receive the output and display it on the Layout of the activity.
How can I achieve the above task?
I think this is the sort of thing you're looking for:
public void myAsynchronousTask() {
final Handler handler = new Handler();
Timer timer = new Timer();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
try {
BackgroundTask backgroundTask = new BackgroundTask();
// The above is the class that performs your task
backgroundTask.execute();
} catch (Exception e) {
// TODO Auto-generated catch block
}
}
});
}
};
timer.schedule(doAsynchronousTask, 0, 50000); //this runs every 5 seconds. Feel free to change it
}
Change it according to your needs.
In the above case for each and every time one async task object will be created but in this case objects will not be created multiple times and with out completing first request the send request will be started...
private void startFectchingTheData() {
asynT.execute();
}
Runnable rannable = new Runnable() {
#Override
public void run() {
asynT.execute();
}
};
Handler handler = new Handler();
AsyncTask<Void, Void, Void> asynT = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
// Write the fetching logic here
return null;
}
protected void onPostExecute(Void result) {
int interval = 5000;
handler.postDelayed(rannable, interval);
};
};
protected void onDestroy() {
handler.removeCallbacks(rannable);
};

Can't cancel running AsyncTask

I'm having some trouble with an AsyncTask subclass.
I have a main activity as below that displays a button and a number that counts up on the screen. Clicking the button launches an Edit activity where a number can be entered.
The number displayed on the Main activity should update with the timer which it does but the trouble I'm having is that I can't stop the timer. It should stop when entering the Edit activity and returning from it as well, as well as restart with the a new value too but it doesn't, the timer is always running with the first entered value, it never stops, even when I leave the program and return to the home screen.
I've looked at posts here such as Can't cancel Async task in android but they all just mention checking for isCancelled() which I'm doing. Can anyone see/explain why I can't stop this AsyncTask ?
public class MainActivity extends Activity {
#Override
UpdateTimer ut;
TextView tvn;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public void onResume() {
super.onResume();
tvn = (TextView) findViewById(R.id.numDisplay);
if(ut != null )//&& ut.getStatus() == AsyncTask.Status.RUNNING) {
ut.cancel(true);
ut.cancelled = true;
Log.d("-----M_r","called cancel: "+ut.isCancelled()+" "+cancelled);
}
if (updateRequired) {
ut = new UpdateTimer();
ut.execute(number);
updateRequired = false;
}
}
public void onEditButtonPressed(View caller) {
// kill any running timer
if(ut != null )
{
ut.cancel(true);
ut.cancelled = true;
}
// start the edit screen
Intent e_intent = new Intent(this, EditActivity.class);
startActivity(e_intent);
}
private void updateScreen(long number) {
// update screen with current values
tvn.setText("" + number);
}
private class UpdateTimer extends AsyncTask<Long, Long, Integer> {
long number;
public boolean cancelled;
#Override
protected Integer doInBackground(Long... params) {
number = params[0];
cancelled = false;
while(true) {
number += 1;
//sleep for 1 second
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// tell this AsyncTask to update the time on screen
publishProgress(number);
// check if timer needs to stop
if (isCancelled()) break;
if(cancelled) break;
}
return null;
}
protected void onProgressUpdate(Long... progress) {
Log.d("-----M_ut","updated: "+number+" "+this.isCancelled()+" "+cancelled);
updateScreen(progress[0]);
}
protected void onCancelled(Integer result) {
cancelled = true;
Log.d("-----M_ut","-- cancelled called: "+this.isCancelled());
}
}
protected void onStop()
{
super.onStop();
// kill any running timer
if(ut != null) {
ut.cancel(true);
}
}
}
Try this...
remove the variable..cancelled and change to this..
#Override
protected void onCancelled() {
super.onCancelled();
}
call the super.onCancelled instead..
And in the doInBackground check
if (isCancelled()) {
break;
}
Try calling from your activity ut.cancel(true);
Hope it works:)
private YourAsyncTask ut;
declare your asyncTask in your activity.
ut = new YourAsyncTask().execute();
instantiate it like this.
ut.cancel(true);
kill/cancel it like this.

Two background service android

In my acivity, i need to run two background service.
main background service:
class loadingTask extends AsyncTask<Void, Void,Void> {
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
pd = ProgressDialog.show(context, "", "Chargement en cours..", true, false);
super.onPreExecute();
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
pd.dismiss();
}
...
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
getxml = Util.CallWebService("");
return null;
}
}
Second background service.
class mloadingTask extends AsyncTask<String, Void, String> {
protected String doInBackground(String... urls) {
SAXHelper sh = null;
try {
sh = new SAXHelper(urls[0]);
} catch (MalformedURLException e) {
e.printStackTrace();
}
sh.parseContent("");
return "";
}
protected void onPostExecute(String s) {
pd.dismiss();
}
}
In my onCreate() method I want to call the first background and when it finished loading the second background service starts. Part of my background service is as follows.
AsyncTask<Void, Void,Void> loadTask = new loadingTask().execute();
if(loadTask.getStatus()==AsyncTask.Status.FINISHED){
new mloadingTask().execute(getxml);
System.out.println("getxml: "+getxml);
}
However the second background service doesn't seem to start. i am not getting the a print also. I think I miss a step or android doesn't allow more than one background service in the same activity. A help please.
AsyncTask<Void, Void,Void> loadTask = new loadingTask().execute();
if(loadTask.getStatus()==AsyncTask.Status.FINISHED){
new mloadingTask().execute(getxml);
System.out.println("getxml: "+getxml);
}
there is a 99% chance that the if() block will never pass.
You first execute the first asyncTask named loadTask and RIGHT after check if it finished.
Small chance that it actually finishes by then.
The easy approach:
Use only one async task. You want to finish asyncTask 1 and then fire asyncTask 2, its exactly the same as having only one asyncTask doing both operations.
class loadingTask extends AsyncTask<Void, Void,Void> {
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
pd = ProgressDialog.show(context, "", "Chargement en cours..", true, false);
super.onPreExecute();
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
pd.dismiss();
}
...
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
getxml = Util.CallWebService("");
SAXHelper sh = null;
try {
sh = new SAXHelper(urls[0]);
} catch (MalformedURLException e) {
e.printStackTrace();
}
sh.parseContent("");
return null;
}
}
The difficult approach:
How I solve this kind of thing is(our situation is different, but it should do)
Create an interface, with one method. for example:
public interface OnDataChangedListner {
void dataChanged(Class listener);
}
Then somewhere (i use my repository classes)
write a method to add and remove entires to a list of OnDataChangedListener interfaces
private ArrayList<OnDataChangedListner> mOnDataChangedListners;
public void addOnDataChangedListner(OnDataChangedListner onDataChangedListner){
synchronized (mOnDataChangedListners){
mOnDataChangedListners.add(onDataChangedListner);
}
}
public void removeOnDataChangedListner(OnDataChangedListner onyDataChangedListner){
if (mOnDataChangedListners != null){
synchronized (mOnDataChangedListners){
for (Iterator<OnDataChangedListner> it = mOnDataChangedListners.iterator(); it.hasNext();) {
OnDataChangedListner listener = it.next();
if (listener .equals(onDataChangedListner))
it.remove();
}
}
}
}
This might be overkill. But this example should help you with updating the UI while your tasks are running. A free extra! :))
With the above code in place, create an onDataChanged() method in the same class where u defined the add and remove listener methods.
In that code call a handler
// Need handler for callbacks to the UI thread
final static Handler mHandler = new Handler();
// Create runnable for posting
final Runnable mNotifyDataChanged = new Runnable() {
public void run() {
if (mOnDataChangedListners != null){
synchronized (mOnDataChangedListners){
for (Iterator<OnDataChangedListner> it = mOnDataChangedListners.iterator(); it.hasNext();) {
OnDataChangedListner listener = it.next();
if (listener != null)
listener.dataChanged(this.getClass());
else
it.remove();
}
}
}
}
};
/**
* will notify registerred delegates on the main (UI) thread
*/
public void notifyDataChanged(){
mHandler.post(mNotifyDataChanged);
}
Ok, so I ended up giving out an entire sample.
Where you place this code is upto you. But when you call notifyDataChanged() it will fire the handler, which in turn will loop trough all current registered listeners for this class
then in turn it will call the listeners datachanged method.
To make this all work, all you have to do is have a class implement the interface
call addOnDataChangedListener(this);
and implement the method provided in the interface.
Note that this is deffinetly not the easiest way to do things.
I don't know what the easiest way to do what you want is. I never have been in that situation before.
but you can execute the second task in the implemented method. Should work..
AsyncTask is Asynchronous as its name suggest. You need to call your 2nd AsyncTask in onPostExecute of your 1st AsyncTask
OR
Loop and wait till AsyncTask is finished in your activity, but it may take more time and you can get Application Not Responding message.
As soon as you call execute() method, control comes to next statement which loadTask.getStatus(). As task is just started, loadTask.getStatus() will not return FINISH and your 2nd task is never getting executed.

How to waits the thread till another thread completes

I want to show the progress dialog while loading the images in grid view.
The problem i'm facing was the current thread and Progress Dialog thread running simultaniously.
public String Method1(){
String output="";
final ProgressDialog aProgDialogL = ProgressDialog.show(this, "", "Loading...");
Thread thread = new Thread() {
public void run () {
//My codes
aHandlerL.post(new Runnable() {
#Override
public void run() {
//Post Runnable codes
aProgDialogL.dismiss();
}
});
}
};
thread.start();
/*
*
*
* OTHER CODES
*
*
*/
return output;
}
In the above example I need to run the code inside Progress Dialog Thread. After it finish executing i need to run my "OTHER CODES". How to do it?
.
I tried using Async task. Before async task completes method1 gets extcuted and reurning the string.
public String Method1(){
String result="";
new GetImages().execute();
return result;
}
public class GetData extends AsyncTask<Void, Void, Integer>{
#Override
protected void onPreExecute() {
aProgDialogL = ProgressDialog.show(Main.this, "", "Loading...");
}
#Override
protected Integer doInBackground(Void... params) {
//Progress Dialig Code
return null;
}
#Override
protected void onPostExecute(Integer result) {
aProgDialogL.dismiss();
//OTHER CODES
super.onPostExecute(result);
}
}
You can use Async task. http://developer.android.com/reference/android/os/AsyncTask.html. There is a good tutorial here. http://www.vogella.com/articles/AndroidPerformance/article.html.Also have a look at this link
http://developer.android.com/guide/components/processes-and-threads.html. Use asynctask modify it according to your needs.
doInBackground()- For long running operations. Don't update ui here.
onPreExecute()- update ui before running the operatio nin background.
onPostExecute()- update ui after running the operation.
I would suggest you to take somewhat different approach.
Dont involve any threads in Method1() function.Rather your Method1() function should be run under separate thread.
Below snippet will help you.
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((Button) findViewById(R.id.btnPopup))
.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
new Thread() {
public void run() {
String answer = Method1();
runOnUiThread(new Runnable() {
#Override
public void run() {
// Here you will write the code which is
// to be executed on main thread.
}
});
};
}.start();
}
});
}
public String Method1() {
// Write code
return "result";
}
}
Instead of that : What about use Timer After specific Time Stop Your thread and and write your code you want after stop statement Like that :
Timer timer=new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
thread.stop;
// Other code }
}, Time You want );

Android: TimerTask scheduled for repetition getting fired only once

Ok this is a very weird problem I am having, and I'm pretty sure that I am messing up somewhere, but I can't quite figure out where.
What I am trying is -
Schedule a Timer to execute a TimerTask every five seconds
The TimerTask in turn executes an AsyncTask (which in this case simple sleeps for a second before returning the static count of the number of AsyncTasks).
Finally, the aforementioned count is updated in the UI.
And of course, the appropriate Handlers and Runnables have been used to post asynchronous messages from other threads to the UI.
This code executes only once. I expect it to fire every 5 seconds. Here's the code.
Note: I had no idea what to do with the Looper. I put it there after trial and error!
public class TimerAsyncMixActivity extends Activity {
public static final String TAG = "TimerAsyncMix";
static int executionCount = 0;
Handler mHandler = new Handler();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new Timer().schedule(new MyTimerTask(this), 0, 5000);
}
class MyAsyncTask extends AsyncTask<String, Void, Integer>{
#Override
protected Integer doInBackground(String... params) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return ++executionCount;
}
#Override
protected void onPostExecute(Integer result) {
mHandler.post(new UpdateUiThread(TimerAsyncMixActivity.this, result));
super.onPostExecute(result);
}
}
}
class MyTimerTask extends TimerTask{
private TimerAsyncMixActivity tma;
public MyTimerTask(TimerAsyncMixActivity tma) {
this.tma = tma;
}
#Override
public void run() {
Looper.prepare();
Log.d(TimerAsyncMixActivity.TAG, "Timer task fired");
tma.new MyAsyncTask().execute();
Looper.loop();
Looper.myLooper().quit();
}
}
class UpdateUiThread implements Runnable{
int displayCount;
TimerAsyncMixActivity tma;
public UpdateUiThread(TimerAsyncMixActivity tma, int i) {
this.displayCount = i;
this.tma = tma;
}
#Override
public void run() {
TextView tv = (TextView) tma.findViewById(R.id.tvDisplay);
tv.setText("Execution count is : "+displayCount);
}
Can anyone point me to what I'm doing wrong?
techie, this is how I implemented similar things. I'm won't claim that this is the best way, but it has worked for me and doesn't look too bad.
I have the following code in my activity. I create an async task when the activity starts and I stop it onPause. The AsyncTask does whatever it needs to do, and updates the UI on onProgressUpdate() (which is run on the UI thread, so there's no need to use a Handler).
private Task task;
#Override
protected void onPause() {
task.stop();
task = null;
}
#Override
protected void onResume() {
task = new Task();
task.execute();
}
private class Task extends AsyncTask<Void, String, Void> {
private boolean running = true;
#Override
protected Void doInBackground(Void... params) {
while( running ) {
//fetch data from server;
this.publishProgress("updated json");
Thread.sleep(5000); // removed try/catch for readability
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
if( ! running ) {
return;
}
String json = values[0];
//update views directly, as this is run on the UI thread.
//textView.setText(json);
}
public void stop() {
running = false;
}
}
Do not use a timer. If your phone goes to sleep, the timer is suspended too. Use AlarmManager.

Categories

Resources