I am trying to build a class to go to the web, download data and then load it into a database. I have no problem doing this with a single progress dialog but can simply not figure out how to have multiple dialogs. In researching this, I found hundreds of Progress Dialog questions, so it does not seem as straight forward as it should be.
I have tried using handlers and threads but simply cannot ma
I am looking for an example of working code to accomplish this.
Here is the pseudo code that I am attempting:
public class myactivity extends Activity()
{
private WebIO webIO ; // web acess io
private DataIO DataIO ; // database io
public void onCreate( Bundle savedInstanceState ) {
DataIO = new DataIO( this );
WebIO = new WebIO();
DataIO.open();
runProgram();
}
}
private void runProgram() {
startProgressDialog( "Downloading data from web" );
new Thread() {
public void run() {
try{
String vData = webIO.getData();
dismissProgressDialog();
if ( vData.length() > 0 ) {
promptUser( vData );
} } } }
}
private void promptUser( vData ){
if alertdialog_to_prompt_user_to_load(){
{
loadData( pData )
}
private void loadData( String pData ){
startProgressDialog( "Loading data into database" );
new Thread() {
public void run() {
try{
loadDataIntoDatabase();
dismissProgressDialog();
} } } }
}
the only way to have multiple dialogs is to layer them on top of each other, which is an obvious user experience no-no. in android, dialogs are their own window, so there can only be one in focus at a time.
to solve your problem, create a custom dialog with multiple ProgressBar widgets. the simplest way to do that is to start with a DialogFragment and override onCreatedDialog() to return an AlertDialog with a custom view. to set a custom view on an alert dialog, see the setView() method on AlertDialog. e.g.,
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater li = LayoutInflater.from(context);
View layout = = li.inflate(R.layout.my_dialog);
return new AlertDialog.Builder(getActivity())
.setIcon(..)
.setTitle(...)
.setView(layout)
...
.create();
}
it'd be pretty neat to encapsulate all this into a multi-download progress dialog, where you could register additional downloads and have the class automatically add a progress bar and register itself for progress updates.
Related
I am developing my first Android App and I want to display progress dialog while user click on login button in my apps. so I integrated asynctask in apps, all operation like login logout successfully done but problem is that after successfully login this giving me error like LoginActivity has leaked window due to progress dialog. how to dismiss progress dialog and update the UI.
please refer following code and tell me some changes
following is the LoginActivity
public class LoginActivity extends SherlockActivity {
.................
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sessionmngr = new SessionManager(this);
//check the user login or not
if (sessionmngr.isLoggedIn()) {
Intent checkLoginIntnt = new Intent(this,ProjectFragActivity.class);
startActivity(checkLoginIntnt);
}
setContentView(R.layout.activity_login);
........
}
// onclick listener when click on login activity
public void LoginToBookingScape(View v) throws JSONException {
username = edtTxtUserName.getText().toString();
userpsw = edtTxtUserPsw.getText().toString();
if ((username.trim().length() > 0)&&(userpsw.trim().length() > 0)) {
JsonWebService jsonWebs = new JsonWebService();
jsonWebs.execute(loginUrl);
}else {
............
}
}
Following is the Inner class to extend AsyncTask in LoginActivity
private class JsonWebService extends AsyncTask<String,Void,String> {
private ProgressDialog dialogLogin;
#Override
protected String doInBackground(String... url) {
httpPost.setEntity(new UrlEncodedFormEntity(params));
....
inStream = httpEntity.getContent();
.........
return jsonResp;
}
#Override
protected void onPostExecute(String jsonData) {
//get string data from doinBackground
try {
JSONObject jsonObj = new JSONObject(jsonData);
String key_login = jsonObj.getString(KEY_LOGIN);
if (key_login.equalsIgnoreCase("0")) {
.............
}else {
....
sessionmngr = new SessionManager(getApplicationContext());
sessionmngr.createLoginSession(id,jsonObj.getString(KEY_UNAME),
jsonObj.getString(KEY_UEMAIL));
dialogLogin = ProgressDialog.show(LoginActivity.this, "Bookingscape",
"Please Wait",true);
dialogLogin.setIcon(R.drawable.icon);
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
Intent inteProj = new Intent(getApplicationContext(),
ProjectFragActivity.class);
startActivity(inteProj);
finish();
}
........
}
#Override
protected void onCancelled() {
dialogLogin.dismiss();
dialogLogin = null;
super.onCancelled();
}
}
}
I want ask one question here
Is above code optimize and reusable.
Thanks in advance
The problem is you are moving to new activity without dismissing the progress dialogue . this will cause leaked window error
I think you must move dialogLogin.dismiss(); form onCancelled()block to onPostExecute block in your code
you must do this before you are going to another activity . ie before
Intent inteProj = new Intent(getApplicationContext(),ProjectFragActivity.class);
startActivity(inteProj);
this line of code .I think this will solve your issue
one doubt : where is your onPreExecute ?? Usually i display progress code in that block and dismiss that in onPostExecute
Usually the flow is like this onPreExecute-->doInBackground --->onPostExecute
EDIT :
onPreExecute: Initialize your UI components (eg: Dialoges) .In your case ProgressDialog showed up
doInBackground : After onPreExecute block control goes to this block this will .Here the ProgressDialog continues it's work
onPostExecute : control come here after all background action .Here you can dismiss your ProgressDialog and goto your new activity.
Possibly Its Because of you are writing
Intent inteProj = new Intent(getApplicationContext(),
ProjectFragActivity.class);
startActivity(inteProj);
before dismissing dialog, means your dialog is still showing process even your activity changed. so just put your
dialogLogin.dismiss();
dialogLogin = null;
lines before this
Intent inteProj = new Intent(getApplicationContext(),
ProjectFragActivity.class);
startActivity(inteProj);
then this problem will get resolved.
I had this issue also and this is what caused it.
My app takes input and adds them to SQLite database. This is what I had:
public Item doInBackground(String...params) {
Item item = new Item();
try {
item.setItemName(params[0]);
item.setSupplierPhone(params[1]);
...
databaseHandler.addItem(item);
//Toast.makeText(mContext, "Item successfully saved.", Toast.LENGTH_SHORT).show();
databaseHandler.close();
} catch (SQLiteException e) {
Toast.makeText(mContext, "Error saving Item!", Toast.LENGTH_SHORT).show();
}
return item;
}
I think this was because I was trying to show a Dialog after execution path was already in onPostExecute()
It is also important to note that there are a lot of reasons why this exception is thrown.
A lot of them are discussed here
You need to dismiss the dialog before forwarding to next activity.
Use:-
dialog.dismiss();
I have this lines of code:
1) m_ProgressDialog = ProgressDialog.show(m_Context, "", m_Context.getString(R.string.dictionary_loading));
2) //important code stuff: interact with db, change some textview values (= 2-3 seconds if i'm unlucky)
3) m_ProgressDialog.dismiss();
But what happens is that phase 2) happens before 1).. which is wrong. First UI freezes then dialog appears..
phase 2) is some code that interacts with DB, might also change some textViews..but since this might take a while i decided to show that progress dialog so that user would know that really important stuff is going on. I cant use Async for these operations since UI code & db code is mengled, it will only complicate my life
How can i force dialog to show at request ??.. to me it seams that code presented just adds it in a "To do list when i have some free time & i dont have time now" stack..
You are doing your work on the ui thread. You should use a separate thread for this to keep the UI (progress bar) responsive. Have a look at AsynchTask.
Do not use UiThread for background operations it lead to freeze of screen.You have to use separate thread like Asyc Task.
do like below
in
onCreate()
{
dialog.show();
new DownloadFilesTask().excute()
}
class DownloadFilesTask extends AsyncTask<Void,Void,Void>
{
protected Long doInBackground(URL... urls) {
//Background operation
}
return null;
}
protected void onProgressUpdate(Integer... progress) {
}
protected void onPostExecute(Long result) {
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
//Update you Ui here
dialog.dismiss();
}
});
}
}
For most of cases if you want to simply have 2 methods, ShowLoading() and HideLoading() just use this
public static void ShowLoading()
{
HideLoading();
myLoadingThread = new Thread(new ThreadStart(LoadingThread));
myLoadingThread.Start();
}
private static void LoadingThread()
{
Looper.Prepare();
myProgressDialog = new ProgressDialog(myActivity,
Resource.Style.AppTheme_Dialog);
myProgressDialog.SetMessage("Loading..."); // Or a #string...
myProgressDialog.SetIcon(Resource.Drawable.your_loading_icon);
myProgressDialog.SetProgressStyle(ProgressDialogStyle.Spinner);
myProgressDialog.SetCancelable(false);
myProgressDialog.Show();
Looper.Loop();
}
public static void HideLoading()
{
if (myProgressDialog != null)
{
myProgressDialog.Dismiss();
myProgressDialog = null;
}
if (myLoadingThread != null)
myLoadingThread.Abort();
}
Now I declare and explain the followings variables I used on my code sample, one of them is global, yes, if you don't like to use global vars, or you want to have 2 loading dialogs at a time (wtf...) look for another solution. This is just the simplest way, most friendly and free of weird code with nested methods, new classes and inheritance everywhere for such a simple thing:
private Thread myLoadingThread;
private ProgressDialog myProgressDialog;
// Some people will hate me for this, but just remember
// to call myActivity = this; on each OnStart() of your app
// and end with all your headaches
public Activity myActivity;
I'm trying to implement the code from showing dialog while loading layout by setContentView in background and http://developer.android.com/guide/appendix/faq/commontasks.html#threading to show a loading dialog while my activity is loading, but having difficulty.
I have class variables defined for the UI elements in my view, and also strings for the data which is loaded on another thread from the database:
private TextView mLblName, mLblDescription, etc...
private String mData_RecipeName, mData_Description...
I also have the handlers defined:
private ProgressDialog dialog;
final Handler mHandler = new Handler();
final Runnable mShowRecipe = new Runnable() {
public void run() {
//setContentView(R.layout.recipe_view);
setTitle(mData_RecipeName);
mLblName.setText(mData_RecipeName);
mLblDescription.setText(mData_Description);
...
}
};
In onCreate, I'm trying too show the dialog, then spawn the loading thread:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dialog = ProgressDialog.show(this, "", "Loading. Please wait...", true);
setContentView(R.layout.recipe_view);
showData();
}
protected void showData() {
// Fire off a thread to do some work that we shouldn't do directly in the UI thread
Thread t = new Thread() {
public void run() {
mDatabaseAdapter = new ChickenPingDatabase(ShowRecipe.this);
mDatabaseAdapter.open();
mTabHost = getTabHost();
mLblName = (TextView)findViewById(R.id.lblName);
mLblDescription = (TextView)findViewById(R.id.lblDescription);
...
Cursor c = mDatabaseAdapter.getRecipeById(mRecipeId);
if(c != null){
mData_RecipeName= c.getString(c.getColumnIndex(Recipes.NAME));
mData_Description= c.getString(c.getColumnIndex(Recipes.DESCRIPTION));
...
c.close();
}
String[] categories = mDatabaseAdapter.getRecipeCategories(mRecipeId);
mData_CategoriesDesc = Utils.implode(categories, ",");
mHandler.post(mShowRecipe);
}
};
t.start();
}
This loads the data, but the progress dialog isn't shown. I've tried shuffling the call to spawn the separate thread and show the dialog around, but can't get the dialog to show. It seems this is a fairly common request, and this post seemed to be the only answered example of it.
EDIT: For reference, a blog post demonstrating the way I eventually got this working.
Since what you want is pretty much straight-forward, I would recommend that you use an AsyncTask. You can control the showing/hiding of the dialog in onPreExecute() and onPostExecute(). Check out the link, there's a good example in there.
I would like to implement a method that displays a dialog, waits until the dialog is dismissed, and then returns a result depending on the dialog contents. Is this possible?
public String getUserInput()
{
//do something to show dialog
String input = //get input from dialog
return input;
}
I am actually trying to implement an interface which has method "public String getUserInput()", where the returned String must be retrieved via dialog. This is easily done in java, seems impossible in android?
EDIT: Posting some sample code as requested in comment
getInput() must be called from a background thread (I call it from an AsynchTask). getInput() displays a dialog and calls wait. When the ok button is pressed on the dialog, the dialog sets the user input in a member variable and calls notify. When notify is called, getInput() continues and returns the member variable.
String m_Input;
public synchronized String getInput()
{
runOnUiThread(new Runnable()
{
#Override
public void run()
{
AlertDialog.Builder alert = new AlertDialog.Builder(context);
//customize alert dialog to allow desired input
alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton)
{
m_Input = alert.getCustomInput();
notify();
}
});
alert.show();
}
});
try
{
wait();
}
catch (InterruptedException e)
{
}
return m_Input;
}
Is this possible?
No. There is no blocking UI model in Android. Everything is asynchronous.
UPDATE
In response to some of your comments on the question itself, you cannot display a UI from a background thread. As I wrote in this answer, there is no blocking UI model in Android. Just put your code in the button handler for your dialog that you want to have executed when the dialog is accepted, such as in this sample project.
The right way to do this is an event driven program model, ie, "don't call us, we'll call you".
In simple console mode programming, your code tends to call blocking input functions, which don't return until you've gotten a value.
Many gui programming environments work differently - your code is not normally running, but instead it's called by the operating system / window manager when something of potential interest happens. You do something in response to this and promptly return - if you do not, you can't be notified of anything else since the OS has no way to contact you until you return. (In comparison to win32, it's as if the message loop is implemented by Android, and you only get to write the rest of the code that the message loop calls with events - if you don't return promptly, the message loop hangs)
As a result, you need to rethink your concept of program flow. Instead of writing out a to-do list as a simple series of statements, think about it as a sequence of actions which depend on each other and on input. Remember what action you are currently on in a state variable. When you get called with an event such as user input, see if that event means it's now possible to move on to the next step, and if so update your state variable before promptly returning to the OS in order to be able to receive the next event. If the event wasn't what you needed, then just return without updating your state.
If this model won't work for you, what you can do is write a background thread of program logic which runs like a console-mode application using blocking input. But your input functions will really just wait on a flag or something to be notified that input is available. Then on your UI thread where Android delivers events, you update the flag and promptly return. The background thread sees the flag has changed to indicate that data has been provided, and continues execution. (Something like an android terminal emulator takes this to an extreme, where the background component is actually another process - a console mode linux one, and it gets its input using potentially blocking I/O from pipes. The java component accepts android UI events and stuffs characters into the stdin pipe and pulls them out of the stdout pipe to display on the screen.)
Thanks for all the feedback, I was able to solve this using a background thread along with a wait() and notify(). I recognize this isn't the greatest idea for the given paradigm, but it was necessary to conform to a library that I am working with.
I had a hard time understanding all the solutions offered above so far so I found my own one.
I wrap the code thats supposed to be performed after the user input is OK'ed in a runnable, like so:
Runnable rOpenFile = new Runnable() {
#Override
public void run() {
.... code to perform
}
}
Then right below that I pass the name of the runnable function to the user dialog method.
userInput("Open File", rOpenFile);
The userInput method is based on the alertDialog builder like described above. When the user input is Ok'ed it starts the intended runnable.
private void userInput(String sTitle, final Runnable func) {
AlertDialog.Builder aBuilder = new AlertDialog.Builder(this);
aBuilder.setTitle(sTitle);
final EditText input = new EditText(this);
input.setInputType(InputType.TYPE_CLASS_TEXT);
aBuilder.setView(input);
bDialogDone = false;
aBuilder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
final String sText = input.getText().toString();
sEingabe = sText;
func.run();
}
});
aBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
sEingabe = "";
}
});
aBuilder.show();
}
Something like this would do
/**
*
*/
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
/**
* #author
*/
public class TextEntryActivity extends Activity {
private EditText et;
/*
* (non-Javadoc)
* #see android.app.Activity#onCreate(android.os.Bundle)
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_text_entry);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
// title
try {
String s = getIntent().getExtras().getString("title");
if (s.length() > 0) {
this.setTitle(s);
}
} catch (Exception e) {
}
// value
try {
et = ((EditText) findViewById(R.id.txtValue));
et.setText(getIntent().getExtras().getString("value"));
} catch (Exception e) {
}
// button
((Button) findViewById(R.id.btnDone)).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
executeDone();
}
});
}
/* (non-Javadoc)
* #see android.app.Activity#onBackPressed()
*/
#Override
public void onBackPressed() {
executeDone();
super.onBackPressed();
}
/**
*
*/
private void executeDone() {
Intent resultIntent = new Intent();
resultIntent.putExtra("value", TextEntryActivity.this.et.getText().toString());
setResult(Activity.RESULT_OK, resultIntent);
finish();
}
}
The launch is:
public void launchPreferedNameEdit() {
Intent foo = new Intent(this, TextEntryActivity.class);
foo.putExtra("value", objItem.getPreferedNickname());
this.startActivityForResult(foo, EDIT_PREFERED_NAME);
}
You get the result by using
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case EDIT_PREFERED_NAME:
try {
String value = data.getStringExtra("value");
if (value != null && value.length() > 0) {
}
} catch (Exception e) {
}
break;
default:
break;
}
}
CASE: My data was ready to be processes after a preference change listener event and I needed to add a String queried from user. It doesn't appear possible to pop an alert dialog while the options menu is open...so I had to wait. I threw the half complete object into the next activity in the workflow and set its onResume() to check if its placeholder was !null in which case I popped the dialog and finished up the object *"in the button handler of the dialog"*.
Since this is my first post I can't vote for the correct answer given above but want to save anyone else running into this the time and in-elegance of less correct solutions. The dialog is the place.
You can think in terms of a state machine where if you initially require first-time user input you can have a flag set to mark "user input needed" or whatever. Then upon processing an event you check that flag and if set you fire up a dialog as the only action for the event and unset the flag. Then from the dialog event handler after handling user input you can call the code normally intended for the case when a dialog is not needed.
For your reference, I just made a dialog.
It would show and wait then dismiss.
And I deploy Java wait and notify to make it, this function can be copied and run directly.
private final Object lock = new Lock();
private static final class Lock {}
private void showWaitDialog(final String message, final int time_to_wait) { //ms
if(this.isFinishing()) return;
final String TTAG = "[showWaitDialog]";
Log.d(TTAG, "dialog going to show");
final ProgressDialog waitProgress = ProgressDialog.show(this, "WARNING", message, true);
waitProgress.setCancelable(false);
waitProgress.setOnShowListener(new DialogInterface.OnShowListener() { //callback got the asynchronous
#Override
public void onShow(DialogInterface dialog) {
Log.d(TTAG, "dialog showed");
synchronized (lock) {
try {
Log.d(TTAG, "main thread going to wait");
lock.wait();
} catch (InterruptedException e) {
Log.e(TTAG, e.toString());
Log.e(TTAG, "main thread going ahead");
}
}
}
});
new Thread(new Runnable() {
#Override
public void run() {
synchronized (lock) {
try {
Thread.sleep(time_to_wait);
} catch (Exception e) {
Log.d(TTAG, e.toString());
}
lock.notifyAll();
Log.d(TTAG, "dialog notified");
waitProgress.dismiss();
}
}
}).start();
}
I'm trying to create a ProgressDialog for an Android-App (just a simple one showing the user that stuff is happening, no buttons or anything) but I can't get it right. I've been through forums and tutorials as well as the Sample-Code that comes with the SDK, but to no avail.
This is what I got:
btnSubmit.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
(...)
ProgressDialog pd = new ProgressDialog(MyApp.this);
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setMessage("Working...");
pd.setIndeterminate(true);
pd.setCancelable(false);
// now fetch the results
(...long time calculations here...)
// remove progress dialog
pd.dismiss();
I've also tried adding pd.show(); and messed around with the parameter in new ProgressDialog resulting in nothing at all (except errors that the chosen parameter won't work), meaning: the ProgressDialog won't ever show up. The app just keeps running as if I never added the dialog.
I don't know if I'm creating the dialog at the right place, I moved it around a bit but that, too, didnt't help. Maybe I'm in the wrong context? The above code is inside private ViewGroup _createInputForm() in MyApp.
Any hint is appreciated,
you have to call pd.show before the long calculation starts and then the calculation has to run in a separate thread. A soon as this thread is finished, you have to call pd.dismiss() to close the prgoress dialog.
here you can see an example:
the progressdialog is created and displayed and a thread is called to run a heavy calculation:
#Override
public void onClick(View v) {
pd = ProgressDialog.show(lexs, "Search", "Searching...", true, false);
Search search = new Search( ... );
SearchThread searchThread = new SearchThread(search);
searchThread.start();
}
and here the thread:
private class SearchThread extends Thread {
private Search search;
public SearchThread(Search search) {
this.search = search;
}
#Override
public void run() {
search.search();
handler.sendEmptyMessage(0);
}
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
displaySearchResults(search);
pd.dismiss();
}
};
}
I am giving you a solution for it,
try this...
First define the Progress Dialog in the Activity before onCreate() method
private ProgressDialog progressDialog;
Now in the onCreate method you might have the Any button click on which you will change the Activity on any action. Just set the Progress Bar there.
progressDialog = ProgressDialog.show(FoodDriveModule.this, "", "Loading...");
Now use thread to handle the Progress Bar to Display and hide
new Thread()
{
public void run()
{
try
{
sleep(1500);
// do the background process or any work that takes time to see progress dialog
}
catch (Exception e)
{
Log.e("tag",e.getMessage());
}
// dismiss the progress dialog
progressDialog.dismiss();
}
}.start();
That is all!
Progress Dialog doesn't show because you have to use a separated thread. The best practices in Android is to use AsyncTask ( highly recommended ).
See also this answer.
This is also possible by using AsyncTask. This class creates a thread for you. You should subclass it and fill in the doInBackground(...) method.