Found that weird bahaviour of ProgressDialog.
I show ProgressDialog in onClickListener of list before starting new Thread and dismiss it inside that Thread but after all work is done:
GlobalProgressDialog.show(getActivity());
new Thread(new Runnable() {
#Override
public void run() {
//...all other logic
GlobalProgressDialog.dismiss();
}
}).start();
and that GlobalProgressDialog i use to simplify calls:
public class GlobalProgressDialog{
private static ProgressDialog progressDialog;
public static void show(Activity activity){
progressDialog = new ProgressDialog(activity);
progressDialog.setMessage("Loading...");
progressDialog.show();
}
public static void dismiss(){
if (progressDialog != null) {
progressDialog.dismiss();
}
}
}
Dialog appears but NOT exactly after show() being called! I have debugged it and found out that there are 4 standard Android classes are being operated:
AdapterView.java
AbsListView.java
Handler.java
Looper.java
And only after Looper the ProgressDialog is being snown. Is it possible to trick this or fix? Or maybe there's some my fault in code? What could it be?
The problem is that delay between item click and show() is like 1 sec. So application freezes for 1 sec. And only then dialog appears and all work done takes 1-2 sec, sometimes even 0.5 sec. In such cases its not cool to look at frozen app and flashed for 0.5 sec progress dialog.
Thanks in advance.
You're doing too much work on the main thread. show() will show the dialog, but it will do so on the main thread. It does not block execution until it is dismissed. So something you're doing in your code after calling show() and which you are not showing us, is causing the delay in the appearance of the dialog.
Just to be clear again, this has nothing to do with the Thread you're starting and changing it to an AsyncTask won't fix it, although it might be a good idea to do that anyway if the pattern fits your use case.
You should use a AsyncTask here.
public class DialogAsync extends AsyncTask<Void, Void, Void> {
private Context context;
private ProgressDialog progressDialog;
public DialogAsync(Context context) {
this.context = context;
progressDialog = new ProgressDialog(context);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog.setMessage("Loading...");
progressDialog.show();
}
#Override
protected Void doInBackground(Void... params) {
// Perform your logic here
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
progressDialog.dismiss();
}
}
Usage:
DialogAsync globalProgessDialog = new DialogAsync(getActivity());
globalProgessDialog.execute();
Related
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 am using an AsyncTask (which I am starting in my main activity) to load some data:
Context context = VehicleTabView.this;
ProgressDialog progressDialog = new ProgressDialog(context);
progressDialog.setMessage("Loading...");
new LoadingVehicles(context, progressDialog).execute(null, null, null);
Here is the AsyncClass:
package com.example.schedule_vehicles;
import com.example.utils.VehicleNames;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
// Showing a ProgressDialog once loading the list of vehicles is completed using an AsyncTask
public class LoadingVehicles extends AsyncTask<Void, Void, Void> {
Context context;
ProgressDialog progressDialog;
public LoadingVehicles(Context context, ProgressDialog progressDialog) {
this.context = context;
this.progressDialog = progressDialog;
}
#Override
protected void onPreExecute() {
progressDialog.show();
}
#Override
protected Void doInBackground(Void... params) {
new VehicleNames(context);
return null;
}
#Override
protected void onPostExecute(Void result) {
progressDialog.dismiss();
}
}
The problem that the ProgressDialog is not showing on the screen.
I type Log.d, to see if the program is going through all the phases - onPreExecute, doInBackground, onPostExecute, and it is going through all the phases and doing the job that I need. But the ProgressDialog is not showing. I read a lot of information about this thing and it seems that the PRE and POST execute are started by the main thread, which is blocked by the DOINBACKGROUND method, and this is the reason not to see the ProgressDialog. I tried to find some answer how this is solved - but no success.
If anyone faced this, please share your experience. THANKS a lot!
You're passing the ProgressDialog to the Task, just show() it before you start the AsyncTask, not from within the AsyncTask.
Your code looks good to me. You are correct about your understanding of Asynctask and your use of them also appears correct.
The only thing that I can think of is that you must make sure that you are calling execute() on the UI Thread as well. From the code posted I'm not able to tell what context you are in.
Make sure you can pass in "this" as a context. That will tell you if your on the UI thread or not.
ProgressDialog progressDialog = new ProgressDialog(this);
Try :
ProgressDialog progressDialog = new ProgressDialog([Activity Name].this);
Let me know if this solves the problem or I'll see in depth.
Maybe you are missing the context.
ProgressDialog progressDialog = new ProgressDialog(this);
Normally when creating a ProgressDialog, you use the static method ProgressDialog.show(context, title, message). This will create and show the message and give you back a reference to the dialog.
onPreExecute and onPostExecute are called on the main thread, and are not blocked by the doInBackground, which runs on another thread. onPreExecute is called before doInBackground and onPostExecute is called after.
Here's some example code:
public static class InitializeTask extends MyAsyncTask<String, String, Response<Object>> {
private Activity activity;
private ProgressDialog dialog;
public InitializeTask(Activity activity) {
this.activity = activity;
}
#Override
protected void onPreExecute() {
dialog = ProgressDialog.show(activity, null, "Initializing...");
}
#Override
protected void onPostExecute(Response<Object> result) {
if (dialog != null && dialog.isShowing())
dialog.dismiss();
}
#Override
protected Response<Object> doInBackground(String... params) {
}
#Override
protected void attach(Activity context) {
this.activity = context;
dialog = ProgressDialog.show(context, null, "Initialize...");
}
#Override
protected void detach() {
if (dialog.isShowing())
dialog.dismiss();
activity = null;
}
}
Attach and detach are my own methods for referencing a cross orientation changes.
The next version of my app needs to upgrade the database and this takes quite a bit of time. I'd like to show a progressDialog to update the user on the progress. Problem is, I can't quite figure out how and where to create the dialog.
My basic setup is that I have an activity which is essentially a splashscreen. It's on this screen I would like to show the progress. I have a separate DbAdapter.java file where a DatabaseHelper class extends SQLiteOpenHelper, where I override onUpgrade (the upgrade part is working fine).
I've tried a few different places to implement the progress dialog, but I don't seem to find the right spot. I tried passing context from my splashscreen activity to onUpgrade, but when onUpgrade runs it seems to be getting the context from my ContentProvider instead.
Does anyone have a good example of how to display a progress dialog when upgrading a database?
You need to implement an AsyncTask. Example:
class YourAsyncTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
//show your dialog here
progressDialog = ProgressDialog.show(this, "title", "message", true, false)
}
#Override
protected Void doInBackground(Void... params) {
//update your DB - it will run in a different thread
return null;
}
#Override
protected void onPostExecute(Void result) {
//hide your dialog here
progressDialog.dismiss();
}
}
Then you just have to call
new YourAsyncTask().execute();
You can read more about AsyncTask here: http://developer.android.com/reference/android/os/AsyncTask.html
ProgressDialog myProgressDialog = null;
public void DownloadFiles() {
myProgressDialog = ProgressDialog.show(this, "Please wait !",
"Updating...", true);
new Thread() {
public void run() {
try {
//Your upgrade method !
YourUpdateFunction();
} catch (Exception e) {
Log.v(TAG, "Error");
}
myProgressDialog.dismiss();
}
}.start();
}
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 have been searching for an answer for this for some time now. I have an async task that downloads the database needed for my app, while this is downloading my app cant do anything as all the data it references is in this file, i have the app waiting for the file to be downloaded but i am attempting to show a progress dialog so the user knows something is happening while they wait for this to happen.
my code is currently
public class fileDownloader extends AsyncTask<Void, Integer, SQLiteDatabase>
{
private File dbFile;
private ProgressDialog progressDialog;
private Context context;
private SQLiteDatabase database;
private SQLiteDatabase.CursorFactory factory;
public fileDownloader(Context c)
{
super();
context = c;
}
#Override
protected void onPreExecute()
{
super.onPreExecute();
progressDialog = new ProgressDialog(this.context);
progressDialog.setMessage("Downloading Database...");
progressDialog.setCancelable(false);
progressDialog.setIndeterminate(true);
progressDialog.show();
}
#Override
protected SQLiteDatabase doInBackground(Void... v)
{
....
}
#Override
protected void onPostExecute(SQLiteDatabase db1)
{
progressDialog.dismiss();
}
however nothing shows up i have also tried directly calling ProgressDialog.show in the pre execute and moving this to the calling activity with no luck.
please help!
the solution to this was to look at the calling class the UI thread was getting blocked therefor the dialog never showed up.
Hmm - how long does your doInBackground method run? Maybe your dialog is shown, but the time is just too fast for the dialog to show up...
Below code is working fine, I am using it:
private class DownloadHomeSectionData extends
AsyncTask<Void, Void, Boolean> {
ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(mainScreen);
progressDialog.setMessage(getResources()
.getString(R.string.loading));
progressDialog.setCancelable(false);
progressDialog.setIndeterminate(true);
progressDialog.show();
}
#Override
protected Boolean doInBackground(Void... params) {
for (HomeButton homeBtn : appDesigner.getHomeButtons()) {
StorageManager.getInstance().downloadFileSyncronously(
homeBtn.getTab_logo_selected_image());
StorageManager.getInstance().downloadFileSyncronously(
homeBtn.getTab_logo_unselected_image());
}
return null;
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
progressDialog.dismiss();
}
}
In your case, I think you may be passing wrong context to ProgressDialog.