I have two activities. While switching to second activity by intent, it takes 3-4 seconds because it has lots of components with adapters fetching data from SQLite etc. Thus, I want to show a progress dialog while switching.
I have been digging topics for this purpose and tried many of them:
1-) Using AsyncTask on the second activity. It doesn't show the progress dialog as soon as I click on a component to switch to the second activity. It waits for 3-4 seconds and then progress dialog shows up for less then a second which is not user-friendly way.
2-) Using AsyncTask on the first activity. It shows as soon as I click on that component but the progress wheel doesn't spin. The progress dialog freezes.
3-) Using AsyncTask onStart() method on the second activity. This results as the first way.
The code below implements the second way above, using AsyncTask on the first activity.
public void toVisitRegister(Event event) { //Switching to the second activity
new startingThread().execute();
Intent toVisitRegister = new Intent(MainCalendar.this, VisitRegister.class);
startActivity(toVisitRegister);
finish();
}
And here is the AsyncTask
public class startingThread extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
startingProgress = new ProgressDialog(MainCalendar.this);
startingProgress.setTitle("Visit Register");
startingProgress.setMessage("Initializing...");
startingProgress.show();
}
#Override
protected String doInBackground(String... params) {
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if(MainCalendar.this.startingProgress != null) {
MainCalendar.this.startingProgress.dismiss();
}
}
}
I also tried to call startActivity in onPostExecute, but it didn't work. Therefore, I am waiting for your opinions and suggessions about this issue. Any help will be appreciated.
Thanks.
I also tried to call startActivity in onPostExecute,
Pass the Activity context to startingThread AsyncTask and put your start activity code in onPostExecute() of AsyncTask.
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if(MainCalendar.this.startingProgress != null) {
MainCalendar.this.startingProgress.dismiss();
Intent toVisitRegister = new Intent(MainCalendar.this, VisitRegister.class);
mContext.startActivity(toVisitRegister);
mContext.finish();
}
}
Here mContext is the Context of your current MainCalendar Activity.
Looking at your implementation, the AsyncTask wont have time to work because you will be jumping to the next Activity right away. Try calling the next activity in PostExecute().
I also tried to call startActivity in onPostExecute, but it didn't work.
Did you did it like this:
public void toVisitRegister(Event event) { //Switching to the second activity
new startingThread().execute();
}
public class startingThread extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
startingProgress = new ProgressDialog(MainCalendar.this);
startingProgress.setTitle("Visit Register");
startingProgress.setMessage("Initializing...");
startingProgress.show();
}
#Override
protected String doInBackground(String... params) {
return null;
}
#Override
protected void onPostExecute(String result) {
if(MainCalendar.this.startingProgress != null) {
MainCalendar.this.startingProgress.dismiss();
}
Intent toVisitRegister = new Intent(MainCalendar.this, VisitRegister.class);
startActivity(toVisitRegister);
finish();
}
}
Related
I use an async task to upload an image and get some results.
While uploading the image I see a progress dialog, written in onPreExecute() method like this:
protected void onPreExecute() {
uploadingDialog = new ProgressDialog(MyActivity.this);
uploadingDialog.setMessage("uploading");
uploadingDialog.setCancelable(true);
uploadingDialog.show();
}
Ok when I press the back button, obviously the dialog disappears because of the setCancelable(true).
But (obviously) the async task doesn't stop.
So how can I fix this? I want to cancel both dialog and async task when I press the back button. Any ideas?
From SDK:
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.)
So your code is right for dialog listener:
uploadingDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
myTask.cancel(true);
//finish();
}
});
Now, as I have mentioned earlier from SDK, you have to check whether the task is cancelled or not, for that you have to check isCancelled() inside the onPreExecute() method.
For example:
if (isCancelled())
break;
else
{
// do your work here
}
FOUND THE SOLUTION:
I added an action listener before uploadingDialog.show() like this:
uploadingDialog.setOnCancelListener(new DialogInterface.OnCancelListener(){
public void onCancel(DialogInterface dialog) {
myTask.cancel(true);
//finish();
}
});
That way when I press the back button, the above OnCancelListener cancels both dialog and task. Also you can add finish() if you want to finish the whole activity on back pressed. Remember to declare your async task as a variable like this:
MyAsyncTask myTask=null;
and execute your async task like this:
myTask = new MyAsyncTask();
myTask.execute();
I spent a while figuring this out, all I wanted was a simple example of how to do it, so I thought I'd post how I did it. This is some code that updates a library and has a progress dialog showing how many books have been updated and cancels when a user dismisses the dialog:
private class UpdateLibrary extends AsyncTask<Void, Integer, Boolean>{
private ProgressDialog dialog = new ProgressDialog(Library.this);
private int total = Library.instance.appState.getAvailableText().length;
private int count = 0;
//Used as handler to cancel task if back button is pressed
private AsyncTask<Void, Integer, Boolean> updateTask = null;
#Override
protected void onPreExecute(){
updateTask = this;
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setOnDismissListener(new OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
updateTask.cancel(true);
}
});
dialog.setMessage("Updating Library...");
dialog.setMax(total);
dialog.show();
}
#Override
protected Boolean doInBackground(Void... arg0) {
for (int i = 0; i < appState.getAvailableText().length;i++){
if(isCancelled()){
break;
}
//Do your updating stuff here
}
}
#Override
protected void onProgressUpdate(Integer... progress){
count += progress[0];
dialog.setProgress(count);
}
#Override
protected void onPostExecute(Boolean finished){
dialog.dismiss();
if (finished)
DialogHelper.showMessage(Str.TEXT_UPDATELIBRARY, Str.TEXT_UPDATECOMPLETED, Library.instance);
else
DialogHelper.showMessage(Str.TEXT_UPDATELIBRARY,Str.TEXT_NOUPDATE , Library.instance);
}
}
create some member variables in your activity like
YourAsyncTask mTask;
Dialog mDialog;
use these for your dialog and task;
in onPause() simply call
if(mTask!=null) mTask.cancel();
if(mDialog!=null) mDialog.dismiss();
I would like to improve the code. When you canel the aSyncTask the onCancelled() (callback method of aSyncTask) gets automatically called, and there you can hide your progressBarDialog.
You can include this code as well:
public class information extends AsyncTask<String, String, String>
{
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... arg0) {
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
this.cancel(true);
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
}
#Override
protected void onCancelled() {
Toast.makeText(getApplicationContext(), "asynctack cancelled.....", Toast.LENGTH_SHORT).show();
dialog.hide(); /*hide the progressbar dialog here...*/
super.onCancelled();
}
}
Most of the time that I use AsyncTask my business logic is on a separated business class instead of being on the UI. In that case, I couldn't have a loop at doInBackground(). An example would be a synchronization process that consumes services and persist data one after another.
I end up handing on my task to the business object so it can handle cancelation. My setup is like this:
public abstract class MyActivity extends Activity {
private Task mTask;
private Business mBusiness;
public void startTask() {
if (mTask != null) {
mTask.cancel(true);
}
mTask = new mTask();
mTask.execute();
}
}
protected class Task extends AsyncTask<Void, Void, Boolean> {
#Override
protected void onCancelled() {
super.onCancelled();
mTask.cancel(true);
// ask if user wants to try again
}
#Override
protected Boolean doInBackground(Void... params) {
return mBusiness.synchronize(this);
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
mTask = null;
if (result) {
// done!
}
else {
// ask if user wants to try again
}
}
}
public class Business {
public boolean synchronize(AsyncTask<?, ?, ?> task) {
boolean response = false;
response = loadStuff(task);
if (response)
response = loadMoreStuff(task);
return response;
}
private boolean loadStuff(AsyncTask<?, ?, ?> task) {
if (task != null && task.isCancelled()) return false;
// load stuff
return true;
}
}
I had a similar problem - essentially I was getting a NPE in an async task after the user had destroyed the activity. After researching the problem on Stack Overflow, I adopted the following solution:
volatile boolean running;
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
running=true;
...
}
public void onDestroy() {
super.onDestroy();
running=false;
...
}
Then, I check "if running" periodically in my async code. I have stress tested this and I am now unable to "break" my activity. This works perfectly and has the advantage of being simpler than some of the solutions I have seen on SO.
You can just ask for cancellation but not really terminate it. See this answer.
How to cancel AsyncTask
Full answer is here - Android AsyncTask Example
AsyncTask provides a better cancellation strategy, to terminate currently running task.
cancel(boolean mayInterruptIfitRunning)
myTask.cancel(false)- It makes isCancelled returns true. Helps to cancel the task.
myTask.cancel(true) – It also makes isCancelled() returns true, interrupt the background thread and relieves resources .
It is considered as an arrogant way, If there is any thread.sleep() method performing in background thread, cancel(true) will interrupt background thread at that time. But cancel(false) will wait for it and cancel task when that method completes.
If you invoke cancel() and doInBackground() hasn’t begun execute yet. onCancelled() will invoke.
After invoking cancel(…) you should check value returned by isCancelled() on doInbackground() periodically. just like shown below.
protected Object doInBackground(Params… params) {
while (condition)
{
...
if (isCancelled())
break;
}
return null;
}
I have a button on my app, if the user click it, it will refresh the current page by calling onResume(), and there are lots of database operations in onResume(). Instead of keeping the button stay pressed for a while, I would like to use asynctask to make a progressdialog while loading the data. But the problem is that the button will still be in pressed state and the progressdialog only show at the end of the operation for a very short duration.
RefreshButton.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
onResume();
}
});
protected void onResume()
{
doneloading = false;
monResumeloading = new onResumeloading();
monResumeloading.execute();
....loading...
doneloading = true;
}
private class onResumeloading extends AsyncTask<Integer, Integer, String>
{
private ProgressDialog progressDialog;
#Override
protected void onPostExecute(String result)
{
progressDialog.dismiss();
}
#Override
protected void onPreExecute()
{
progressDialog = new ProgressDialog(StatisticsActivity.this);
progressDialog.setMessage("Loading...");
progressDialog.setCancelable(true);
progressDialog.show();
Log.i(TAG, " doneloading=false");
}
#Override
protected void onProgressUpdate(Integer... values)
{
}
#Override
protected String doInBackground(Integer... params)
{
while(!doneloading)
{
publishProgress(0); //dummy
log.i(TAG, "loading");
}
return null;
}
}
I observed that the "loading" log is showing right after the asynctask execution and stop right after the boolean doneloading becomes false. But the progressdialog is not working properly. Please help me :(
First thing, I don't think you should be calling your AsyncTask in the onResume() function. You can simply call it from your ClickListener.
Right now, you are doing your '....loading...' code before you even execute your AsyncTask. That's why the button stays pressed while it's executing '....loading...' and then when it's done, it executes your AsyncTask which really isn't doing anything - that's why it just shows up for a short duration.
Move your '....loading...' code into your doInBackground() of your AsyncTask and it should work ok.
Summary:
Click: Execute AsyncTask
AsyncTask: opens ProgressDialog
AsyncTask: Executes your '...loading...' code
AsyncTask: Wait for '...loading...' code to complete while still displaying dialog.
AsyncTask: Dismiss ProgressDialog
I have two activities. The first one executes the second one.
Intent i = new Intent(MyOne.this, MyTwo.class);
startActivity(i);
The problem: My second activity does some heavy work on launching so it launches couple of second and before it is launched i see a black screen.
Is it any way to set a progressbar or some image instead of this black screen? Because i don't think user will wait for something, that he doesn't know. I tried setting progressbar after setcontentview in my second activity, but progressbar shows up only when activity fully started.
I suggest you to do this asynchronously using AsyncTask.
Short example:
ProgressDialog dialog;
class YourTask extends AsyncTask<Void, Void, Void> {
protected void onPreExecute() {
dialog = ProgressDialog.show(...);
}
protected Void doInBackground(Void... unused) {
try {
// doSomethingHeavy();
// publishProgress(...);
} catch(Exception e) {
//...
}
return null;
}
protected void onProgressUpdate(Void... unused) {
}
protected void onPostExecute(Void unused) {
dialog.dismiss();
}
}
You sure can. Check out the AsyncTask and this tutorial for inspiration.
Dear Android hackers,
I am trying to do the following in my Android App: When the User clicks on a list item in a ListActivity, a ProgressDialog should show up, some preloading should happen and after it's done, another Activity should be called using an intent.
I tried different approaches. What didn't work at all was using an Async Task. Apparently I cannot show, dismiss or edit my ProgressDialog out of the Async Task, if that Class is not a Member of my original Activity.
I switched to a simple Thread then, this is how I'm trying to do it:
dialog = ProgressDialog.show(BookmarkActivity.this, "", "Loading...",true);
new Thread() {
public void run() {
// do something
dialog.setMessage("Change Message...");
// do more
dialog.dismiss();
// ...
Intent intent = new Intent(BookmarkActivity.this, ThreadActivity.class);
BookmarkActivity.this.startActivity(intent);
}
}.start();
This works almost, but the changing of the dialog message does not. I'm getting errors saying something about "leaked windows". (I can post the complete log if it is needed).
My questions:
How can I use an Async Task for this, where the Class has it's own file?
How can I change the ProgressDialog out of my Thread or AsyncTask without causing an error for changing the UI in another thread?
Thanks in advance, Jan Oliver
Ok, with the help of Jason, I put together this Async Task. That works!
public class ThreadPreLoader extends AsyncTask<Object, String, Void> {
private Activity mActivity;
private ProgressDialog mDialog;
public ThreadPreLoader(Activity activity) {
mActivity = activity;
}
protected void onPreExecute() {
mDialog = new ProgressDialog(mActivity);
mDialog.setMessage("Loading...");
mDialog.show();
}
protected Void doInBackground(Object... args) {
publishProgress("Loading something else..");
return null;
}
protected void onProgressUpdate(String... msg) {
mDialog.setMessage(msg[0]);
}
protected void onPostExecute(Void result) {
mDialog.dismiss();
}
}
Thanks again, Jason.
You should use an Async Task, Define a custom Async Task which receives the context (this) of the original activity.
Then keep that context for later Dismissing the dialog.
From your doInBackground() method you can call postProgress( int progress) which will cause onProgressUpdate() to be called in the async task , this method is on the UI thread so it will not cause cross thread errors.
Once doInBackground() is complete the method onComplete() will also be called on the UI thread, this is where you can use your saved context and dissmiss the dialog (context.dissmissDialog()
Take a look at Android's Handler class. If you create the Handler in the onCreate method of your activity, Runnables that are sent to the post method of the handler are then run on the UI thread of your activity:
Handler h;
protected void onCreate(Bundle bundle) {
h = new Handler;
new Thread() {
public void run() {
// your run code
h.post(new Runnable() { /* change dialog here */ });
}
}.start();
}
I'm not sure that's the best option, but worth a try.
In AsyncTask
You should do you work which need time in doInBackground and calling intent like things, that you need to do after this task should be in onPostExecute
public class ThreadPreLoader extends AsyncTask<Object, String, Void> {
private Activity mActivity;
private ProgressDialog mDialog;
public ThreadPreLoader(Activity activity) {
mActivity = activity;
}
protected void onPreExecute() {
mDialog = new ProgressDialog(mActivity);
mDialog.setMessage("Loading...");
mDialog.show();
}
protected Void doInBackground(Object... args) {
//do more
publishProgress("Loading something and reached somewhere..");
//do more
publishProgress("Loading something and reached somewhere..");
//do more
return null;
}
protected void onProgressUpdate(String msg) {
mDialog.setMessage(msg);
}
protected void onPostExecute() {
Intent intent = new Intent(BookmarkActivity.this, ThreadActivity.class);
BookmarkActivity.this.startActivity(intent);
mDialog.dismiss();
}
}
I admit, I'm new at this whole Android stuff. I am trying to make an app but randomly I get Force close errors and I really don't know why. My application has many activities, none of them finish() when I start a new one. I get data from the web (via web services and direct image downloading) and I use AsyncTask a lot. Most of the time it crashes on the asynctask. Here is a sample on how I do things:
private BackTask backTask;
Activity ctx = this;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.trackslist);
backTask = new BackTask();
backTask.execute();
}
protected class BackTask extends AsyncTask<Context, String, myObject>
{
#Override
protected myObject doInBackground(Context... params)
{
try{
if (hasInternet(ctx)==true)
{
//access the web SERVICE here
//initialize myObject WITH result FROM the web
return myObject
}
else
{
return null
}
}catch(Exception ex){
return null;
}
}
#Override
protected void onPreExecute()
{
super.onPreExecute();
}
#Override
protected void onProgressUpdate(String... values)
{
super.onProgressUpdate(values);
}
#Override
protected void onCancelled()
{
super.onCancelled();
}
#Override
protected void onPostExecute( myObject result )
{
super.onPostExecute(result);
if (result==null || result.isEmpty())
{
//no valid result, show a message
}
else
{
//result valid do something with it
}
}
}
#Override
public void onPause()
{
if (backTask!=null && ! backTask.isCancelled())
{
backTask.cancel(true);
}
super.onPause();
}
public void btnStartOnClick(View target) {
Intent intent = new Intent(this, MyNewActivity.class);
startActivity(intent);
}
When the activity gets onPause() the task is being canceled. I am not sure what happens during the try/catch if a error appears, from what I've did, it should return null, but I think here I miss something. As I said before, randomly I get a force close even if I am on another Activity. This is really frustrating as I can't offer a app that has this behavior. So, what am I doing wrong ?
There is problem in your code. I have corrected as follows: You find I have added this while calling async task.
Your async task accept context as argument and you was not passing that.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.trackslist);
backTask = new BackTask();
backTask.execute(this);
}
You need to ask inside your AsyncTask class for isCancelled() and then decide what to do.
Check this question. It has a good explanation by Romain Guy:
You can stop an AsyncTask. If you call
cancel(true), an interrupt will be
sent to the background thread, which
may help interruptible tasks.
Otherwise, you should simply make sure
to check isCancelled() regularly in
your doInBackground() method. You can
see examples of this at
code.google.com/p/shelves.