Hi friends,
After some months of experience in Android, I got some issue with canceling ProgressDialog.
Default behavior is, you can cancel Dialog by pressing back “key”.
I got issue in this that, My task was not canceled.
I realized that AsyncTask is separate thread, you need to call .cancel() method.
I also realized that my custom image gallery was eating lots of internet call, because of AsyncTask was not canceled.
Cancelling an AsyncTask is not easy as it looks. You need to take care of it’s state, make use of onCancelled() call etc, notifying correct message to user etc.
All this thing is explained by taking an example of login activity.
Please read all the comments on following code:
package com.isummation.exampleapp;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.json.JSONObject;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class UserLogin extends Activity {
private EditText etUsername;
private EditText etPassword;
private ProgressDialog progressDialog;
private static final int PROGRESSDIALOG_ID = 0;
private static final int SERVER_ERROR = 1;
private static final int NETWORK_ERROR = 2;
private static final int CANCELLED = 3;
private static final int SUCCESS = 4;
private String ServerResponse;
private LoginTask loginTask;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
etUsername = (EditText) findViewById(R.id.txt_username);
etPassword = (EditText) findViewById(R.id.txt_password);
Button login_button = (Button) this.findViewById(R.id.login_button);
login_button.setOnClickListener(new OnClickListener() {
public void onClick(View viewParam) {
if (etUsername.getText().toString().length() == 0
|| etPassword.getText().toString().length() == 0) {
Toast.makeText(getApplicationContext(),
"Please enter username and password",
Toast.LENGTH_SHORT).show();
} else {
//Show dialog by passing id
showDialog(PROGRESSDIALOG_ID);
}
}
});
}
protected Dialog onCreateDialog(int id) {
switch(id) {
case PROGRESSDIALOG_ID:
removeDialog(PROGRESSDIALOG_ID);
//Please note that forth parameter is true for cancelable Dialog
//Also register cancel event listener
//if the litener is registered then forth parameter has no effect
progressDialog = ProgressDialog.show(UserLogin.this, "Authenticating",
"Please wait...", true, true, new OnCancelListener(){
public void onCancel(DialogInterface dialog) {
//Check the status, status can be RUNNING, FINISHED and PENDING
//It can be only cancelled if it is not in FINISHED state
if (loginTask != null && loginTask.getStatus() != AsyncTask.Status.FINISHED)
loginTask.cancel(true);
}
});
break;
default:
progressDialog = null;
}
return progressDialog;
}
@Override
protected void onPrepareDialog(int id, Dialog dialog) {
switch (id) {
case PROGRESSDIALOG_ID:
//check if any previous task is running, if so then cancel it
//it can be cancelled if it is not in FINISHED state
if (loginTask != null && loginTask.getStatus() != AsyncTask.Status.FINISHED)
loginTask.cancel(true);
loginTask = new LoginTask(); //every time create new object, as AsynTask will only be executed one time.
loginTask.execute();
}
}
class LoginTask extends AsyncTask<Void, Integer, Void> {
@Override
protected Void doInBackground(Void... unused) {
try {
ServerResponse = null; //don't forget to make it null, as task can be called again
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpGet = new HttpGet(
getString(R.string.WebServiceURL)
+ "/cfc/iphonewebservice.cfc?returnformat=json&method=validateUserLogin&username="
+ URLEncoder.encode(etUsername.getText()
.toString(), "UTF-8")
+ "&password="
+ URLEncoder.encode(etPassword.getText()
.toString(), "UTF-8"));
httpClient.getParams().setParameter(
CoreProtocolPNames.USER_AGENT,"Some user agent string");
//call it just before you make server call
//calling after this statement and canceling task will no meaning if you do some update database kind of operation
//so be wise to choose correct place to put this condition
//you can also put this condition in for loop, if you are doing iterative task
//now this very important
//if you do not put this condition and not maintaining execution, then there is no meaning of calling .cancel() method
//you should only check this condition in doInBackground() method, otherwise there is no logical meaning
if (isCancelled())
{
publishProgress(CANCELLED); //Notify your activity that you had canceled the task
return (null); // don't forget to terminate this method
}
HttpResponse response = httpClient.execute(httpGet,
localContext);
BufferedReader reader = new BufferedReader(
new InputStreamReader(
response.getEntity().getContent(), "UTF-8"));
ServerResponse = reader.readLine();
publishProgress(SUCCESS); //if everything is Okay then publish this message, you may also use onPostExecute() method
} catch (UnknownHostException e) {
removeDialog(PROGRESSDIALOG_ID);
e.printStackTrace();
publishProgress(NETWORK_ERROR);
} catch (Exception e) {
removeDialog(PROGRESSDIALOG_ID);
e.printStackTrace();
publishProgress(SERVER_ERROR);
}
return (null);
}
@Override
protected void onProgressUpdate(Integer... errorCode) {
switch (errorCode[0]) {
case CANCELLED:
removeDialog(PROGRESSDIALOG_ID);
Toast.makeText(getApplicationContext(), "Cancelled by user",
Toast.LENGTH_LONG).show();
break;
case NETWORK_ERROR:
removeDialog(PROGRESSDIALOG_ID);
Toast.makeText(getApplicationContext(), "Network connection error",
Toast.LENGTH_LONG).show();
break;
case SERVER_ERROR:
removeDialog(PROGRESSDIALOG_ID);
Toast.makeText(getApplicationContext(), "Server error",
Toast.LENGTH_LONG).show();
break;
case SUCCESS:
removeDialog(PROGRESSDIALOG_ID);
try {
if (ServerResponse != null) {
JSONObject JResponse = new JSONObject(ServerResponse);
String sMessage = JResponse.getString("MESSAGE");
int success = JResponse.getInt("SUCCESS");
if (success == 1) {
//proceed further
//you may start new activity from here
//after that you may want to finish this activity
UserLogin.this.finish();
//Remember when you finish an activity, it doesn't mean that you also finish thread or AsynTask started within that activity
//So you must implement onDestroy() method and terminate those threads.
} else {
//just showing invalid username password from server response
Toast.makeText(getApplicationContext(), sMessage,
Toast.LENGTH_SHORT).show();
}
}
} catch (Exception e){
Toast.makeText(getApplicationContext(), "Server error",
Toast.LENGTH_LONG).show();
e.printStackTrace();
}
break;
}
}
@Override
protected void onPostExecute(Void unused) {
}
}
@Override
protected void onDestroy(){
//you may call the cancel() method but if it is not handled in doInBackground() method
if (loginTask != null && loginTask.getStatus() != AsyncTask.Status.FINISHED)
loginTask.cancel(true);
super.onDestroy();
}
}
Please feel free to ask/comment.
u can check network connection by
private boolean checkInternetConnection() {
ConnectivityManager conMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (conMgr.getActiveNetworkInfo() != null
&& conMgr.getActiveNetworkInfo().isAvailable()
&& conMgr.getActiveNetworkInfo().isConnected()) {
tryLogin();
return true;
} else {
Toast.makeText(Login.this, “Internet Connection Not Present”, Toast.LENGTH_LONG).show();
Log.v(TAG, “Internet Connection Not Present”);
return false;
}
}
This work well on device. But do some other testing. Try to disable network adapter of pc, then check it in emulator. This method will not work as it is still connected to 10.0.2.2 i.e. pc’s localhost!
see my comment here
hi, I m not getting why u want to disable LAN connection,any way as per my knowledge, check ur logcat ,if you are getting exception of “java.net.UnknownHostException: http://www.urweb.com“, and you can handle this by try{ urLoginProcess….. }catch (IOException e) {e.printtrace();}
and one more tips if u use my “checkInternetConnection()” in thread then it be faster as like
showDialog(0);
t = new Thread() {
@Override
public void run() {
Looper.prepare();
checkInternetConnection();
removeDialog(0);
}
};
t.start();
and one more thing ur link “here” is not working plz check it, i ll try if i can give you better solution
Check the link now…
OK, Its working, but sry I can’t help you more on regarding current topic, bcz as per my above suggestion i ve tried with above my code and it working perfect(not FC) even if LAN is disable… any way all D best
how to down;load source code? i didnot find xml
Pingback: Cancel asynctask download on backbutton press : Android Community - For Application Development
Pingback: Json can not be convert to int : Android Community - For Application Development
Pingback: When I developing an Android application ,how can I cancel a running AsyncTask? : Android Community - For Application Development
Hello and thanks for the post.
If you can help me with this
http://stackoverflow.com/questions/16582484/progress-bar-remains-empty-using-asynctask-edit-dialog-never-stops-loading
I ‘ll appreciate it.
Exept from the problem I have with dialog ,I can’t terminate the task also.
Thanks!