AsyncTask.cancel only works once - android

For some reason my call to AsyncTask.cancel only works once, i.e. for the first instance of the task, and never again. The first task cancels beautifully and hits the onCancelled method. All the others seem to ignore the cancel() call and end up in onPostExecute.
The task is executed from a service:
public class ZitFtpService extends Service implements ZitFtpServiceInterface
{
//Blah blah
public void connect(String server, int port)
{
if(!isConnecting){
isConnecting = true;
ConnectTask task = new ConnectTask();
task.execute(server, String.valueOf(port));
}
}
//Blah blah blah
As you can see it is a new instance every time. I can't see why the first one would behave differently from the subsequent ones. The AsyncTask is a private inner class:
private class ConnectTask extends AsyncTask<String, String, Boolean> {
#Override
protected Boolean doInBackground(String... params) {
boolean result = false;
try {
publishProgress(
"start", "Connecting to "+ params[0] + ":" + params[1]);
Log.v("ZIT", params[0] + " " + params[1] + " " + params.length);
conn.connect(params[0], Integer.valueOf(params[1]), 1000);
result = true;
} catch (NumberFormatException e) {
Log.e("ZIT", e.getMessage());
} catch (IOException e) {
failMessage = e.getMessage();
e.printStackTrace();
}
return Boolean.valueOf(result);
}
private void cancelConnect() {
try {
conn.disconnect();
} catch (IOException e) {
e.printStackTrace();
} finally {
conn = new ZMobileFTPImpl();
}
if(!(dialog==null)) {
dialog.dismiss();
}
}
#Override
protected void onCancelled() {
Log.v("ZIT", "I was cancelled.");
isConnecting = false;
}
#Override
protected void onProgressUpdate(String... values) {
if(dialog == null) {
dialog = new ProgressDialog(progressActivity);
dialog.setCancelable(true);
dialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
ConnectTask.this.cancel(true);
cancelConnect();
dialog.dismiss();
}
});
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
}
dialog.setMessage(values[1]);
dialog.setCancelable(true);
dialog.show();
}
#Override
protected void onPostExecute(Boolean result) {
dialog.dismiss();
if(!result) {
AlertDialog.Builder builder =
new AlertDialog.Builder(progressActivity);
builder.setMessage(failMessage).setTitle("Error");
failMessage = "";
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
AlertDialog failDialog = builder.create();
failDialog.show();
}
isConnecting = false;
}
}

From Doc's
There are a few threading rules that must be followed for this class to work properly:
The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.
The task instance must be created on the UI thread.
execute(Params...) must be invoked on the UI thread.
Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
So, you can call an AsyncTask multiple times by creating new instance every time like
new ConnectTask().execute(params);

This is intentional as you can only execute an AsyncTask instance once, you can run task.execute multiple times though...
Anyhow, I believe you forgot to add the super.onCancelled in following override:
#Override
public void onCancelled() {
//...
super.onCancelled();
}
Try if that helped, and otherwise you should share the error or log so we can troubleshoot that :)

Related

Android Thread Issues

I'm having some problems running a thread in my android application, It should show a dialog asking the user something and if the user clicks yes, a loading dialog should appear while it's doing something in the background, I created a thread but when I click the yes button, the UI still locks up until the process is done.
Code:
Dialog:
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage("LOGO.bin Was Not Found, Would You Like To Extract It?")
.setTitle("LOGO Not Found!");
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
getAndExtract();
}
});
builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
finish();
System.exit(0);
}
});
AlertDialog dialog = builder.create();
dialog.show();
getAndExtract:
public void getAndExtract()
{
new Thread(new Runnable() {
#Override
public void run() {
try {
showLoad("Grabbing Logo...");
getLogo();
Thread.sleep(2000);
progressDialog.cancel();
showLoad("Extracting Images...");
extractImages();
Thread.sleep(2000);
progressDialog.cancel();
}catch (InterruptedException iE)
{
iE.printStackTrace();
}
}
}).run();
}
showLoad:
progressDialog.setMessage(msg);
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressDialog.show();
basics of extractImages:
Command cmd = new Command(0, "LogoInjector -i " + getFilesDir() + "/LOGO.bin -d -g " + getFilesDir() + "/");
RootTools.getShell(true).add(cmd);
basics of getLogo:
Command cmd = new Command(0, "dd if=/dev/block/mmcblk0p" + partitionIndex + " of=" + getFilesDir() + "/LOGO.bin");
RootTools.getShell(true).add(cmd);
I also tried putting showLoad in runOnUiThread but there was no change... if I remove progressDialog.cancel(); it does show the loading dialog but after the extract is already complete. I press Yes and it just hangs until getLogo() and extractImages() both completed
Can anyone help me find out why this isn't working?
Thanks!
Try using AsyncTask:
final AsyncTask<Void,Void,Void> asyncTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
// do whatever you need to do in background
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute( aVoid);
// do after finished
}
};
asyncTask.execute();
Hope that helps =]

Wait for thread to finish and then move to next position

i am trying to display a Toast on the screen and when Toast fades off then move to the next question. I have tried with Thread but cannot seem to manage.
My code:
next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (getUserSelection()){
position = position + 3;
if (position < questionsArray.size()) {
curName = questionsArray.get(position).getName();
curArray = questionsArray.get(position).getAnswers();
curIscorrect = questionsArray.get(position).getIscorrect();
setupQuestionView(curName, curArray, curIscorrect);
} else {
StringGenerator.showToast(QuestionsActivity.this, "Your score : " + score + "/" + (questionsArray.size() / 3));
}
}else {
StringGenerator.showToast(QuestionsActivity.this, getString(R.string.noanswerselected));
}
}
});
and the getUserSelectionMethod:
private boolean getUserSelection() {
correct = (RadioButton)findViewById(group.getCheckedRadioButtonId());
if (correct == null){
return false;
}else {
correctAnswerText = correct.getText().toString();
if (map.get(correctAnswerText).equals(Constants.CORRECTANSWER)) {
score++;
setCorrectMessage();
return true;
} else {
setWrongMessage();
return true;
}
}
}
private void setCorrectMessage() {
correctToast = new Toast(QuestionsActivity.this);
correctToastView = getLayoutInflater().inflate(R.layout.correct, (ViewGroup) findViewById(R.id.correctRootLayout));
correctText = (TextView)correctToastView.findViewById(R.id.correctTextView);
correctText.setText(getString(R.string.correctAnswer));
correctToast.setDuration(Toast.LENGTH_SHORT);
correctToast.setView(correctToastView);
correctToast.show();
correctThread = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
correctToast.cancel();
}
});
correctThread.start();
}
private void setWrongMessage() {
wrongToast = new Toast(QuestionsActivity.this);
wrongToastView = getLayoutInflater().inflate(R.layout.wrong, (ViewGroup) findViewById(R.id.wrongRootLayout));
wrongText = (TextView)wrongToastView.findViewById(R.id.wrongTextView);
wrongText.setText(getString(R.string.wrongAnswer));
wrongToast.setDuration(Toast.LENGTH_SHORT);
wrongToast.setView(wrongToastView);
wrongToast.show();
wrongThread = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
wrongToast.cancel();
}
});
wrongThread.start();
}
Any suggestion on how to do this?
You can determine the toast visibility:
toast.getView().getWindowToken()
If the result is null, than your toast isn't visible anymore, and than you can run any code you want.
as stated in this answer you can start a thread that waits the duration of the Toast:
Thread thread = new Thread(){
#Override
public void run() {
try {
Thread.sleep(3500); // 3.5seconds!
// Do the stuff you want to be done after the Toast disappeared
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Toast.LENGTH_SHORT and Toast.LENGTH_LONG are only flags so you have to either hard code the duration or keep them in a constant. The durations are 3.5s (long) and 2s (short).
If you want to manipulate some of your views, you cannot do this in another thread than the "main" UI thread. So you have to implement a kind of callback/polling mechanism to get notified when the SleepThread has finished.
Check this answer to read about a couple of ways to do this. Probably the easiest of them to understand and implement is this:
After you started your Thread you can check if it is still alive and running by calling thread.isAlive(). In this way you can do a while loop that runs while the thread is running:
// start your thread
while(thread.isAlive()){}
// continue the work. The other thread has finished.
Please note that this is NOT the most elegant way to do this! Check the other possibilities in the answer I've mentioned above for more elegant solutions (especially the last one with the listeners is very interesting and worth reading!)
That's because the Thread class is purely executed in the background and you need to manipulate the view in the Main thread. To solve your issue just replace the Thread with AsynTask.
AsyncTask<Void,Void,Void> a = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
correctToast.cancel();
}
};
a.execute();
If you look at my code you can see my onPostExecute, this method is called in the Main Thread.
My Error was because i was trying to acess UI Elements through another Thread so modifying the code like this:
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(500);
QuestionsActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
moveToNextQuestion();
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
did the trick. I hope my answer helps someone!!!

Display dialog in async task

I am trying to send email using async method as shown below and everything is working fine..
Now I would like to display a dialog on successfull email.
This is my async code:
public void sending(View v) {
try {
LongOperation l=new LongOperation();
l.execute();
Toast.makeText(this, l.get(), Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Log.e("SendMail", e.getMessage(), e);
}
}
public class LongOperation extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
try{GMailSender sender = new GMailSender("XXX#gmail.com","Pwd");
sender.sendMail("Sub",
"body",
"sender",
"recepient");
}
catch(Exception e){Log.e("error",e.getMessage(),e);return "Email Not Sent";}
return "Email Sent";
}
#Override
protected void onPostExecute(String result)
{
}
#Override
protected void onPreExecute()
{
}
#Override
protected void onProgressUpdate(Void... values)
{
}
In the above code if the mail is not sent I'm getting a toast as "Email Sent" and If not send the email I would get "Email Not Sent"
1)In the place of toasts I would like to display a dialog.
2)I have done it in onPostExecute and it worked fine.
But here comes the problem.Suppose if there is no internet connection and user clicks the button both the toast "Email Not sent" and the dialog is displaying after onPostExecute method.
I would only like to display the dialog.
So how do I modify the above code inorder to remove the toasts and only get the dialog for successfull and unsuccessfull email.
Here is my dialog code:
new AlertDialog.Builder(MainActivity.this)
.setTitle("Info")
.setMessage("Sample message.")
.setPositiveButton("OK",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int which) {
Log.d("AlertDialog","Positive");
}}).show();
Still not completely sure I understand the problem but maybe this is what you want.
public void sending(View v) {
try {
LongOperation l=new LongOperation();
l.execute();
} catch (Exception e) {
Log.e("SendMail", e.getMessage(), e);
}
}
public class LongOperation extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
try{GMailSender sender = new GMailSender("XXX#gmail.com","Pwd");
sender.sendMail("Sub",
"body",
"sender",
"recepient");
}
catch(Exception e){Log.e("error",e.getMessage(),e);return "Email Not Sent";}
return "Email Sent";
}
#Override
protected void onPostExecute(String result)
{
if ("Email Sent".equals(result))
{
new AlertDialog.Builder(MainActivity.this)
.setTitle("Info")
.setMessage("Sample message.")
.setPositiveButton("OK",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int which) {
Log.d("AlertDialog","Positive");
}}).show();
}
#Override
protected void onPreExecute()
{
}
#Override
protected void onProgressUpdate(Void... values)
{
}
I simply removed the Toast since you don't want that at all. Then I placed the Dialog code in onPostExecute() and checked the result passed to it from doInBackground(). I only showed it if the result is "Email Sent". You can change that to pass back a different result from doInBackground() if it isn't sent and show a different message in your Dialog.
Edit
I almost forgot to mention, you almost never want to use .get() on an AsyncTask. It is a blocking call which means everything will halt until your task is finished. You update the UI in any task method besides doInBackground() or you use an interface with a callback.
See this answer if you need an interface

using method inside asyntask in android

i have created one simple login application which takes user name and password from sqlserver..it works fine...
i want during login process one progeress bar should be displayed using asyntask...
but i am unaware to use parameters in asyntask...if some one plzz tell me how to put my method in doInbackground of asyntask and what param should i use....
my code is;.....
public void save(){
initilize();
ResultSet rs = null;
String mylog=id.getText().toString();
String mypass=pass.getText().toString();
try{
Statement statement=connect.createStatement();
rs=statement.executeQuery("LOGIN '"+mylog+"', '"+mypass+"'");
}catch(Exception e){
e.printStackTrace();
}
if(mylog.equals("")||mypass.equals("")){
Toast.makeText(getApplicationContext(), "empty fields", Toast.LENGTH_SHORT).show();
} else
try {
if(rs.next()){
Intent i=new Intent(getApplicationContext(),Act2.class);
startActivity(i);
}
else if(rs.next()==false){
Toast.makeText(getApplicationContext(), "incorrect login", Toast.LENGTH_SHORT).show();
id.setText("");
pass.setText("");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if it is possible that same method save() be kept inside doInbackground() of asyntask...
making a fast refactorization (note that this as it stand it's really bad practice and coding, you MUST refactor this code to be more maintanable and to avoid duplication):
public class MyAsyncTask extends AsyncTask<> {
private Activity activity;
boolean result;
private String myLog;
private String myPass;
private Connection connect;
public MyAsyncTask(Activity activity, Connection connect) {
this.activity = activity;
this.connect = connect;
}
#Override
protected void onPreExecute() {
//show your progress dialog
}
#Override
protected Object doInBackground(Object[] objects) {
ResultSet rs = null;
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
initilize();
mylog=id.getText().toString();
mypass=pass.getText().toString();
}
});
try{
Statement statement=connect.createStatement();
rs=statement.executeQuery("LOGIN '"+mylog+"', '"+mypass+"'");
}catch(Exception e){
e.printStackTrace();
}
if(mylog.equals("")||mypass.equals("")){
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(activity.getApplicationContext(), "empty fields", Toast.LENGTH_SHORT).show();
}
});
} else
try {
if(rs.next()){
result = true;
}
else if(rs.next()==false){
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(activity.getApplicationContext(), "incorrect login", Toast.LENGTH_SHORT).show();
id.setText("");
pass.setText("");
}
});
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Object o) {
//hide your progress dialog
if(result == Boolean.TRUE){
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
Intent i=new Intent(activity.getApplicationContext(),Act2.class);
activity.startActivity(i);
}
});
}
}
}
then in your Activity you do this:
MyAsyncTask a = new MyAsyncTask(this, connect); //im guessing "connect" is your Connection object
a.execute();
As i said i made this fast refactoring for the code to work but best practice and good implementation is not in consideration here.
Maybe, you could use a timer, to check if your
login is ready. As long as it is not, you Show your progress Bar. If its ready, you can close the Bar and start a new activity or anything. timers run can run on u UI thread.
regards :)

ProgressDialog.dismiss() does not close in Async Class android

I have an inner class that downloads some images from the server. The problem is that the ProgressDialog does not dismiss() onPostExecute() method and don't understand why.
I understand that the progress dialog should be shown onPreExecute() method, and the after the code from the doInBackground() finished , in the onPostExecute() method the dialog should be dismiss. Do you have any idea what i am doing wrong here? Thank you.
/**
* Download images from server
*/
public class DownloadAsyncTask extends AsyncTask<Void, Integer, Void> {
private ProgressDialog mDialog;
// execution of result of Long time consuming operation
protected void onPostExecute(Void result) {
// progressDialog.show();
if (mDialog.isShowing()) {
mDialog.dismiss();
}
}
// Things to be done before execution of long running operation.
protected void onPreExecute() {
mDialog = ProgressDialog
.show(ImagesActivity.this, getString(R.string.pleasewait),
getString(R.string.loading));
}
// perform long running operation operation
protected Void doInBackground(Void... params) {
System.out.println("doInBackground loading.." + id);
String tempPath = FileUtils.createTempFile(id);
for (int i = 0; i < imagePaths.size(); i++) {
imagePaths.get(i).trim();
try {
Bitmap imgTemp;
imgTemp = FileUtils.downloadBitmapFromURL(id,
imagePaths.get(i), tempPath);
System.out.println("imgTemp: " + imgTemp);
if (imgTemp != null) {
// save image on sdcard.
// compress it for performance
Bitmap img = Bitmap.createScaledBitmap(imgTemp, 90, 80,
true);
imgTemp.recycle();
FileUtils.saveDataToFile(img, tempPath,
imagePaths.get(i));
} else {
continue;
}
} catch (IOException e) {
e.printStackTrace();
mDialog.dismiss();
}
}
Looper.prepare();
mDialog.dismiss();
return null;
}
/*
* Things to be done while execution of long running operation is in
* progress.
*/
protected void onProgressUpdate(Integer... values) {
if (mDialog.isShowing()) {
mDialog.dismiss();
}
}
}
actually what you are trying to do is to access the UI Thread from another thread and that is not possible , in your case you are using AsyncTask class enables proper and easy use of the UI thread without having to manipulate threads and/or handlers. use onPostExecute(Result) to access the UI Thread.
so this should work
protected void onPostExecute(Void result) {
progressDialog.show();
if (mDialog.isShowing()) {
mDialog.dismiss();
}
}
I've struggled with this same problem for quite a while. Here is how I got it solved, take a look at this part of the documentation:
A dialog is always created and displayed as a part of an Activity. You
should normally create dialogs from within your Activity's
onCreateDialog(int) callback method. When you use this callback, the
Android system automatically manages the state of each dialog and
hooks them to the Activity, effectively making it the "owner" of each
dialog
Note: If you decide to create a dialog outside of the onCreateDialog()
method, it will not be attached to an Activity. You can, however,
attach it to an Activity with setOwnerActivity(Activity).
from: http://developer.android.com/guide/topics/ui/dialogs.html#ShowingADialog
This is an example of what you have to set on your activity:
#Override
protected void onPrepareDialog(int id, Dialog dialog)
{
//This doesn't do anything
if (id == DIALOG_PROGRESS_ID) {
((ProgressDialog)dialog).setIndeterminate(true);
}
super.onPrepareDialog(id, dialog);
}
#Override
protected Dialog onCreateDialog(int id)
{
if (id == DIALOG_PROGRESS_ID) {
ProgressDialog dialog = new ProgressDialog(this);
dialog.setMessage("Loading");
dialog.setCancelable(false);
dialog.setIndeterminate(true);
return dialog;
}
return null;
}
You can then call
myActivity.showDialog(myActivity.DIALOG_PROGRESS_ID), myActivity.dismissDialog(myActivity.DIALOG_PROGRESS_ID) from any where as long as you have a reference to your activity instance.
Use a handler and onPostExecute() send the handler msg to dismiss the progress dialog.
You can get help from this link ProgressDialog dismissal in android
Your code is working fine but can you check that control are reaching in Post onPostExecute() method I have tried as
package com.alarm.activity;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
public class AlarmManagerActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//set up main content view
setContentView(R.layout.main);
new DownloadAsyncTask().execute();
}
/**
* Download images from server
*/
public class DownloadAsyncTask extends AsyncTask<Void, Integer, Void> {
private ProgressDialog mDialog;
// execution of result of Long time consuming operation
#Override
protected void onPostExecute(Void result) {
// progressDialog.show();
if (mDialog.isShowing()) {
mDialog.dismiss();
}
}
// Things to be done before execution of long running operation.
#Override
protected void onPreExecute() {
mDialog = ProgressDialog.show(AlarmManagerActivity.this, "Hello", "Test");
}
// perform long running operation operation
#Override
protected Void doInBackground(Void... params) {
//System.out.println("doInBackground loading.." + id);
/* String tempPath = FileUtils.createTempFile(id);
for (int i = 0; i < imagePaths.size(); i++) {
imagePaths.get(i).trim();
try {
Bitmap imgTemp;
imgTemp = FileUtils.downloadBitmapFromURL(id, imagePaths.get(i), tempPath);
System.out.println("imgTemp: " + imgTemp);
if (imgTemp != null) {
// save image on sdcard.
// compress it for performance
Bitmap img = Bitmap.createScaledBitmap(imgTemp, 90, 80, true);
imgTemp.recycle();
FileUtils.saveDataToFile(img, tempPath, imagePaths.get(i));
}
else {
continue;
}
}
catch (IOException e) {
e.printStackTrace();
mDialog.dismiss();
}
}
Looper.prepare();
mDialog.dismiss();*/
try {
Thread.sleep(5000);
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/*
* Things to be done while execution of long running operation is in
* progress.
*/
#Override
protected void onProgressUpdate(Integer... values) {
if (mDialog.isShowing()) {
mDialog.dismiss();
}
}
}
}
I think problem in doInbackground() method. I have simply run thread for sleep 5 sec and after control reaches in post() method and dissmiss progress dialog.

Categories

Resources