AsyncTask in Android starts but does not process - android

I know that there are many similar AsyncTask questions already, but in my case something is very unusual or am I missing something !?
As the AsyncTask is not allowed to run more than once. I call it with new B().execute(); so it should create a separated instance on each run !? Right?
The problem is after the B class is created and executed once, it wont work the second time the user calls the startBClass() method (just opens the dialog, but the actual work is not happening).
I just Debugged the code and realize that after the Dialog is closed, the Thread is still running in the background. What is the proper way to stop the background thread when the Dialog is closing? - And since I'm closing the first Dialog inside B class and create another instance of the B class, why is the second one not working? Can't multiple AsyncTasks run in parallel !?
I simplified the classes for easier understanding what I'm trying:
public class A {
/* Is called when user clicks a button */
private void startBClass() {
new B().execute();
}
/* Opens a Dialog with a countdown TextView (works first call only) */
private class B extends AsyncTask<Void, Integer, Void> {
private int secondsPassed = 0;
private double totalToPay = 0;
private Dialog dialog;
private TextView tvCost;
private Button dialogBtn;
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = new Dialog(ConfigurationActivity.this);
dialog.setCancelable(true);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.dialog);
dialog.setCanceledOnTouchOutside(false);
dialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
onPostExecute(null);
}
});
tvCost = (TextView) dialog.findViewById(R.id.textCounter);
dialogBtn = (Button) dialog.findViewById(R.id.button1);
dialogBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
dialog.cancel();
}
});
dialog.show();
}
#Override
protected Void doInBackground(Void... arg0) {
while(true){
publishProgress(secondsPassed++);
SystemClock.sleep(1000);
}
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
totalToPay = 12.00;
tvCost.setText(totalToPay + " USD");
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
final AlertDialog alert = new AlertDialog.Builder(ConfigurationActivity.this).create();
alert.setTitle("Information");
alert.setMessage("You should pay about " + totalToPay + " USD.");
alert.setButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface alertDialog, int which) {
alertDialog.dismiss();
}
});
alert.show();
}
}
}

dialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
onPostExecute(null);
}
});
This is no good. Per the docs:
Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.
To end it, I'd change both the code above, and the while loop in doInBackground().
protected Void doInBackground(Void... arg0) {
while(running){
publishProgress(secondsPassed++);
SystemClock.sleep(1000);
}
}
running is a boolean you set to true in onPreExecute(). Set it to false when you want to end it. Then your loop will exit and onPostExecute() will be called correctly.
Side note: Where is secondsPassed ever used?

Related

Unable to cancel Async task on button click

I am trying to cancel/end an async task on the button click of a pop-up box. However, when I click on the button the onCancelled() method is not being called. Could someone please help me with this? Below is my code:
public AuthenticationAsync(Context context, final String rid) {
this.rid = rid;
alertDialog = new AlertDialog.Builder(context).create();
alertDialog.setTitle("Information");
alertDialog.setMessage("RaspberryPi Validated");
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
cancel(true); //Cancelling async task on button click
dialog.dismiss();
}
});
}
#Override
protected Object doInBackground(Object[] params) {
String metricData = String.valueOf(kuraPayload.getMetric("data"));
if (metricData.isEmpty())
subResponse = false;
}
#Override
protected void onCancelled() {
Log.d("Async","cancelled"); //not being called
}
#Override
protected void onPostExecute(Object o) {
if (subResponse) {
asyncHttpClient = new AsyncHttpClient();
asyncHttpClient.get(WSConstants.ADD_RPI_WS + MQTTFactory.getRaspberryPiById(), new AsyncHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
Toast.makeText(ActivityContexts.getMainActivityContext(), "RaspberryPi Validated", Toast.LENGTH_LONG).show();
alertDialog.show();
}
}
}
}
It looks like the it's never getting into onCancelled() because you are actually calling alertDialog.show() in onPostExecute(). Since doInBackground() has already completed, there is nothing to cancel.
The cancel() method is meant to be called during the execution of the doInBackground() method, which is the only method that runs on a background Thread.
Note that even if cancel() is called during execution of doInBackground(), the execution of the method won't be stopped immediately. You should do periodic checks to isCancelled() and if it returns true, then exit out of the method.
After doInBackground() has completed, if cancel() has been called, then onCancelled() will be called instead of onPostExecute().
Here is a very simple test based on your code:
public class AuthenticationAsync extends AsyncTask {
AlertDialog alertDialog;
String rid;
public AuthenticationAsync(Context context, final String rid) {
this.rid = rid;
alertDialog = new AlertDialog.Builder(context).create();
alertDialog.setTitle("Information");
alertDialog.setMessage("RaspberryPi Validated");
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
cancel(true); //Cancelling async task on button click
dialog.dismiss();
}
});
}
#Override
protected void onPreExecute(){
//for testing, showing the dialog before the background Thread starts
alertDialog.show();
}
#Override
protected Object doInBackground(Object[] params) {
//cycle forever until the user clicks OK
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//Check if user clicked OK in the dialog
if (isCancelled()){
//Exit the method if the user dismissed the dialog
return null;
}
}
}
#Override
protected void onCancelled() {
Log.d("Async", "cancelled"); //this is called now
Toast.makeText(MainActivity.this, "cancelled", Toast.LENGTH_LONG).show();
}
#Override
protected void onPostExecute(Object o) {
Toast.makeText(MainActivity.this, "postExecute", Toast.LENGTH_LONG).show();
}
}
Result:
Dialog is shown during execution of doInBackground():
After clicking OK, onCancelled() is called:
#yanchenko answered something similar there -> Ideal way to cancel an executing AsyncTask
You can use one ProgressDialog and set this dialog as Cancelable and set the CancelListener.

Android: Progress Dialog with AsyncTask

Since the game requires TTS, and need quite a long time to load, I would like to implement Progress Dialog (PD), as either in the following ways:
Implement AsyncTask in Game Index Page:
This will show the PD, but the PD is freezed, i.e. the looping circle inside the PD is not looping.
buttonC.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
new initialize_game().execute();
}
});
private class initialize_game extends AsyncTask<String,Integer,String>
{
#Override
protected void onPreExecute()
{
dialog= new ProgressDialog(Index_game.this);
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.setMessage("Loading!\nPlease wait...");
dialog.show();
}
#Override
protected String doInBackground(String... params)
{
buttonC.setBackgroundColor(getResources().getColor(R.color.tran_black));
Intent intent = new Intent(Index_game.this, Game_star_intro.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
startActivityForResult(intent, 0);
overridePendingTransition(0, 0); // 0 for no animation
Index_game.this.finish();
return "Done!";
}
protected void onPostExecute(String result)
{
super.onPostExecute(result);
Log.i("result","" +result);
if(result!=null)
{
dialog.dismiss();
}
}
}
AsyncTask for TTS:
Once clicked from the Game Index Page, no PD is shown until the Game is loaded fully, and at that time then the PD pops up and off for a millisecond, i.e. even worse than that above.
private class MainFrameTask extends AsyncTask<String,Integer,String> implements OnInitListener, OnUtteranceCompletedListener
{
private Index_game_card_intro mainFrame = null;
public MainFrameTask(Index_game_card_intro mainFrame)
{
this.mainFrame = mainFrame;
}
#Override
protected void onCancelled()
{
stopProgressDialog();
super.onCancelled();
}
#Override
protected void onPreExecute()
{
startProgressDialog();
}
#Override
protected String doInBackground(String... params)
{
// setup TTS part 1.1
mTts = new TextToSpeech(Index_game_card_intro.this, this); // TextToSpeech.OnInitListener
return "Done!";
}
protected void onPostExecute(String result)
{
stopProgressDialog();
}
// setup TTS part 2
#Override
public void onUtteranceCompleted(String utteranceId)
{
Log.v(TAG, "Get completed message for the utteranceId " + utteranceId);
lastUtterance = Integer.parseInt(utteranceId);
}
// setup TTS part 3
#Override
public void onInit(int status)
{
if(status == TextToSpeech.SUCCESS)
{
int result = mTts.setLanguage(Locale.US); // <====== set speech location
mTts.setSpeechRate((float) 0.8);
mTts.setPitch(1.0f);
if(result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED)
{
// button_header.setEnabled(false);
}
else
{
// button_header.setEnabled(true);
mTts.setOnUtteranceCompletedListener(this);
}
}
}
}
// setup TTS part 4
private void speakText()
{
lastUtterance++;
if(lastUtterance >= loveArray.length)
{
lastUtterance = 0;
}
Log.v(TAG, "the begin utterance is " + lastUtterance);
for(int i = lastUtterance; i < loveArray.length; i++)
{
params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, String.valueOf(i));
mTts.speak(loveArray[i], TextToSpeech.QUEUE_ADD, params);
mTts.playSilence(ttsilience, TextToSpeech.QUEUE_ADD, null);
}
}
Question:
I found that the Progress Dialog does not show out when Button C in the game index is pressed. However, when the Game_star_intro is finally loaded, the progress dialog pops up for a very very short time and then gone.
I would like to show the ProgressDialog when it is loading up the game, not after the game is loaded then the dialog pops for a millisecond.
In this way, I have also tried to put the load TTS in AsyncTask inside Game_star_intro, yet the result is the same: the dialog just pops up for a millisecond.
Actually how should the AsyncTask be coded?? I have followed some website like this http://karanbalkar.com/2012/10/tutorial-5-custom-progressdialog-with-asynctask/
Thanks for your time!
You shouldn't start your activity in background thread. Start it, for example, in your onClick() method. You should put only your expensive code in doInBackground(), separating it from the framework lifecycle stuff. I guess you should implement AsyncTask inside Game_star_intro class for this.
ProgressDialog is not showing probably because UI thread is freezed until the work is done.
Also, naming conventions in Java suggest name classes without underscores, i.e. GameStarIntro :)
If I understood correctly from your question, loading of the Game_star_intro activity takes a lot of time because you use TTS in creation of this activity. The code you use is wrong. ProgressDialog from Index_game won't be shown when another activity is running (or is being created). You should use AsyncTask in Game_star_intro activity and use TTS there. In Index_game just start Game_star_intro:
buttonC.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
Intent intent = new Intent(Index_game.this, Game_star_intro.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
startActivityForResult(intent, 0);
}
});
And in Game_star_intro something like this
public void onCreate() {
...
new TTLTask().execute();
}
private class TTLTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute()
{
dialog= new ProgressDialog(Index_game.this);
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.setMessage("Loading!\nPlease wait...");
dialog.show();
}
#Override
protected String doInBackground(String... params)
{
//... TTS code
return null;
}
protected void onPostExecute(String result)
{
super.onPostExecute(result);
Log.i("result","" +result);
if(dialog.isShown())
{
dialog.dismiss();
}
}
}

unable to show a progress bar properly

i want to show in my activity a progress bar as a response to a button click.
i read in another question that i should use async task in order to show/not show the progress bar but when i click on the button the progress bar is not shown properly (it appears for much less time then it should)
any suggestions?
the activity code:
public void chooseContactFromList(View view){
ProgressBar pBar = (ProgressBar) findViewById(R.id.progressBar1);
circleActivity progressTask = (circleActivity) new circleActivity(pBar).execute();
AlertDialog.Builder builder = new AlertDialog.Builder(this);
CharSequence[] cs=nameList.toArray(new CharSequence[nameList.size()]);
builder.setTitle("Make your selection");
builder.setItems(cs, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
reciverNumber = phoneList.get(item);
}
});
AlertDialog alert = builder.create();
alert.show();
progressTask.cancel(true);
}
the AsyncTask code:
public class circleActivity extends AsyncTask<Void, Void, Void> {
private ProgressBar progressBar;
public circleActivity(ProgressBar pBar) {
progressBar=pBar;
}
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
progressBar.setVisibility(View.VISIBLE);
}
#Override
protected void onPostExecute(Void result) {
progressBar.setVisibility(View.INVISIBLE);
}
#Override
protected void onProgressUpdate(Void ... progress) {
}
#Override
protected Void doInBackground(Void... arg0) {
// TODO Auto-generated method stub
return null;
}
}
thanks
As you are doing nothing in the doInBackground(), the progressBar is shown for few moments only. If you really want to see it, then try doing some operation in doInBackground() which will take some time.
eg. Try Thread.sleep(1000); in doInBackground to test it.
And I suggest you to refer following links.
http://www.vogella.com/articles/AndroidBackgroundProcessing/article.html
http://developer.android.com/reference/android/os/AsyncTask.html

How to close a Dialog after certain seconds of inactivity?

i have an app that contains a dialog
i want to close this dialog after x second, when user haven't any interact with app, like volume seekbar popup(that's open when the volume button clicked, and closed after 2 second of inactivity).
what is the simplest way to implement this?
thank you
You could for example use a Handler and call its .removeCallbacks() and .postDelayed() method everytime the user interacts with the dialog.
Upon an interaction, the .removeCallbacks() method will cancel the execution of .postDelayed(), and right after that, u start a new Runnable with .postDelayed()
Inside this Runnable, you could close the dialog.
// a dialog
final Dialog dialog = new Dialog(getApplicationContext());
// the code inside run() will be executed if .postDelayed() reaches its delay time
final Runnable runnable = new Runnable() {
#Override
public void run() {
dialog.dismiss(); // hide dialog
}
};
Button interaction = (Button) findViewById(R.id.bottom);
final Handler h = new Handler();
// pressing the button is an "interaction" for example
interaction.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
h.removeCallbacks(runnable); // cancel the running action (the hiding process)
h.postDelayed(runnable, 5000); // start a new hiding process that will trigger after 5 seconds
}
});
For tracking user interaction, you could use:
#Override
public void onUserInteraction(){
h.removeCallbacks(runnable); // cancel the running action (the hiding process)
h.postDelayed(runnable, 5000); // start a new hiding process that will trigger after 5 seconds
}
Which is available in your activity.
I like to do this with AsyncTask:
class ProgressDialogTask extends AsyncTask<Integer, Void, Void> {
public static final int WAIT_LENGTH = 2000;
private ProgressDialog dialog;
public ProgressDialogTask(Activity activity) {
dialog = new ProgressDialog(activity);
}
#Override
protected void onPreExecute() {
dialog.setMessage("Loading");
}
#Override
protected Void doInBackground(final Integer... i) {
long start = System.currentTimeMillis();
while(!isCancelled()&&System.currentTimeMillis()-start< WAIT_LENGTH){}
return null;
}
#Override
protected void onPostExecute(final Void v) {
if(dialog.isShowing()) {
dialog.dismiss();
}
}
}
Then trigger it from your Activity on click:
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ProgressDialogTask task = new ProgressDialogTask(this);
task.execute(0);
}
});
If you need better precision you can also use System.nanoTime()
I am also new at android, but I recommend creating a timer, and when lets say the timer t is greater than or equal to 2, then you do something. It would look kind of like this
if (t >= 2.0){
//Do whatever you want it to do
}
This may not work for your purposes, but it's just something that may require less lines of code in the end. (as I always say, less code is more code) I know that timers are basically easy to make, but I have never used one in an app. I wouldn't specifically know how to make the timer, but I'm sure you can find a tutorial on youtube.
This is the question that came up when I was looking up things regarding timing out. I have implemented an answer which uses AsyncTask, Handler, and Runnable. I am providing my answer here as a potential template for future answer searchers.
private class DownloadTask extends AsyncTask<Void, CharSequence, Void> {
//timeout timer set here for 2 seconds
public static final int timerEnd = 2000;
private Handler timeHandler = new Handler();
#Override
protected void onPreExecute() {
ProgressDialog dProgress = new ProgressDialog(/*Context*/);
dProgress.setMessage("Connecting...");
dProgress.setCancelable(false);
dProgress.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
//Dismissing dProgress
dialog.dismiss();
//Removing any Runnables
timeHandler.removeCallbacks(handleTimeout);
//cancelling the AsyncTask
cancel(true);
//Displaying a confirmation dialog
AlertDialog.Builder builder = new AlertDialog.Builder(/*Context*/);
builder.setMessage("Download cancelled.");
builder.setCancelable(false);
builder.setPositiveButton("OK", null);
builder.show();
} //End onClick()
}); //End new OnClickListener()
dProgress.show();
} //End onPreExecute()
#Override
protected Void doInBackground(Void... params) {
//Do code stuff here
//Somewhere, where you need, call this line to start the timer.
timeHandler.postDelayed(handleTimeout, timerEnd);
//when you need, call onProgressUpdate() to reset the timer and
//output an updated message on dProgress.
//...
//When you're done, remove the timer runnable.
timeHandler.removeCallbacks(handleTimeout);
return null;
} //End doInBackground()
#Override
protected void onProgressUpdate(CharSequence... values) {
//Update dProgress's text
dProgress.setMessage(values[0]);
//Reset the timer (remove and re-add)
timeHandler.removeCallbacks(handleTimeout);
timeHandler.postDelayed(handleTimeout, timerEnd);
} //End onProgressUpdate()
private Runnable handleTimeout = new Runnable() {
public void run() {
//Dismiss dProgress and bring up the timeout dialog
dProgress.dismiss();
AlertDialog.Builder builder = new AlertDialog.Builder(/*Context*/);
builder.setMessage("Download timed out.");
builder.setCancelable(false);
builder.setPositiveButton("OK", null);
builder.show();
}
}; //End Runnable()
} //End DownloadTask class
To those somewhat new to using AsyncTask, you must make a DownloadTask object and call .execute().
For example:
DownloadTask dTaskObject = new DownloadTask();
dTaskObject.execute();
I actually also took this code further than what you see by having all my doInBackground() code be done via a function, so I actually had to call onProgressUpdate() and other functions using the DownloadTask object.

cannot display progress bar at the time of loading another Activity in Android

This may be a simple question but i am a beginner ,i need your suggestion on this.
i have two Activities A1 and A2 .When i click the image on A1 screen i have to display progress bar until A2 screen appears(A2 activity has huge task to do).I tried
image.setOnClickListener(new ImageView.OnClickListener() {
public void onClick(View v)
{
myProgressDialog = ProgressDialog.show(A1.this,
"Please wait...", "Loading...", true);
new Thread() {
public void run() {
try{
Intent i = new Intent(A1.this,.A2.class);
startActivity(i);
} catch (Exception e) { }
// Dismiss the Dialog
myProgressDialog.dismiss();
}
}.start();
}
});
This couldn't display progress bar .I know that i am making a mistake but i couldn't figure out
Your best bet is to show the progress dialog in the A2 activity. Once you start an Activity, the previous activity goes into the background, so the progress dialog wouldn't display anyway.
First of all , the progress dialog needs to be called on a separate thread . Use the AsyncTask<> to display the dialog and at the same time perform some operation in the background . A sample code might be something like this
class hello extends AsyncTask<Void,Void,Void>
{
ProgressDialog dialog=null;
Intent i;
#Override
protected void onPreExecute()
{
dialog=ProgressDialog.show(A1.this,"PLEASE WAIT","LOADING CONTENTS ..",true);
}
#Override
protected void onPostExecute(Void result)
{
if(dialog.isShowing())
{
dialog.dismiss();
startActivity(i);
}
}
#Override
protected Void doInBackground(Void... params)
{
i = new Intent(A1.this,.A2.class);
return null;
}

Categories

Resources