I have got a little problem while cancellling a AsyncTask, which is in a Fragment which processes some data. If a internet session is expired the AsyncTask should be cancelled and a dialog be shown to inform the user.
However if I cancel the AsyncTask the AlertDialog is not shown, I also noticed that onCancelled()is not being called but the onPostExecute()is still executed.
If someone pls could assist?
Edit: If I use the while method, the AlertDialog is shown but how do I properly cancel the AsyncTask as the code as of tryin doInBackground() still is being executed?
while (!isCancelled()) {
// Do stuff
}
Edit 2: Solved! It seemed the AsyncTask call was not correctly instinciated, below code works and now also onCancelled method is called and onPostExecute declined as it should be.
Cudos for Anudeep Bulla to point me in the right direction.
public class Tb3_Abonnement extends Fragment {
private AsyncTask<Void, Void, Void> task;
...
#Override // If Fragment is visible to user, start asynctask
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
// execute AsyncTask
startFetch();
}
}
// Wrap (asynctask call) in a own method
public void startFetch() {
task = new FetchFacturen();
task.execute();
}
private class FetchFacturen extends AsyncTask<Void, Void, Void> {
// Create new AlertDialog
AlertDialog taskDialog = new AlertDialog.Builder(getActivity())
.setCancelable(false)
.setTitle("Mededeling Facturen:")
.setMessage("Uw sessie is verlopen! U dient zich weer opnieuw in te loggen. ")
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Start LoginActivity
Intent mainIntent = new Intent(getActivity(), LoginActivity.class);
getActivity().startActivity(mainIntent);
getActivity().finish();
}
})
.setIcon(android.R.drawable.ic_dialog_info)
.create();
#Override
protected void onPreExecute() {
if (Helper.minutes <= 0) {
task.cancel(true);
} else {
showProgress(true);
}
}
#Override
protected Void doInBackground(Void... result) {
CharSequence cs1 = "€";
if (isCancelled()) {
util.disconnect();
return null;
}
try {
// The heavy stuff
}
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onCancelled() { // Correctly called
if(isCancelled()){
Log.e("CANCELLED", "TAB3");
this.taskDialog.show();
}
super.onCancelled();
}
#Override
protected void onPostExecute(Void result) { // Skipped
if(isCancelled()){
this.taskDialog.show();
} else {
setupInvoiceAdapter();
showProgress(false);
}
}
}
Here are the important code parts:
public class Tb3_Abonnement extends Fragment {
private FetchAbbo task;
...
#Override // If Fragment is visible to user, start asynctask
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
// execute AsyncTask
task = new FetchAbbo();
task.execute();
}
public class FetchAbbo extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
if (Helper.minutes <= 0) {
task.cancel(true); // Cancel AsyncTask
new AlertDialog.Builder(getActivity()) // Create new AlertDialog
.setCancelable(false)
.setTitle("Mededeling:")
.setMessage("Uw sessie is verlopen! U dient zich weer opnieuw in te loggen. ")
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Start LoginActivity
}
})
.setIcon(android.R.drawable.ic_dialog_info)
.show();
}
}
#Override
protected Void doInBackground(Void... result) {
if (!this.isCancelled()) { // Executed
Log.e("FetchAbbo: ", "Cancelled!"); // Printed
util.disconnect();
return null;
}
try {
Log.e("FetchAbbo: ", "still running!");
// Do the heavy stuff
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onCancelled() {
Log.e("CANCELLED", "TAB3"); // Not printed, onCancelled() not called?
super.onCancelled();
}
#Override
protected void onPostExecute(Void result) {
setupTxtViews();
mScrollView.setVisibility(View.VISIBLE); // Set ScrollView visible
}
}
I may be wrong, but I don't seem to understand the logic of showing the dialog in onPreExecute everytime. Why not try this ?
public class FetchAbbo extends AsyncTask<Void, Void, Void> {
AlertDialog taskDialog = new AlertDialog.Builder(getActivity()) // Create new AlertDialog
.setCancelable(false)
.setTitle("Mededeling:")
.setMessage("Uw sessie is verlopen! U dient zich weer opnieuw in te loggen. ")
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Start LoginActivity
}
})
.setIcon(android.R.drawable.ic_dialog_info)
.create();
#Override
protected void onPreExecute() {
if (Helper.minutes <= 0) {
task.cancel(true); // Cancel AsyncTask
}
}
#Override
protected Void doInBackground(Void... result) {
if (!this.isCancelled()) { // Executed
Log.e("FetchAbbo: ", "Cancelled!"); // Printed
util.disconnect();
return null;
}
try {
Log.e("FetchAbbo: ", "still running!");
// Do the heavy stuff
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onCancelled() {
Log.e("CANCELLED", "TAB3"); // Not printed, onCancelled() not called?
if(this.isCancelled()){
this.taskDialog.show();
}
super.onCancelled();
}
#Override
protected void onPostExecute(Void result) {
if(this.isCancelled()){
this.taskDialog.show();
} else {
setupTxtViews();
mScrollView.setVisibility(View.VISIBLE); // Set ScrollView visible
}
}
}
Related
I am trying to stop an AsyncTask in Android. In doInBackground it runs through an IP - Address list and tries to ping all of them.
Furthermore, when executing the AsyncTask a ProgressDialog opens which you can cancel. Calling this cancel - text calls the onCancelled method in AsyncTask. So, this method is being called, but it seems as if it is never stopped because when I hit the button Find again, I always get the following error message:
java.lang.IllegalStateException: Cannot execute task: the task has already been executed (a task can be executed only once)
Here is my code:
private Settings.HostWorker hostWorker;
private void initComponents() {
hostWorker = new Settings.HostWorker();
progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
if(!hostWorker.isCancelled()) {
hostWorker.cancel(true);
}
}
});
}
findServerButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
if(findServerButton.isClickable()) {
progressDialog.show();
hostWorker.execute();
findServerButton.setClickable(false);
}
}
});
private class HostWorker extends AsyncTask<Integer, String, Void> {
#Override
protected Void doInBackground(Integer... params) {
try {
for (int i = 0; i <= 255; i++) {
String ip = createHostsList(i);
if (ip != null) {
publishProgress(ip);
}
if(isCancelled())
{
break;
}
}
} catch (Exception e) {
MyAlertDialog myAlertDialog = new MyAlertDialog(getBaseContext(), "Error in Settings - doInBackground: " + e.getMessage());
myAlertDialog.showAlertDialog();
}
return null;
}
protected void onProgressUpdate(String... values) {
hostsOnline.add(values[0]);
settingsCustomArrayAdapter.notifyDataSetChanged();
}
protected void onCancelled(){
findServerButton.setClickable(true);
}
#Override
protected void onPostExecute(Void aVoid)
{
super.onPostExecute(aVoid);
}
}
The error
Cannot execute task: the task has already been executed (a task can be executed only once)
suggests that you need to create a new HostWorker instance each time you want to run the task. You could achieve this by removing the line
hostWorker = new Settings.HostWorker();
from initComponents and instead adding it into your findServerButton OnClickListener like so:
findServerButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
if(findServerButton.isClickable()) {
progressDialog.show();
hostworker = new Settings.HostWorker(); // Line added here.
hostWorker.execute();
findServerButton.setClickable(false);
}
}
});
I have an activity with a button that starts an AsyncTask:
public void search(View view) {
if (searchTask != null) {
return;
}
searchTask = new SearchTask(this);
searchTask.execute((Void)null);
}
And this is the task:
public class SearchTask extends AsyncTask<Void, Void, Boolean> {
private final Activity activity;
private final ProgressDialog dialog;
public SearchTask(Activity activity) {
this.activity = activity;
this.dialog = new ProgressDialog(activity);
}
#Override
protected Boolean doInBackground(Void... params) {
try {
wait(3000);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
#Override
protected void onPreExecute() {
dialog.show();
}
#Override
protected void onPostExecute(final Boolean success) {
if (dialog.isShowing())
dialog.dismiss();
}
}
I'm not calling get() so I shouldn't be blocking the UI thread. The problem is that the progress dialog is not being shown.
Is this not the correct way to show a dialog within an AsynTask?
wait() causes IllegelMonitorException. to apply a delay in the task Thread.sleep() should be used.
try after removing return; from below code-
public void search(View view) {
if (searchTask != null) {
return;
}
searchTask = new SearchTask(this);
searchTask.execute((Void)null);
}
I currently trying to show a progress dialog on OnclickListener of a Dialogbox since my items are taking too long to fetch from Server.
I use Async task as suggested here (Android progress dialog) and this post (android problem with progress dialog) to show progress dialog The progress dialog is shown , however the code returns exception when it goes to do background that " Looper is not set". And when I set looper nothing happens.
I am not sure at this stage what is it that I am doing wrong.
public void firstMethod()
{
final CustomObj obj = getCustomObj();//not imp
Messages.getInstance().showAlert(MainActivity.this, "message", false, new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which)
{
dialog.dismiss();
}
}, new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which)
{
gotoAnotherPge(obj);
}
});
}
public void gotoAnotherPge(final CustomObject obj)
{
final ProgressDialog pd = new ProgressDialog(MainActivity.this);
new AsyncTask<Object, Object, Boolean>()
{
protected void onPreExecute()
{
pd.setMessage(String.format(Statics.getText(MainActivity.this, R.raw.dictionary, "subscriptions_loading_unsubscribing")));
pd.show();
}
protected Boolean doInBackground(Object... params)
{
try{
Looper.prepare();
final LocalPopulator lp = new LocalPopulator(MainActivity.this, 0)
{
#Override
public void populate()
{
List<Serializable> items = Arrays.asList(getItemHere(obj));
List<Serializable> listItems = new ArrayList<Serializable>();
listItems.addAll(items);
Serializable[] sItems = listItems.toArray(new Serializable[menuItems.size()]);
result = sItems;
}
};
showNextPage(true, 1, 0, lp);
Looper.loop();
}catch (Exception e){
Log.e("tag", e.getMessage());
/*
* The task failed
*/
return false;
}
return true;
}
protected void onPostExecute(Boolean result)
{
pd.dismiss();
}
};
MainActivity.this.runOnUiThread (new Runnable()
{
#Override
public void run()
{
// dismiss the progressdialog
pd.dismiss();
}
});
}
I have a thread that run several operations once and I would like to stop it when the user cancels the ProgressDialog.
public void run() {
//operation 1
//operation 2
//operation 3
//operation 4
}
This thread runs only once, so I can't implement a loop to check if he thread should still be running.
Here is my ProgressDialog :
//Wait dialog
m_dlgWaiting = ProgressDialog.show(m_ctxContext,
m_ctxContext.getText(R.string.app_name),
m_ctxContext.getText(R.string.msg_dlg_analyse_pic),
true, //indeterminate
true,
new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
m_bRunning = false;
}
});
As I don't know how to stop the thread, would it be correct to sequence the thread's operations through a loop to see if it should still be running, or is there a better way ?
public void run() {
int op = 0;
while(m_bRunning) {
switch(op) {
case 0 :
//operation 1
break;
case 1 :
//operation 2
break;
case 2 :
//operation 3
break;
case 3 :
//operation 4
break;
}
op++;
}
}
Even with this solution, if there are too much operations in the thread, it could be hard to sequence the operations. Is there a better way to achieve this ?
Use callbacks or AsyncTask
http://developer.android.com/reference/android/os/AsyncTask.html
final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
private ProgressDialog dialog;
#Override
protected void onPreExecute()
{
this.dialog = new ProgressDialog(context);
this.dialog.setMessage("Loading...");
this.dialog.setCancelable(true);
this.dialog.setOnCancelListener(new DialogInterface.OnCancelListener()
{
#Override
public void onCancel(DialogInterface dialog)
{
// cancel AsyncTask
cancel(false);
}
});
this.dialog.show();
}
#Override
protected Void doInBackground(Void... params)
{
// do your stuff
return null;
}
#Override
protected void onPostExecute(Void result)
{
//called on ui thread
if (this.dialog != null) {
this.dialog.dismiss();
}
}
#Override
protected void onCancelled()
{
//called on ui thread
if (this.dialog != null) {
this.dialog.dismiss();
}
}
};
task.execute();
You can use Asynctask like below
FetchRSSFeeds fetchRss = new FetchRSSFeeds()
fetchRss.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 {
/**
* Write your RUN method code here
*/
if (isCancelled()) {
if (dialog.isShowing()) {
dialog.dismiss();
}
}
return true;
} catch (Exception e) {
Log.e("tag", "error", e);
return false;
}
}
#Override
protected void onPostExecute(final Boolean success) {
}
}
And when you want to cancel your background process do below
if (fetchRss.getStatus() == AsyncTask.Status.RUNNING) {
fetchRss.cancel(true);
}
I am developing an application in android, where i need to display a splash screen and at the same time there will be server communication. The problem here is when i launch the app, first application is communicating with the server and then it is displaying the splash screen. I want to both server communication and splash screen at the same time.
The following is my code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash_screen);
try {
Thread thread = new Thread(this);
thread.start();
thread.join();
//Attractions
CommonMethods.getSystemOutput("Response Json Array String Attractions:::"+jArrayMobileAttractions);
attractionsDate = JsonParsing.getLatestDate(jArrayMobileAttractions);
attractionsDate = getDate(attractionsDate);
CommonMethods.getSystemOutput("Attractions Date:::::"+attractionsDate);
//Categories
CommonMethods.getSystemOutput("Response Json Array String Categories:::"+jArrayCategories);
categoryDate = JsonParsing.getLatestDate(jArrayCategories);
categoryDate = getDate(categoryDate);
CommonMethods.getSystemOutput("Category date:::"+categoryDate);
//Contacts
CommonMethods.getSystemOutput("Response Json Array String Contacts:::"+jArrayContacts);
contactsDate = JsonParsing.getLatestDate(jArrayContacts);
contactsDate = getDate(contactsDate);
CommonMethods.getSystemOutput("Contacts Date:::"+contactsDate);
} catch (Exception e) {
CommonMethods.getSystemOutput("Exception in Splash screen thread:::"+e);
}
}
public void run() {
// if (attractionsDate == null) {
jArrayMobileAttractions = RequestHandler.getJSONfromURL(Constants.MOBILE_ATTRACTIONS_URL);
jArrayCategories = RequestHandler.getJSONfromURL(Constants.CATEGORY_URL);
jArrayContacts = RequestHandler.getJSONfromURL(Constants.CONTACTS_URL);
// } else {
// jArrayMobileAttractions = RequestHandler.getJSONfromURL(Constants.MOBILE_ATTRACTIONS_URL+"?lastupdateddate="+attractionsDate);
// }
}
You can use the AsynchTask Manager in which it has a method
private class DownloadWebPageTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
// Do Server Interaction Here
return response;
}
#Override
protected void onPreExecute(String result) {
//Show your Splash Screen
}
#Override
protected void onPostExecute(String result) {
//Gone the Splash Screen view
}
}
For this purpose it will be better start from "SplashActivity" - in onCreate() start new Thread for communication with server, and when all communication finished - call startActivityForResult(mainActivityIntent). For correct behavior back button finish splash activity on finish main activity. Approximate code:
public class SplashActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setup view for activity
new Thread(new Runnable() {
public void run() {
// do here some long operation
startActivityForResult(new Intent(SplashActivity.this, MainActivity.class), 0);
}
}).start();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
finish();
}
}
I had the same thing to do and I did it this way and it works just fine. I had to show the splashscreen and download some file from the server, unzip it, move files insto proper directories and then start the apps main screen. Here is the code, I used AsyncTask.
So, you have three AsyncTask classes, one for each task and in the onPostExecute() I call the next AsyncTask. I can't say if this is the best way but it works for me.
I removed unneccessary code but for clarity I left a call to a dialog where I ask a user ih he wants to proceed with downloading as it may take a while. Also I check if FIRST_RUN is true just so I know if I should download the package since for my app I need to do it only the first time, so if it is true I do the spashscreen activities and if it is false I proceed to MAINAPP activity.
Hope it helps.
public class SplashScreen extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.splashscreen);
SharedPreferences settings = getSharedPreferences(PREFS_NAME,0);
boolean firstRun = settings.getBoolean("FIRST_RUN", true);
if (firstRun) {
showDialog(INITIAL_DLG);
} else {
startActivity(new Intent(appContext, MAINAPP.class));
}
}
/***
* First entry after YES on Dialog!
*/
protected void initialize() {
messageTV.setVisibility(TextView.VISIBLE);
progressBar.setVisibility(ProgressBar.VISIBLE);
downloadThread = new DownloadFiles();
downloadThread.execute();
}
protected void rollback() {
}
#Override
protected Dialog onCreateDialog(int id) {
AlertDialog.Builder builder;
switch (id) {
case INITIAL_DLG:
builder = new AlertDialog.Builder(this);
builder.setMessage(R.string.app_setup)
.setCancelable(false)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
initialize();
}
})
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
alertDlg = builder.create();
return alertDlg;
default:
return null;
}
}
protected class DownloadFiles extends AsyncTask<String, Integer, Boolean> {
#Override
protected Boolean doInBackground(String... params) {
try {
//file download
} catch (Exception e) {
result = false;
}
return true;
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
progressBar.setProgress(values[0]);
}
#Override
protected void onPostExecute(Boolean result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
unzipThread = new DecompressZipFile();
unzipThread.execute();
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
messageTV.setText("Step 1/4:Downloading data...");
progressBar.setProgress(0);
progressBar.setMax(100);
super.onPreExecute();
}
}
protected class DecompressZipFile extends AsyncTask<String, Integer, Boolean> {
#Override
protected Boolean doInBackground(String... params) {
try {
//unzip files
return true;
} catch(Exception e) {
return false;
}
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
if (values[0]<0) progressBar.setMax(values[0]*-1);
else progressBar.setProgress(values[0]);
}
#Override
protected void onPostExecute(Boolean result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
moveDBThread = new MoveDBFile();
moveDBThread.execute();
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
messageTV.setText("Step 2/4:Decompressing data...");
progressBar.setProgress(0);
progressBar.setMax(100);
super.onPreExecute();
}
}
protected class MoveDBFile extends AsyncTask<String, Integer, Boolean> {
#Override
protected Boolean doInBackground(String... params) {
try {
//moving files
return true;
} catch (Exception e) {
globalE = e;
finish();
return false;
}
}
#Override
protected void onPreExecute() {
messageTV.setText("Step 3/4:Shufflin'...");
progressBar.setProgress(0);
progressBar.setMax(100);
super.onPreExecute();
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
progressBar.setProgress(values[0]);
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if (result) {
getSharedPreferences(PREFS_NAME,0).edit().putBoolean("FIRST_RUN", false).commit();
startActivity(new Intent(appContext, MAINAPP.class));
} else {
rollback();
}
}
}
}