Is there a preferred way to show 'loading' animations in Android? Currently I'm showing Dialog with the text "Loading..." for long running processes. It's tricky to get a .gif to work for this, so I'm wondering if this is a problem that has been solved before, and if so, how?
In my apps, I typically use a ProgressDialog to show a spinning "Loading..." message. There are fancier/prettier ways, but this is a quick and easy built-in solution.
ProgressDialog progressDialog = ProgressDialog.show(Activity.this, "",
"Loading...");
...Do some work...
progressDialog.dismiss();
progressDialog = null;
If you have a static Utilities class to generate things like Alerts and Dialogs, here are 2 nice additions:
public static ProgressDialog createProgressDialog(Context context, String title, String message, boolean isCancelable)
{
ProgressDialog dialog = new ProgressDialog(context);
dialog.setTitle(title);
dialog.setMessage(message);
dialog.setCancelable(isCancelable);
return dialog;
}
If you are using AsyncTasks to do your work in the background, it is especially important to check that the Activity is still "alive" and not finishing when you show and dismiss the ProgressDialog, or your app will die with a bizarre exception(see this answer).
public static void safeShowProgressDialog(Context context, ProgressDialog dialog)
{
if(!((Activity) context).isFinishing())
{
dialog.show();
}
}
Same for dismissing the dialog:
public static void safeDismissProgressDialog(Context context, ProgressDialog dialog)
{
if(!((Activity) context).isFinishing())
{
dialog.dismiss();
}
}
See the API reference:
http://developer.android.com/reference/android/app/ProgressDialog.html
Here is good example:
Let's say you try to login and wait response from Server. On wait you show Progress Dialog and on Success switch login activity to Main:
private ProgressDialog dialog;
...
dialog = ProgressDialog.show(FirstLoginActivity.this, "", "Connecting. Please wait...", true);
HeavyTask task = new HeavyTask();
task.execute(str1, str2);
private class HeavyTask extends AsyncTask<String, Void, Void> {
private String str1= "";
private String str2= "";
protected Void doInBackground(String... args) {
str1= args[0];
str2= args[1];
try {
doSomething(str1, str2);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(Void results) {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
doStuff(str1, str2);
}
}, 500);
}
private void doStuff(String str1, String str2) {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
startActivity(new Intent().setClass(FirstLoginActivity.this, OtherActivity.class).setData(getIntent().getData()));
Toast.makeText(getApplicationContext(), "Registration succeeded.", Toast.LENGTH_LONG).show();
//kill the dialog waiting
dialog.dismiss();
dialog = null;
}
}, 1000);
}
You can find some guidance in the Android Design documentation: http://developer.android.com/design/building-blocks/progress.html
you can use progress bar. i usually use it through asyctasks. and overload the following method as:
protected void onProgressUpdate(Integer... progress) {
((ProgressBar) findViewById(R.id.progressBar1)).setProgress(progress[0]);
}
Depending on your application design it would vary but a ProgressDialog is a fairly common solution. This tutorial would show you how it all get's tied together and the two variations (with or without displaying progress).
Related
I am new in android. I am trying to display ProgressDialog when click on button .
This is my code:
// set listener
btn_Login.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//progress.show();
MyAsynch asynch = new MyAsynch();
asynch.execute();
}
In this code progress dialog too much late appear when i am comment on Asynctask object then progress dialog appear normally.
I am puting my progress dialog in
AsynchTask method
onPreExecute() but same out put dialog display late .
How to solve my problem..??
I am also read stack answers following link but not solve my problem .
async task progress dialog show too late
ProgressDialog appears too late and dissapears too fast
here is my Asynctask code
private class MyAsynch extends AsyncTask<String, Void, String> {
ProgressDialog progress;
String login_stat;
String stat;
#Override
protected void onPreExecute() {
progress = new ProgressDialog(this);
progress.setTitle(" User Login ");
progress.setMessage("Please Wait!!");
progress.setCancelable(false);
progress.setIndeterminate(true);
progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progress.show();
}
#Override
protected String doInBackground(String... urls) {
try {
login_stat = s_ApiHandling.doLogin(m_Et_Username.getText()
.toString().trim(), m_Et_Password.getText()
.toString().trim());
} catch (Exception e) {
System.out.println("internet connection loss ");
stat = "ERORR";
e.printStackTrace();
}
return stat;
}
#Override
protected void onPostExecute(String status) {
progress.dismiss();
}
}
You are probably doing too much in onPreExecute
Remove progress.cancel() from your doInBackground method and put it in to a onPostExecute method in your AsyncTask (like the second link you posted)
You shouldn't have anything talking to the UI in a background thread - that should all be done in pre/post execution.
you code should look like this:
AsyncTask<String, Void, String>()
{
private ProgressDialog progressDialog = ProgressDialog.show(this, "", "Loading...");
#Override
protected void onPostExecute(String result)
{
progressDialog.dismiss();
}
#Override
protected String[] doInBackground(String... params)
{
//ALL CODE GOES HERE.
}
}
When you call the asynctask you must not use the get() method or the progress dialog won't work correctly.
I have an AsyncTask that is supposed to show a progress bar while it uploads some stuff via Internet. Sometimes it works like a charm and sometimes it does not show any progress bar. Here is the code:
public class Upload extends AsyncTask<Void, Void, Void> {
private ProgressDialog dialog = new ProgressDialog(Activity.this);
protected void onPreExecute() {
dialog = ProgressDialog.show(Activity.this, "wait...", "", true, true);
}
#Override
protected Void doInBackground(Void... params) {
//upload stuff
return null;
}
protected void onPostExecute(Void result) {
try {
if (dialog.isShowing())
dialog.dismiss();
dialog = null;
} catch (Exception e) {
// nothing
}
Intent next = new Intent(getApplicationContext(), SecondActivity.class);
startActivity(next);
}
}
}
The doInBackground and onPostExecute work always, and sometimes altogether it works like a charm. But sometimes, there is no progress bar while it is uploading. Is this a race condition? I do not think so, but I cannot find any explanation.
You're creating the object twice in the class. The ProgressDialog.show already returns a created ProgressDialog object, but you have instantiated it first at the top. The ProgressDialog should be instantiated once, so try removing the instantiation at the top and try again, like so:
private ProgressDialog dialog;
protected void onPreExecute() {
dialog = ProgressDialog.show(Activity.this, "wait...", "", true, true);
}
Maybe it is because void parameter that causes that problem. Just try to use Integer as your parameters.:
public class Upload extends AsyncTask<Integer, Integer, Integer>
I have a huge database (40MB) on an SDCard. I need fetch data, with LIKE in query, which is very slow.
DB request takes about 5 seconds. Therefore, I need to do it asynchronously and with ProgressDialog.
I tried it with AsyncTask, but problem is with ProgressDialog. It was implemented this way:
private class GetDataFromLangDB extends AsyncTask<String, String, String> {
private final ProgressDialog dialog = new ProgressDialog(TranslAndActivity.this);
#Override
protected void onPreExecute() {
super.onPreExecute();
urDBCursor.close();
curDBCursor = null;
scaAdapter = null;
this.dialog.setMessage("Loading data...");
this.dialog.show();
}
#Override
protected String doInBackground(String... whatSearch) {
String result = "";
if (myDatabaseAdapter != null) {
curDBCursor = myDatabaseAdapter.fetchAll(whatSearch[0]);
}
return result;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (this.dialog.isShowing()) {
this.dialog.dismiss();
}
prepareListView();
}
}
The problem is that ProgressDialog is not shown during the DB request.
After finished database query, it flash on screen for a short time. When user tries
to tap on screen during database request, UI is freezed, and after DB request
message about 'not responding' is shown.
I tried it with a thread this way:
public void startProgress(View view, final String aWhatSearch) {
final ProgressDialog dialog = new ProgressDialog(MyActivity.this);
if (curDBCursor != null){
curDBCursor.close();
curDBCursor = null;
}
dialog.setMessage("Loading data...");
dialog.show();
Runnable runnable = new Runnable() {
public void run() {
curDBCursor = myDatabaseAdapter.fetchAll(aWhatSearch);
// dirty trick
try {
Thread.sleep(250); // it must be here to show progress
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
public void run() {
if (dialog.isShowing()) {
dialog.dismiss();
}
prepareListView();
}
});
}
};
new Thread(runnable).start();
}
The result was the same, but when I used the trick with Thread.sleep(250);
ProgressDialog was shown during the database request. But it is not spinning,
it looks freezed during the DB request.
DB stuff is called this way (after tap on search button):
btnSearchAll.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// AsyncTask
new GetDataFromLangDB().execute(edtTextToSearch.getText().toString());
// or Thread
//startProgress(null, edtTextToSearch.getText().toString());
}
});
I found a lot of problems like this in SO, but nothing was useful for me.
Could it be that DB is on SD Card?
I put the definition of the dialog into the AsyncTask Class and it works fine for me.
Take a look at this exampel (You have to change NAMEOFCLASS in the name of your CLASS:
private class doInBackground extends AsyncTask<Integer, Integer, Void> {
final ProgressDialog dialog = new ProgressDialog(NAMEOFCLASS.this) {
#Override
protected void onPreExecute() {
dialog.setCancelable(false);
dialog.setTitle(getString(R.string.daten_wait_titel));
dialog.setIcon(R.drawable.icon);
dialog.setMessage(getString(R.string.dse_dialog_speichern));
dialog.show();
}
#Override
protected void onCancelled() {
dialog.cancel();
}
....
#Override
protected void onProgressUpdate(Integer... values) {
// DO YOUR UPDATE HERE
}
#Override
protected void onPostExecute(Void result) {
dialog.dismiss();
}
}
Maybe this SO answer could help you. It looks like similar problem. Try to use AsyncQueryHandler for querying your database
declare you Dialog box on Class (Activity) level like this
private ProgressDialog dialog = null;
show the progress dialog and call the AsyncTask class when you want to start you Busy work..like onButton click or any
dialog = ProgressDialog.show(this,"Sending Email to your account please! wait...", true);
SendingEmailTask task = new SendingEmailTask();
String s = "";
task.execute(s);
create your inner class like
private class SendingEmailTask extends AsyncTask<String, Void, String> {
protected String doInBackground(String... urls) {
//do your work here..
// like fetching the Data from DB or any
return null;
}
#Override
protected void onPostExecute(String str) {
//hide progress dialog here
dialog.dismiss();
}
}
let me know if this help!!
Here is a few bit of code:
public class ShowDialog extends Thread {
private static String mTitle="Please wait";
private static String mText="Loading...";
private Activity mActivity;
private ProgressDialog mDialog;
ShowDialog(Activity activity) {
this(activity, mTitle, mText);
}
ShowDialog(Activity activity, String title) {
this(activity, title, mText);
}
ShowDialog(Activity activity, String title, String text) {
super();
mText=text;
mTitle=title;
mActivity=activity;
if (mDialog == null) {
mDialog = new ProgressDialog(mActivity);
mDialog.setTitle(mTitle);
mDialog.setMessage(mText);
mDialog.setIndeterminate(true);
mDialog.setCancelable(true);
mDialog.setOnCancelListener(
new DialogInterface.OnCancelListener() {
#Override
public void onCancel(DialogInterface arg0) {
mDialog.dismiss();
interrupt();
}
});
}
}
public void run() {
mDialog.show();
while(!isInterrupted())
mDialog.dismiss();
mDialog=null;
}
}
And in my main activity:
ShowDialog show = new ShowDialog(this, "Please wait!","Loading badly...");
show.start();
SystemClock.sleep(2000);
show.interrupt();
I know I might use an async task and all the stuff but that is not what I want. Replace the SystemClock.sleep by anything that takes some time. The idea is to execute the code between start and interrupt in the UI thread and make a seperate thread handling the ProgressDialog.
What's wrong with my thread ?
Thanks a lot!
To wait for a Thread to complete, you should use the Thread.join() method. But now I see you're not wanting to wait for it to complete, but you need to control when it completes. Still, you want to avoid interrupting threads in this fashion.
In your ShowDialog class, add a dismiss() method that you can call from your main, instead of interrupt(). Also add a boolean dismiss = false instance variable. In dismiss(), add dismiss = true, then notify();. In run(), replace your constant while() loop (was running constantly, and very inefficient) with while(!dismiss){wait()}. You will still need to add synchronization blocks and exception handling, but this should get you off to a good start.
Here is a generic-Java (non-android) simplified example:
public static class ShowDialog extends Thread{
protected boolean dismiss;
public void dismiss(){
dismiss = true;
synchronized(this){
notifyAll();
}
}
#Override
public void run(){
System.out.println("Running...");
// Show your dialog here.
while(!dismiss){
synchronized(this){
try{
wait();
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
}
System.out.println("Quitting...");
// Dismiss your dialog here.
}
}
public static void main(String[] args) throws Exception{
ShowDialog sd = new ShowDialog();
sd.start();
Thread.sleep(2000);
sd.dismiss();
}
You mentioned you didn't want to use AsyncTask, but I would still reconsider. (What are your reasons against it?)
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();
}