How can i cancel the AsynsTask in Android? - android

Hi onCancel of dialog i want to cancel to server call but i m facing problem that even i cancel the task, it hits my server and modifies the data. How can I resolve this issue ? Below is my code..
private class UserBoardingTask extends AsyncTask {
#Override
protected void onPreExecute() {
progressDialog = new ProgressDialog(getActivity());
progressDialog.setMessage(getResources().getString(R.string.please_wait));
progressDialog.setIndeterminate(false);
progressDialog.setCancelable(true);
progressDialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
if (userOnBoardingTask!= null && userOnBoardingTask.getStatus() != AsyncTask.Status.FINISHED && !userOnBoardingTask.isCancelled()) {
userOnBoardingTask.cancel(true);
}
}
});
progressDialog.show();
}
#Override
protected Void doInBackground(String... urls) {
String boardingURL=null;
boardingURL= getUrl();
UserOnBoardingDTO userOnBoardingDetailsDTO = AppStateManager.getUserBoardingDetails();
try{
RestAPIManager.putToNSWebService(boardingURL, userOnBoardingDetailsDTO, username, password);
}
catch (Exception e) {
errorMessage=getResources().getString(R.string.unknown_exp);
}
return null;
}
#Override
protected void onCancelled() {
super.onCancelled();
closeProgressDialog();
errorMessage="";
AppStateManager.setUserBoardingDetails(null);
userOnBoardingTask=null;
}
#Override
protected void onPostExecute(Void res) {
closeProgressDialog();
userOnBoardingTask=null;
if(!FieldsValidator.isBlank(errorMessage)){
CommonUtil.showToast(getActivity(),errorMessage);
errorMessage="";
return;
}

Just check isCancelled() once in a while:
protected Object doInBackground(Object... x) {
while (/* condition */) {
// work...
if (isCancelled()) break;
}
return null;
}
and another solution is
protected void onProgressUpdate(String... progress1) {
if(condition){
break;
}
}

Move the dialog out of the async task and only start the task when the dialog is not canceled.

Actually the problem is not termination of your asynsTask but the server hit if a server hit is already done before termination of asynsTask then you must interrupt your server request also.Just terminate your server request using abort method.

Where is userOnBoardingTask declared and where it is assigned to a reference to running task? I suspect this does not store a proper reference when the task tries to cancel it.
I am not sure if it is the actual reason of your problem. But for sure you may get rid of this variable if it is intended to pint at current task. Just change dialog's on cancel listener:
private class UserBoardingTask extends AsyncTask<String, Void, Void> {
#Override
protected void onPreExecute() {
// ...
progressDialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
if (UserBoardingTask.this.getStatus() != AsyncTask.Status.FINISHED
&& UserBoardingTask.this.isCancelled()) {
UserBoardingTask.this.cancel(true);
}
}
});
In fact you may omit UserBoardingTask.this phrase as the inner class can point directly fields of nesting class as far as the names are not obscured by the names of inner class members:
private class UserBoardingTask extends AsyncTask<String, Void, Void> {
#Override
protected void onPreExecute() {
// ...
progressDialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
if (getStatus() != AsyncTask.Status.FINISHED && isCancelled()) {
cancel(true);
}
}
});
EDIT
Another point is that before sending request to the server you may check inside doInBackground you may check if the task has not been cancelled
// ...
#Override
protected Void doInBackground(String... urls) {
// ...
try {
if(isCancelled()) {
throw new Exception("Exit: task cancelled!");
}
RestAPIManager.putToNSWebService(boardingURL, userOnBoardingDetailsDTO, username, password);
// ...

RestAPIManager.putToNSWebService(boardingURL, userOnBoardingDetailsDTO, username, password);
This above code hit the server. So you have to validate the execution of code inbetween cancellation.
Try something like this
try{
if(!userOnBoardingTask.isCancelled())
{
RestAPIManager.putToNSWebService(boardingURL, userOnBoardingDetailsDTO, username, password);
}
}
catch (Exception e) {
errorMessage=getResources().getString(R.string.unknown_exp);
}
This is ok. If user cancel the task before ResetAPIManager code executes. Suppose user try to cancel the task after server call initiated you have to tell already modified or remodify server data or unable to cancel or some message to user. All done through getting server reponse and validate server response if it changed or not.
Use something like this
Var rsponse = RestAPIManager.putToNSWebService(boardingURL,userOnBoardingDetailsDTO, username, password);
Validate the reponse message in onPostExecute() or OnCancelled() method.

If you cancel the asynctask after access this method
RestAPIManager.putToNSWebService(boardingURL,userOnBoardingDetailsDTO, username, password); the async task will cancel after running the above code so you should correct this by creating a new method inside RestAPIManager class and call that method inside OnCancelled method from your asyncTask.

Short Anser: Its not possible stop data posts thru a simple cancel. once an async task runs even if you cancel it mid way data posts will occure. Cancellation can be done in a Simple Run
Check this Post
[Android - Cancel AsyncTask Forcefully

Related

doInBackground is not getting called sometimes Android

In my application, there are multiple asynctasks. Please let me know why doInBackground of an asynctask sometimes does not getting called. Its onPreExecute method gets called. Is there any issue because of multiple asynctasks or something else?
/* ASync class for test table */
public class TestAsynch extends AsyncTask<String, Void, String>{
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
String status = null;
String result1=API_Manager.getInstance().sendTestData(userName);
try {
if(result1 != null) {
// save in db
}
}
}
catch( Exception e) {
e.printStackTrace();
}
return status;
}
#Override
protected void onPostExecute(String status) {
}
}
If your project has multiple asynctasks you must check that there is a limit of asynctasks that can be executed. When you create a new AsyncTask it will be added on a Pool and will be execute only when is possible.
Check this answer:
Multitasking on android
And the docs: ThreadPoolExecutor
Here is an example on how properly handle multiple AsyncTasks AsyncTaskManager
OnPreExecute() gets called on the UI thread and doInBackground() is called on the background thread.
There is one dedicated background thread for the async task. This behaviour can be changed if you want to.
http://android-er.blogspot.in/2014/04/run-multi-asynctask-as-same-time.html
Now, say you have multiple instances of async task and I'm assuming you are calling execute() to run the async tasks. This will trigger all the preExecute immediately since UI thread is free but for the doInBackground it will triggered one by one. Hence it may take some time for the next async task to start.
doInBackground should run on a loop using a Boolean to check before execution. Before your Task is being executed, set a global boolean (may be true/false) depends on which you prefer and values add on thread should call runOnUiThread.
startExect = true;
new TestAsynch().execute();
then change this
public class TestAsynch extends AsyncTask<String, Void, String>{
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
String status = null;
String result1=API_Manager.getInstance().sendTestData(userName);
try {
if(result1 != null) {
// save in db
}
}
}
catch( Exception e) {
e.printStackTrace();
}
return status;
}
#Override
protected void onPostExecute(String status) {
}
}
to this
public class TestAsynch extends AsyncTask<String, Void, String> {
String result1 = null;
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
String status = null;
result1=API_Manager.getInstance().sendTestData(userName);
while (startExecute) {
Thread exe = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(5);
}
catch( Exception e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
if(result1 != null) {
// save in db
}
}
});
}
}); exe.start();
}
return status;
}
#Override
protected void onPostExecute(String status) {
}
}

AsyncTask onPostExecute isnt' getting called

I'm trying to implement a basic login screen for an android app. The flow is as follows:
1) User enters login information and hits submit
2) A LoginRequest which extends AsyncTask is created and executed.
3) The doInBackground will fire some http calls to validate the user credentials
4) The onPostExecute should be getting called to set the loginResults
5) Ui thread sees the login results and continues accordingly.
I'm been simplifying the code to get to the root issue but haven't had any luck so far. Here is the simplified code that still repros the issue.
Inside my activity:
private void tryLogin(String email, String password)
{
this.showProgress(true);
LoginHelper loginHelper = new LoginHelper();
LoginResult result = loginHelper.tryLogin(email, password);
this.showProgress(false);
}
This gets called from my submit buttons on click listener.
Inside LoginHelper:
TestClass test = new TestClass();
public LoginResult tryLogin(String mobileNumber, String password, int deviceId)
{
String loginUrl = "...";
new LoginRequest(test).execute(loginUrl);
while (test.result == null)
{
try {
Thread.sleep(1000);
}
catch (Exception e)
{
//...
}
}
return test.result;
}
This will execute the AsyncTask and wait for the result being continuing.
LoginRequest:
public class LoginRequest extends AsyncTask<String, Void, LoginResult>
TestClass test;
public LoginRequest(TestClass test)
{
this.test = test;
}
#Override
protected LoginResult doInBackground(String... params) {
LoginResult ret = null;
ret = new LoginResult(1,"test");
return ret;
}
#Override
protected void onPostExecute(LoginResult result) {
this.test.result = result;
}
}
I run this through the debugger with breakpoints inside the doInBackground and onPostExecute. The doInBackground executes correctly and returns the LoginResult value, but the onPostExecute breakpoint never gets hit, and my code will wait in the while loop in LoginHelper.
You are basically checking the whole time the variable 'result' of your LoginRequest. But that's not, how AsyncTask works.
From Docs:
AsyncTask allows you to perform asynchronous work on your user
interface. It performs the blocking operations in a worker thread and
then publishes the results on the UI thread, without requiring you to
handle threads and/or handlers yourself.
You can do your work in doInBackground() method and the publish you results in onPostExecute().
onPostExecute runs on UI Thread, to allow you change elements, show the result or whatever you want to do. Your problem is, that you are the whole time blocking the UI Thread with your checking method in tryLogin()
So how to solve it?
Remove the checking method:
public void tryLogin(String mobileNumber, String password, int deviceId)
{
// Starts AsynTasks, handle results there
String loginUrl = "...";
new LoginRequest().execute(loginUrl);
}
in AsyncTask:
public class LoginRequest extends AsyncTask<String, Void, LoginResult>
// Removed Constructor, if you need to pass some other variables, add it again
#Override
protected LoginResult doInBackground(String... params) {
// TODO: Change this to actual Http Request
LoginResult ret = null;
ret = new LoginResult(1, "test");
return ret;
}
#Override
protected void onPostExecute(LoginResult result) {
// Now the result arrived!
// TODO: Use the result
}
}
More Thoughts:
You probably want to store user credentials. If so, make sure the are safe. Link
You might want, depending on results, change some UI. Here's an example:
AsyncTask:
public class LoginRequest extends AsyncTask
private Activity activity;
// Constructor
public LoginRequest(Activity activity) {
this.activity = activity;
}
#Override
protected LoginResult doInBackground(String... params) {
// TODO: Change this to actual Http Request
LoginResult ret = null;
ret = new LoginResult(1, "test");
return ret;
}
#Override
protected void onPostExecute(LoginResult result) {
ActivityLogin acLogin = (ActivityLogin) activity;
if(result.equals("ok")) {
Button loginButton = (Button) acLogin.findViewById(R.id.login-button);
loginButton.setBackgroundColor(Color.GREEN);
//Finish LoginActivity
acLogin.finish();
}
else {
//TODO: Fail Handling
}
}
}
And the start it like this:
new LoginRequest(loginActivity).execute(loginUrl);
I didnt tested the code.
It's AsyncTask so it's calling the LoginRequest and while(test.result) at the same time. You got stuck in the while loop because test.result is not done returning yet. test.result is done in onPostExecute(), so if you move that while loop in that function it will work and onPostExecute() will get called. One way to solve this problem is to implement a callback interface. Put the while loop in the overrided callback method.
refer to my answer here: how to send ArrayList(Bitmap) from asyncTask to Fragment and use it in Arrayadapter
Try This
public class LoginRequest extends AsyncTask<String, Void, LoginResult>
{
TestClass test;
LoginResult ret = null;
public LoginRequest(TestClass test)
{
this.test = test;
}
#Override
protected Boolean doInBackground(String... params) {
ret = new LoginResult(1,"test");
return true;
}
#Override
protected void onPostExecute(Boolean success) {
if(success)
this.test.result = result;
}
}
Temporary solution : You can add this.test.result = result; in the doInbackground() method.
#Override
protected LoginResult doInBackground(String... params) {
LoginResult ret = null;
ret = new LoginResult(1, "test");
this.test.result = result;
return ret;
}
Please post full code to get proper solution.

how can i stop my AsyncTask thread. or stop chatmanager

I developed chat app using xmpp by smack client. I used a background thread for incoming msg notification and working fine. But now when I am in chat view then I don't want notification of incoming msg. so I removed chatmangerlistener. but it is not working .
I used my second method that when I'll come in chat view then my background thread will be close. but i saw that background thread is not closing or stoping. isCancelling method is giving me false.
this is code :-
public class incomingmsg extends AsyncTask<String, Void, String>
{
String msg;
protected String doInBackground(String... urls) {
connection = XMPPLogic.getInstance().getConnection();
// register listeners
ChatManager chatmanager = connection.getChatManager();
chatmangerlistnr = new ChatManagerListener()
{
#Override
public void chatCreated(final Chat chat, final boolean createdLocally) {
chat.addMessageListener(new MessageListener()
{
#Override
public void processMessage(Chat chat, Message message) {
msg = message.getBody();
System.out.println("Received message: "
+ (message != null ? message.getBody() : "NULL"));
GeneratNotification(msg);
}
});
}
};
connection.getChatManager().addChatListener(chatmangerlistnr);
// idle for 20 seconds
/* final long start = System.nanoTime();
while ((System.nanoTime() - start) / 1000000 < 20000) // do for 20 seconds
{
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
*/
System.out.println("is cancellable "+this.isCancelled());
return msg;
}
protected void onPostExecute(String r) {
// GeneratNotification(r);
}
}
I m confusion if isCancellable() method is false then how can i stop it? or how can I remove my chatlistener?
please expert help me.
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.)
Check the documentation for more.
to start you async:
incomingmsg aTask = new incomingmsg();
aTask.execute(...);
to stop you async
aTask.cancel(true);
by convention uses the name of its class starting with capital letter
public class incomingmsg extends AsyncTask<String, Void, String>...
change to:
public class Incomingmsg extends AsyncTask<String, Void, String>...
but it just a good practice
Full example:
AsyncTask<Void, Void, Void> myTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
//do this test ever step of you async task.
if(!isCancelled()){
//do something here
}
return null;
}
#Override
protected void onPostExecute(Void result) {
myTask = null;
}
};
//here u start u task:
myTask.execute(null, null, null);
if(myTask != null){
//here u stop u task:
myTask.cancel(true);
}

ProgressBar does not show immediately in android

I have a base class of an activity and a sub class which extends the base class. The superclass has a async task to perform some action. I call this by running it on the ui thread since otherwise it throws an IllegalInitializerError:
superclass.this.runOnUiThread(new Runnable() {
public void run() {
String p="";
try {
p=new asynctasker().execute().get();
}
}
}
In my async task:
protected void onPreExecute()
{
// TODO Auto-generated method stub
super.onPreExecute();
//showDialog();
Log.d("Now","Inside right now");
dialog = ProgressDialog.show(class_create_event.this, "Loading1", "Please Wait");
}
However the dialog is displayed almost at the end of the request. The I am in part is printed correctly. I know that something is blocking my ui thread. But if I dont call the async task from the UI thread it throws an illegal initializer error. Is there any way out?
You don't need to have UIthread for calling AsyncTask
Call it like this way
FetchRSSFeeds async = new FetchRSSFeeds();
async.execute();
private class FetchRSSFeeds extends AsyncTask<String, Void, Boolean> {
private ProgressDialog dialog = new ProgressDialog(HomeActivity.this);
/** progress dialog to show user that the backup is processing. */
/** application context. */
protected void onPreExecute() {
this.dialog.setMessage(getResources().getString(
R.string.Loading_String));
this.dialog.show();
}
protected Boolean doInBackground(final String... args) {
try {
// Fetch the RSS Feeds from URL
// do background process
return true;
} catch (Exception e) {
Log.e("tag", "error", e);
return false;
}
}
#Override
protected void onPostExecute(final Boolean success) {
if (dialog.isShowing()) {
dialog.dismiss();
}
if (success) {
// Setting data to list adaptar
setListData();
}
}
}

How to close parent thread on Android

I would like to do step by step upload date to web service.
My code:
private Thread WebServiceThread;
public void onCreate(Bundle savedInstanceState) {
//...
WebServiceThread = new WebService();
WebServiceThread.start();
}
private class WebService extends Thread {
public void run() {
try {
new WebServiceUpload().execute("");
} catch (Exception e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT)
.show();
}
}
}
private class WebServiceUpload extends AsyncTask<String, Void, String> {
protected String doInBackground(String... data) {
// upload part
}
protected void onPostExecute(String result) {
//...
WebServiceThread = new WebService();
WebServiceThread.start();
//<Tab>__what to do here__</Tab>
//...
}
}
Now can run, but cause the device slow.
Please tell me how to close parent thread or restart parent thread way to solve this problem. (or other practice to same target.)
You don't have to chain threads like that. Just create a single AsyncTask extension that uploads the data step by step in doInBackground. If you want to publish progress reports, you can do that by calling publishProgress.
Your method of creating a WebServiceUpload from a worker thread is really bizarre and will most likely not work. AsyncTask is designed to be started from the UI thread. Just call your new WebServiceUpload().execute() from the main thread when you want to start the upload steps.
In your onPostExecute check if thread is running then force it to stop.
protected void onPostExecute(String result) {
//...
**if (WebServiceThread.isAlive())
WebServiceThread.stop();**
WebServiceThread = new WebService();
WebServiceThread.start();
//<Tab>__what to do here__</Tab>
//...
}

Categories

Resources