AsyncTask run 5 times and then not run doInBackground method - android

click the button to call this method:
private void goRegister(final boolean isUsername) {
new Loading.LoadTast(ctx) {
#Override
protected String doInBackground(Integer... params) {
Looper.prepare();
String msg=doRegister(isUsername);
closeProgressDialog();
if(msg == null || msg.length() == 0) {
SmartNgApplication.getInstance().exit();
} else {
BaseHelper.showToast(ctx, msg);
}
Looper.loop();
return null;
}
}.execute();
}
and this is LoadTast class:
public abstract static class LoadTast extends AsyncTask <Integer, Integer, String > {
private ProgressDialog progressDialog;
private Context ctx;
public LoadTast(Context ctx) {
this.ctx=ctx;
}
protected abstract String doInBackground(Integer... params);
public void onPreExecute() {
super.onPreExecute();
progressDialog=ProgressDialog.show(ctx, "", "loading...", true, false);
}
public void onPostExecute(String result) {
super.onPostExecute(result);
progressDialog.dismiss();
BaseHelper.showToast(ctx, result);
}
public void closeProgressDialog() {
if(progressDialog != null) {
progressDialog.dismiss();
}
}
}
my program is:
when I click 5 times the button don't call doInbackground method and the screen always run a loading. I guess the code is run onPreExecute and not run doInbackground. Why??
in the AsyncTask has a thread pool,the CORE_POOL_SIZE=5. How to solution the program,Help me thank you !

asyncTask isn't supposed to run its doInBackground more than once , and it's also not supposed to be a loopy thread .
asyncTask is supposed to be a one time thing that you run , and you can only assume that if multiple asyncTasks have executed , at least one will run at the same time.
another thing i've noticed : you called closeProgressDialog from within doInBackground , but that's a UI related operation ,while the doInBackground is being ran on a non-UI thread.

I have had this problem myself. I solved it by executing the AsyncTasks in the thread pool, instead of serial.
To do this, you have to call your AsyncTasks like this:
YourAsyncTask task = new YourAsyncTask();
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
That should solve the issue you have.

Related

Abort Jsoup request [duplicate]

I use an async task to upload an image and get some results.
While uploading the image I see a progress dialog, written in onPreExecute() method like this:
protected void onPreExecute() {
uploadingDialog = new ProgressDialog(MyActivity.this);
uploadingDialog.setMessage("uploading");
uploadingDialog.setCancelable(true);
uploadingDialog.show();
}
Ok when I press the back button, obviously the dialog disappears because of the setCancelable(true).
But (obviously) the async task doesn't stop.
So how can I fix this? I want to cancel both dialog and async task when I press the back button. Any ideas?
From SDK:
Cancelling a task
A task can be cancelled at any time by invoking cancel(boolean).
Invoking this method will cause subsequent calls to isCancelled()
to return true.
After invoking this method, onCancelled(Object), instead of
onPostExecute(Object) will be invoked after doInBackground(Object[]) returns.
To ensure that a task is cancelled as quickly as possible,
you should always check the return value of isCancelled() periodically from
doInBackground(Object[]), if possible (inside a loop for instance.)
So your code is right for dialog listener:
uploadingDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
myTask.cancel(true);
//finish();
}
});
Now, as I have mentioned earlier from SDK, you have to check whether the task is cancelled or not, for that you have to check isCancelled() inside the onPreExecute() method.
For example:
if (isCancelled())
break;
else
{
// do your work here
}
FOUND THE SOLUTION:
I added an action listener before uploadingDialog.show() like this:
uploadingDialog.setOnCancelListener(new DialogInterface.OnCancelListener(){
public void onCancel(DialogInterface dialog) {
myTask.cancel(true);
//finish();
}
});
That way when I press the back button, the above OnCancelListener cancels both dialog and task. Also you can add finish() if you want to finish the whole activity on back pressed. Remember to declare your async task as a variable like this:
MyAsyncTask myTask=null;
and execute your async task like this:
myTask = new MyAsyncTask();
myTask.execute();
I spent a while figuring this out, all I wanted was a simple example of how to do it, so I thought I'd post how I did it. This is some code that updates a library and has a progress dialog showing how many books have been updated and cancels when a user dismisses the dialog:
private class UpdateLibrary extends AsyncTask<Void, Integer, Boolean>{
private ProgressDialog dialog = new ProgressDialog(Library.this);
private int total = Library.instance.appState.getAvailableText().length;
private int count = 0;
//Used as handler to cancel task if back button is pressed
private AsyncTask<Void, Integer, Boolean> updateTask = null;
#Override
protected void onPreExecute(){
updateTask = this;
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setOnDismissListener(new OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
updateTask.cancel(true);
}
});
dialog.setMessage("Updating Library...");
dialog.setMax(total);
dialog.show();
}
#Override
protected Boolean doInBackground(Void... arg0) {
for (int i = 0; i < appState.getAvailableText().length;i++){
if(isCancelled()){
break;
}
//Do your updating stuff here
}
}
#Override
protected void onProgressUpdate(Integer... progress){
count += progress[0];
dialog.setProgress(count);
}
#Override
protected void onPostExecute(Boolean finished){
dialog.dismiss();
if (finished)
DialogHelper.showMessage(Str.TEXT_UPDATELIBRARY, Str.TEXT_UPDATECOMPLETED, Library.instance);
else
DialogHelper.showMessage(Str.TEXT_UPDATELIBRARY,Str.TEXT_NOUPDATE , Library.instance);
}
}
create some member variables in your activity like
YourAsyncTask mTask;
Dialog mDialog;
use these for your dialog and task;
in onPause() simply call
if(mTask!=null) mTask.cancel();
if(mDialog!=null) mDialog.dismiss();
I would like to improve the code. When you canel the aSyncTask the onCancelled() (callback method of aSyncTask) gets automatically called, and there you can hide your progressBarDialog.
You can include this code as well:
public class information extends AsyncTask<String, String, String>
{
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... arg0) {
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
this.cancel(true);
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
}
#Override
protected void onCancelled() {
Toast.makeText(getApplicationContext(), "asynctack cancelled.....", Toast.LENGTH_SHORT).show();
dialog.hide(); /*hide the progressbar dialog here...*/
super.onCancelled();
}
}
Most of the time that I use AsyncTask my business logic is on a separated business class instead of being on the UI. In that case, I couldn't have a loop at doInBackground(). An example would be a synchronization process that consumes services and persist data one after another.
I end up handing on my task to the business object so it can handle cancelation. My setup is like this:
public abstract class MyActivity extends Activity {
private Task mTask;
private Business mBusiness;
public void startTask() {
if (mTask != null) {
mTask.cancel(true);
}
mTask = new mTask();
mTask.execute();
}
}
protected class Task extends AsyncTask<Void, Void, Boolean> {
#Override
protected void onCancelled() {
super.onCancelled();
mTask.cancel(true);
// ask if user wants to try again
}
#Override
protected Boolean doInBackground(Void... params) {
return mBusiness.synchronize(this);
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
mTask = null;
if (result) {
// done!
}
else {
// ask if user wants to try again
}
}
}
public class Business {
public boolean synchronize(AsyncTask<?, ?, ?> task) {
boolean response = false;
response = loadStuff(task);
if (response)
response = loadMoreStuff(task);
return response;
}
private boolean loadStuff(AsyncTask<?, ?, ?> task) {
if (task != null && task.isCancelled()) return false;
// load stuff
return true;
}
}
I had a similar problem - essentially I was getting a NPE in an async task after the user had destroyed the activity. After researching the problem on Stack Overflow, I adopted the following solution:
volatile boolean running;
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
running=true;
...
}
public void onDestroy() {
super.onDestroy();
running=false;
...
}
Then, I check "if running" periodically in my async code. I have stress tested this and I am now unable to "break" my activity. This works perfectly and has the advantage of being simpler than some of the solutions I have seen on SO.
You can just ask for cancellation but not really terminate it. See this answer.
How to cancel AsyncTask
Full answer is here - Android AsyncTask Example
AsyncTask provides a better cancellation strategy, to terminate currently running task.
cancel(boolean mayInterruptIfitRunning)
myTask.cancel(false)- It makes isCancelled returns true. Helps to cancel the task.
myTask.cancel(true) – It also makes isCancelled() returns true, interrupt the background thread and relieves resources .
It is considered as an arrogant way, If there is any thread.sleep() method performing in background thread, cancel(true) will interrupt background thread at that time. But cancel(false) will wait for it and cancel task when that method completes.
If you invoke cancel() and doInBackground() hasn’t begun execute yet. onCancelled() will invoke.
After invoking cancel(…) you should check value returned by isCancelled() on doInbackground() periodically. just like shown below.
protected Object doInBackground(Params… params) {
while (condition)
{
...
if (isCancelled())
break;
}
return null;
}

Cannot pass values to an AsyncTask in Android

I am using an AsyncTask in an activity.
here is my code
public class MyActivity extends AppCompatActivity {
EditText editUserNameLogin;
EditText editPassLogin;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
//ButterKnife.bind(this);
editUserNameLogin = (EditText) findViewById(R.id.input_username_login);
editPassLogin = (EditText) findViewById(R.id.input_password_login);
}
public class AsyncTaskClass extends AsyncTask<String, String, String> {
String strUserName = editUserNameLogin.getText().toString();
String passLogin = editPassLogin.getText().toString();
#Override
protected void onPreExecute() {
}
#Override
protected String doInBackground(String... params) {
Toast.makeText(MyActivity.this, passLogin, Toast.LENGTH_SHORT).show();
}
#Override
protected void onPostExecute(String r) {
}
}
but in doInBackground can't get values passLogin or strUserName
(Toast.makeText(MyActivity.this, passLogin,) don't show any text)
Try and execute AsyncTaskClass in onCreate
new AsyncTaskClass().execute(); //use this method and call this in onCreate
Try this one, inside onCreate
String response="checking";
new AsyncTaskClass().execute(response);
then create inner class AsyncTaskClass,
private class AsyncTaskClass extends AsyncTask<String,Void,String > {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... strings) {
String respose1 = strings[0];
return respose1;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);}
}
You can not perform UI operation inside background AsyncTask doInBackground method because AsyncTask not work with current UI thread, its create new thread while you initialize and execute.
Let me explain you in bref.
While activity start its stay with Activity Thread and when you complete activity operation and destroy its completely remove from operation task.
But while you start AsyncTask on Activity its start with individual operation stat that not depends on activity that you start, so if you perform UI operation in doInBackground method and in case Activity destroyed and you working on UI that already destroyed by activity and UI cannot get reference, its generate an exception. So it's necessary to work with current activity thread not another background thread.
There are many case that you can pass data inside AsyncTask, i'm comfortable with below operation, it can help you also.
// Pass data to AsyncTask comma separated values
new MyBackgroundTask().execute("Hello there!","How are you?");
private class MyBackgroundTask extends AsyncTask<String, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(String... strings) {
String message1 = strings[0];
String message2 = strings[1];
Log.d("_TAG_", "First String: " + message1);
Log.d("_TAG_", "Second String: " + message2);
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
}
}
For more information read Android Official Documents AsyncTask Developer Guides
You cant show ui operations like toast in doInBackground if you still want to do that then use this code to display toast while in doInBackground
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this, "", Toast.LENGTH_SHORT).show();
}
});
and also you need to call yourAsyncTaskObject.execute to start asynctask
I have no idea what exactly you want to achieve by such behavior.
But i am pointing out some point here . First of all you can not access any UI element in background thread .
#Override
protected String doInBackground(String... params) {
Toast.makeText(MyActivity.this, passLogin, Toast.LENGTH_SHORT).show();
}
The above code is not going to work as doInBackground runs asynchronously separate from UI thread.
If you want to show a toast on AsyncTask started then do it in onPreExecute or after execution do it in onPostExecute.
#Override
protected void onPreExecute() {
Toast.makeText(MyActivity.this, passLogin, Toast.LENGTH_SHORT).show();
}
And as i see you never execute the AsyncTask then how are you expecting anything from it. Do call execute().
new AsyncTaskClass().execute();
For more on AsyncTask read AsyncTask.
Try the following:
#Override
protected String doInBackground(String... params) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(MyActivity.this, passLogin, Toast.LENGTH_SHORT).show();
}
});
}
AsyncTask enables proper and easy use of the UI thread. This class
allows you to perform background operations and publish results on the
UI thread without having to manipulate threads and/or handlers.
new AsyncTaskClass("SEND STRING").execute();
You can pass this Your Value this way
private class AsyncTaskClass extends AsyncTask<String, String, String> {
String strRESPONSE="";
public MyAsyncTask(String str_GET) {
this.strRESPONSE=str_GET; // print "SEND STRING"
}
}

AsycTask thread inside doInBackground runs after PostExecution has started

I am using AsyncTask and there are threads running inside the doInBackground method, isn't the purpose of AsyncTask is to let all the code finish executing inside the doInBackground and THEN go to PostExecute? Then why is it that some of my threads are running after the code block in PostExecution has started?
What should I do to solve this problem?
public class myActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
...
}
#Override
public void onClick(View view) {
new myTask().execute();
}
class myTask extends AsyncTask<Void, Void, Void> {
Boolean success;
#Override
protected void onPreExecute() {
success = true
}
#Override
protected Void doInBackground(Void... params) {
try {
Callback callback = new Callback() {
public void successCallback(String name, Object response) {
}
public void errorCallback(String name, error) {
success = false;}
};
} catch (Exception e) {
success = false;
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
if (success == true){
// do something
}
}
}
}
It is inside the error callback, that I want the success field to change to false. But the error callback runs after the postExecute method.
I think that you misunderstand the threading model.
AsyncTask does indeed execute doInBackground first, on a background thread, and then executes onPostExecute on the foreground thread, passing it the result from doInBackground.
However, from the wording of your question, it sounds like you are starting new threads from doInBackground. I'm sure that doInBackground does indeed complete before onPostExecute starts, but there is nothing that would cause the AsyncTask to wait for your additional threads to complete as well.
Edit:
It looks like you could skip the AayncTask altogether. The reason that you have callbacks is probably that method is already asynchronous
But note that you are only creating the callback, never using it. Perhaps you just left that part out?

Android : Get status of Asynctask and wait

I am using Asynctask to load all the contacts from the device. Although it has been discussed many times that Contacts.Contract is really slow and take me 10-15 secs to load all contacts data with image and all other data like email etc. So I have decided to start a service with asynctask on the splash screen.
Now the problem is
I have activity series A-B-C-D
Asynctask starts in Activity A and I want Contacts in Activity D. If all contacts is loaded till user reaches Activity D then its ok. But if user reaches Activity D and service is still running than I need to make user wait.
So my question is HOW TO WAIT FOR ASYNCTASK TO FINISH in Activity D. I will show a simple progress bar in activity D till Asynctask finishes. BUT HOW?
I have an idea to make async series in just one async task:
protected Boolean doInBackground(String... params) {
if(params[0] == "taskA") {
//do somthing
params[0] = "taskB";
}
if(params[0] == "taskB") {
//do somthing
params[0] = "taskC";
}
if(params[0] == "taskC") {
//do somthing
params[0] = "taskD";
}
if(params[0] == "taskD") {
//do somthing
return true;
}
And in your main thread just call async task like this:
ShowMyProgress();
new MyAsyncTask().execute("taskA");
And finally you can hide your progress on onPostExecute like:
protected void onPostExecute(final Boolean success) {
if (success) {
....
HideMyProgress();
}
}
To wait for AsyncTask to finish you can use get() method.
From documentation of get() method:
Waits if necessary for the computation to complete, and then retrieves
its result.
AsyncTask - get()
But this will make your main thread wait for the result of the AsyncTask.
Another way would be that you can show a progress dialog in the async task until it finishes. This way you can get the status calling:
task.getStatus() == Status.RUNNING
And if the status is Status.RUNNING you will just show the progress dialog until will be finished. So, as an example:
final AsyncTask task = MyAsyncTask.getInstance();
final Thread waitingThread = new Thread(new Runnable() {
#Override
public void run() {
try {
// ...
// show progress dialog
while(task.getStatus() != Status.FINISHED) {
TimeUnit.SECONDS.sleep(1);
}
result = task.get();
// ...
// hide progress dialog
} catch (InterruptedException e) {
// TODO log
}
}
});
waitingThread.start();
The task object is your asyncTask. You can make it Singleton and start in Activity A, and get instance of it in Activity D.
public class MyAsyncTask extends AsyncTask<Void, Void, Void>{
private static MyAsyncTask instance;
private MyAsyncTask(){}
public static MyAsyncTask getInstance() {
// check status if we want to execute it again
if (instance == null) {
instance = new MyAsyncTask();
} else if (instance.getStatus() == Status.FINISHED) {
instance = new MyAsyncTask();
}
return instance;
}
#Override
protected Void doInBackground(Void... params) {
// do smth
return null;
}
}
Haven't tried this in action but I think it will work.
you can do
myAsyn asyn = new myAsyn();
asyn.execute();
while(asyn.getStatus()!=Aynctask.Status.Finished)
{
Thread.sleep(100);
}
instead of waiting for asyntask to finish, you can simply show a progress dialog.
public class myAsyn extends AsyncTask<Void, Void, Void>{
private ProgressDialog dialog;
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
dialog = new ProgressDialog(context);
dialog.setMessage("Loading...");
dialog.setCanceledOnTouchOutside(false);
dialog.show();
}
#Override
protected Void doInBackground(String... arg0) {
// TODO Auto-generated method stub
//do your work
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
dialog.dismiss();
}
}
It is simple i will explain..
You can get the status of the async task task...like this
if (o2.getStatus() == Status.FINISHED) { ////o2 is a asynch task instance...
} else if (o2.getStatus() == Status.RUNNING) {
} else if (o2.getStatus() == Status.PENDING) {
}
AsyncTask has basically onPreExecute and doInbackground, and onPostExecute exists. The meaning of each!
onPreExecute:
Runs on the UI thread before doInBackground (Params. ..).
opPostExecute:
Runs on the UI thread after doInBackground (Params. ..). The specified result is the value returned by doInBackground (Params. ..).
This method won't be invoked if the task was cancelled.
The order in which the calls
One. onPreExecute
Two. doInbackground
Three. onPostExecute
However doInbackground operate in the other thread.
Must be treated so well doInbackground result is passed three times because of onPreExecute() to create a progress bar progress bar to end its onPostExecute could work.
Please try this
public class LoadData extends AsyncTask<Void, Void, Void> {
ProgressDialog progressDialog;
//declare other objects as per your need
#Override
protected void onPreExecute()
{
progressDialog= ProgressDialog.show(YourActivity.this, "Progress Dialog Title Text","Process Description Text", true);
//do initialization of required objects objects here
};
#Override
protected Void doInBackground(Void... params)
{
//do loading operation here
return null;
}
#Override
protected void onPostExecute(Void result)
{
super.onPostExecute(result);
progressDialog.dismiss();
};
}
You can call this using
LoadData task = new LoadData();
task.execute();
To check whether your Service is still running::
private boolean isMyServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (MyService.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}

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

Categories

Resources