How to stop AsyncTask in infinite loop? - android

I have AsyncTask and my progress in background is in infinite loop. But I need to stop AsyncTask when user stop my app or go back from my app (my app go to foreground). How can I do it?
Solution:
private boolean done = false;
private class CurTask extends AsyncTask<String, Void, Object> {
protected Void doInBackground(String... args) {
while(!done){
DefaultCurProgress();
publishProgress();
}
}
protected void onProgressUpdate(Void...unused) {
textCur = (TextView)findViewById(R.id.text_cur);
SharedPreferences myPrefs = MyActivity.this.getSharedPreferences("myPrefs", MODE_PRIVATE);
String prefNameDefaultCur = myPrefs.getString(DefaultCur, "");
textCur.setText(prefNameDefaultCur);
}
}
#Override
public void onPause(){
super.onPause();
done=true;
}
#Override
public void onResume(){
super.onResume();
done=false;
}

Declare a method within your AsyncTask that tells it to end. Something like so:
private class CurTask extends AsyncTask<String, Void, Object> {
private boolean done = false;
public void quit() {
done = true;
}
protected Void doInBackground(String... args) {
while(!done){
DefaultCurProgress();
publishProgress();
}
}

Add a boolean member variable and use that in your while condition instead of true.
Then when you need to cancel it you can just call an instance method to set this variable to false, the doInBackground method will return and the task will finish.

Related

How can I make sure that Async task is only calling once

I have a method which has a async task and it is called from several different services and those services runs periodically . I want to make sure when one task is on going , no other thing can call it unless the task is finished.
public class Helper {
public static void doSomethingAsync() {
new AsyncTask<String, Void, Integer>() {
#Override
protected void onPreExecute() {
}
#Override
protected Integer doInBackground(String... strings) {
//doing something
}
#Override
protected void onPostExecute(Integer resultCode) {
}
}.execute();
}
public static void someOtherMethod(){
}
}
AsyncTask.getStatus() will give the status of the task, i.e. whether finished or not.
Declare a member variable
private static AsyncTask<String, Void, Integer> mTask;
Modify your method as,
public static void doSomethingAsync() {
if(null != mTask && mTask.getStatus() != AsyncTask.Status.FINISHED){
return; //Returning as the current task execution is not finished yet.
}
mTask = new AsyncTask<String, Void, Integer>() {
#Override
protected void onPreExecute() {
}
#Override
protected Integer doInBackground(String... strings) {
//doing something
}
#Override
protected void onPostExecute(Integer resultCode) {
}
};
mTask.execute();
}
You can try this by making your "doSomethingAsync()" as synchronized method.
public synchronized static void doSomethingAsync() {
new AsyncTask<String, Void, Integer>() {
#Override
protected void onPreExecute() {
}
#Override
protected Integer doInBackground(String... strings) {
//doing something
}
#Override
protected void onPostExecute(Integer resultCode) {
}
}.execute();
}
Note:
static synchronized method will lock the class instead of the object, and it will lock the class because the keyword static means: "class instead of instance". The keyword synchronized means that only one thread can access the method at a time.
And together they mean: "Only one can access class at one time".
Make sure all your services has access to same Mutex which can be accesses throughout your application.
Now before accessing the Async Task, do as follows
public class Mutex {
public void acquire() throws InterruptedException { }
public void release() { }
public boolean attempt(long msec) throws InterruptedException { }
}
Which then can be used as:
try {
mutex.acquire();
try {
// do something
} finally {
mutex.release();
}
} catch(InterruptedException ie) {
// ...
}
Check out more details over here
In Android we have Semaphore. For which the following will be the steps
java.util.concurrent.Semaphore semaphore=new Semaphore(1);
boolean isAvailable = semaphore.tryAcquire();
if(isAvailable){
// Access AsyncTask
}
Once all actions are done, till onPostExecute
semaphore.release();
Try using an IntentService instead as this supports queuing and runs in a background thread
You should refer Synchronization concept, it will help u.
Link

asyncTask not working for me

I have an IME service class and a long operation method in it. I want to run the LongOperation task in a asyncTask class that is in the IME Service class.
public class Myimeservice extends InputMethodService
implements KeyboardView.OnKeyboardActionListene {
//...
//some code here....
//...
public void setDictionary(){
//....
}
private class LongOperation extends AsyncTask<String, Void, String> {
private Myimeservice parent;
public LongOperation(Myimeservice pim){
parent = pim;
}
#Override
protected String doInBackground(String... params) {
Myimeservice tmp = new Myimeservice();
tmp.setDictionary();
return "Executed";
}
#Override
protected void onPostExecute(String result) {
//app.hideLoading();
}
#Override
protected void onPreExecute() {
//app.showLoading();
}
#Override
protected void onProgressUpdate(Void... values) {}
}
When i run it, the application forced to close. please help me.
I think the error is somewhere in your public void setDictionary() method.
I assume that you are manipulating a variable that is bound to the UIThread/MainThread, the application will crash since doInBackground is on another Thread.
Instead make the setDictionary() method return the dictionary and return it instead of "Executed" in doInBackground().
This will call the onPostExecute(Object result) which is run on UIThread/MainThread.
Something like this:
private class LongOperation extends AsyncTask<String, Void, Dictionary> {
#Override
protected Dictionary doInBackground(String... params) {
Myimeservice tmp = new Myimeservice();
Dictionary dict = tmp.setDictionary();
return dict;
}
#Override
protected void onPostExecute(Dictionary result) {
//do what ever you meant to do with it;
}
}
If you are not expecting any result from it you can just do:
AsyncTask.execute(new Runnable() {
#Override
public void run() {
tmp.setDictionary();
}
});
I use the Runnable instead of AsyncTask and the problem solved.
final Runnable r = new Runnable(){
public void run(){
setDictionary();
}
};
this code is in onCreate() method of service.
Tanks a lot Tristan Richard.

Can't start activity from onPostExecute

I have an AsyncTask where I make request to server and download some data. And according to received data I start Activity A or Activity B in onPostExecute().
The problem is that doesn't work. No errors, simply activity doesn't start. Seems like code isn't executed there at all.
private class LoadingAsyncTask extends AsyncTask<Boolean, Void, Boolean> {
protected Void doInBackground(Boolean... params) {
if (InternetConnection.isConnected(ActivityLoading.this)) {
.....load data
} else {
Toast.makeText(ActivityLoading.this, getString(R.string.no_internet_connection), Toast.LENGTH_SHORT).show();
}
isDone = true;
return isDone;
}
protected void onPostExecute(Void isDone) {
super.onPostExecute(isDone);
//if work is done
if (isDone) {
if (dwnlData.equals("success")) {
getApplicationContext().startActivity(new Intent(ActivityLoading.this, ActivityNavigation.class));
} else {
getApplicationContext().startActivity(new Intent(ActivityLoading.this, ActivityAuthorization.class));
}
}
}
I call AsyncTask in onCreate:
public class ActivityLoading extends ActionBarActivity {
static boolean isDone = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_loading);
new LoadingAsyncTask().execute();
}
Change the argument data type void to boolean
protected void onPostExecute(boolean isDone) {
super.onPostExecute(isDone);
//if work is done
if (isDone) {
if (dwnlData.equals("success")) {
getApplicationContext().startActivity(new Intent(ActivityLoading.this, ActivityNavigation.class));
} else {
getApplicationContext().startActivity(new Intent(ActivityLoading.this, ActivityAuthorization.class));
}
}
Did you try making isDone a boolean?
Edit - You could just make doInBackground return nothing, and stop using the argument in onPostExecute.
I suggest using Log.d() or Toast() inside those if{} blocks to verify that your conditions are true

Execute onPostExecute on cancelling AsyncTask

As far as I understand once an AsyncTask is called, the result is changed to null and the AsyncTask is cancelled. Is there a way to retain the result and pass it to onPostExecute(String result). developer.android.com says not to call these functions explicitly.
The app basically scans images and if a user cancels the async task, I'd like the async task to display the images scanned so far. So the result should not be set to null.
Is this possible to accomplish? If yes, how?
class openCVOperation extends AsyncTask<String, String, String>{
private MainActivity context = null;
/*lots of variables here*/
public openCVOperation(MainActivity context1) {
context = context1;// set context from mainActivity
// which
// inherits Activity super class.
// Needed
// for accessing widgets.
}
#Override
protected void onPreExecute() {
pd = new ProgressDialog(context);
pd.setIndeterminate(false);
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setMax(100);
pd.setCancelable(true);
pd.setCanceledOnTouchOutside(false);
pd.setMessage("Starting up");
pd.show();
}
#Override
protected String doInBackground(String... params) {
publishProgress("Finding path to Storage...");
path = Environment.getExternalStorageDirectory();
p = path.getAbsolutePath();
p=p+"/location";
rm(p);// this has a loop!
return null;
}
#Override
protected void onCancelled()
{
System.out.println("In onCancelled");
super.onCancelled();
}
#Override
protected void onPostExecute(String result) {
pd.dismiss();
/*post execute stuff*
}
rm(p) has a loop, so I tried using isCancelled() as a condition, but that didn't work.
In the doInBackground
if (isCancelled())
{
return // image so far
}
onPostExecute(String result)
{
// show result
}
I just had to add this to my doInBackground()
pd.setOnCancelListener(new DialogInterface.OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
// TODO Auto-generated method stub
task.cancel(true);
}
});
Where pd is my progress dialog.
Also make sure you check for isCancelled() in doInBackground() or onCancelled() will never be invoked and the application will force close.
Collect the results:
public class MyTask extends AsyncTask<Void,Void,Void>{
private final List<String> data;
public MyTask(){
data = new ArrayList<String>();
}
public synchronized List<String> getData(){
return new ArrayList<String>(data); //--current data snapshot--
}
private synchronized collect(String s){
data.add(s);
}
#Override
public Void doInBackground(Void...args){
//---do stuff--
collect(/*-stuff-*/);
}
}
You won't lose anything even if thread is interrupted.
If onCancelled is not being called, then your rm method is still running.
Because as you mentioned, it's running a loop.
The best way to control the process (know if it needs to be stopped) is by polling or tediously checking the status of a volatile boolean variable within your rm method.
For example, create a static volatile boolean variable within your AsyncTask class called cancel. Set this variable to false in the onPreExecute method.
In your rm method, check to see if cancel is true before and after the heavy tasks (opening a file, reading a file, part of a download loop).
If it's true, then break out of the method with a return statement.
Better yet, make your rm method return an Integer, 0 for Good and 1 for cancelled.
And finally, right before the doInBackground method hits return, see if you need to call a cancel on the thread or not.
public class asyncTask extends AsyncTask<Void, Void, Void>
{
private static synchronized boolean cancel;
protected void onPreExecute()
{
cancel = false;
}
protected String doInBackground(Void ... params)
{
rm(p);
if(cancel)
asyncTask.cancel;
else
return null;
}
protected void onCancelled()
{
// only executed if doInBackground resulted in a cancel == true
}
protected void onPostExecute(Void param)
{
/// only executed if doInBackground resulted in a cancel == false
}
private int rm(String str)
{
if(cancel)
return 1;
//do part of task
if(cancel)
return 1;
//another part of task
if(cancel)
return 1;
//another part of task
return cancel ? 1 : 0;
}
}

multithreading UI : exceptionininitializererror and runtime exception android

I'm trying to make multithreading but I've got this stacktrace on few smartphones (SGS2) :
java.lang.ExceptionInInitializerError
at com.android.bordeaux.code.model.AnnouncersContainer.setLoudArrayFromJSON_online(AnnouncersContainer.java:68)
at com.android.bordeaux.code.SplashscreenActivity_Second$1.run(SplashscreenActivity_Second.java:55)
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:121)
at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
at android.os.AsyncTask.<clinit>(AsyncTask.java:152)
... 2 more
Here is my main activity (splashscreen) wich is making wait during few seconds in order to wait my asynctask finish:
public class SplashscreenActivity_Second extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.splashscreen_second);
// thread
Thread splashThread = new Thread()
{
#Override
public void run()
{
try
{
int waited = 0;
if (isInternetOn())
{
// Here I'm making my asynctask !!
AnnouncersContainer.setLoudArrayFromJSON_online(getApplicationContext());
while (waited < 5000)
{
sleep(50);
waited += 40;
}
}
else
{
AnnouncersContainer.setLoudArrayFromXML_local(getApplicationContext());
while(waited < 5000)
{
sleep(50);
waited += 60;
}
}
}
catch( InterruptedException e )
{
e.printStackTrace();
}
finally
{
Intent intent_to_tabhost = new Intent(SplashscreenActivity_Second.this, MyTabActivity.class);
startActivity(intent_to_tabhost);
finish();
}
}
};
splashThread.start();
}
}
Here is my asynctask :
public class DownloadAnnouncers extends AsyncTask<Void, Integer, Boolean>
{
public static Boolean loadFinished = false;
//JSON variables..
private static String url = null;
Context context;
public DownloadAnnouncers(Context context)
{
this.context = context;
}
#Override
protected void onPreExecute()
{
super.onPreExecute();
}
protected Boolean doInBackground(Void... params)
{
// fine retrieving all my JSON data in a global array..
}
#Override
protected void onPostExecute(Boolean downloadedArray)
{
super.onPostExecute(downloadedArray);
}
}
I know the problem is that I'm making multithreading in the UI but someone can tell me how to delete my looping thread and replacing it just with onPostExecute() method of my Asynctask ?? (it could be better to wait for asynctask finishes rather than making wait..)
Or may be help me to correct this bug with multithreading..
EDIT :
my asynctask :
public class DownloadAnnouncers extends AsyncTask<Void, Integer, Boolean>
{
public static Boolean loadFinished = false;
//JSON variables..
private static String url = null;
Context context;
public DownloadAnnouncers(Context context)
{
this.context = context;
}
#Override
protected void onPreExecute()
{
super.onPreExecute();
}
protected Boolean doInBackground(Void... params)
{
// fine retrieving all my JSON data in a global array..
}
#Override
protected void onPostExecute(Boolean downloadedArray)
{
super.onPostExecute(downloadedArray);
Intent intent_to_tabhost = new Intent(context, MyTabActivity.class);
intent_to_tabhost.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent_to_tabhost);
}
}
But now if I press cancel button I'm returning to my splashscreen activity.. and I cannot do ctx.finish() in onPostExecute method..
You can't create a Handler inside a Thread that has not called Looper.prepare(), just as your Error message says:
Can't create handler inside thread that has not called Looper.prepare()
The Handler is created within the AsyncTask, so it's not something you might see at first.
If you want to keep your code as it is you would fix it by moving the creation of the AsyncTask to outside your custom Thread.
However, there is no need for you to create the thread, you can just create your AsyncTask in the ui thread (It will run on it's own thread so it won't lock your phone while working), and perform any action you want after the task is complete in the onPostExecute-method.
class ExampleAsync extends AsyncTask<Void, Integer, Boolean>
{
public static Boolean loadFinished = false;
//JSON variables..
private static String url = null;
Context context;
public DownloadAnnouncers(Context context){
this.context = context;
}
protected Boolean doInBackground(Void... params){
// fine retrieving all my JSON data in a global array..
}
#Override
protected void onPostExecute(Boolean downloadedArray){
Intent intent_to_tabhost = new Intent(context, MyTabActivity.class);
startActivity(intent_to_tabhost);
}
}
And in your Activity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splashscreen_second);
AsyncTask myTask = new ExampleAsync(this);
myTask.execute();
}
Instead of waiting for the asyncTask , use the onPostExecute , which is called on the UI thread only after the task has finished.
You should also cancel the task if the activity was destroyed (for example if the user has pressed the back button while the splash screen is shown) .

Categories

Resources