This has been driving me nuts and I cannot find an answer anywhere. A very simple spinner dialog, but the setMessage is not working, it's blank!
public class MainActivity extends FragmentActivity {
ProgressDialog loadingProgress;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
loadingProgress = new ProgressDialog(this);
loadingProgress.setIndeterminate(true);
loadingProgress.setMessage("Loading");
loadingProgress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
}
In AsyncTask I just show the ProgressDialog:
protected void onPreExecute() {
super.onPreExecute();
loadingProgress.show();
}
The result is this:
Blank, nothing... Doesn't matter if it's simulator or device... Any ideas why? Your help is appreciated.
I've tested your code and saw the "Loading" string is displayed very well.
Seeing that your screenshot has the space of textview, i think it will be the problem of text color or theme.
If setMessage works, you can detect in "Dump View Hierarchy for UI Automator" tool of device tab in Eclipse like following screenshot.
Here is the code I am using in my app. It works well -- a spinner with a message. The main differences between what you show and this are: 1) I'm using a DialogFragment; 2) I don't call setProgressStyle. Not sure which (if either) of these matter, but this code definitely is working for me.
public void showProgressDialog(int stringResId, boolean isCancelable) {
Bundle arguments = new Bundle();
arguments.putString(EXTRA_MESSAGE, getString(stringResId));
arguments.putBoolean(EXTRA_CANCELABLE, isCancelable);
DialogFragment fragment = new ProgressDialogFragment();
fragment.setArguments(arguments);
showDialog(fragment);
}
public static class ProgressDialogFragment extends DialogFragment {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Bundle arguments = getArguments();
String message = arguments.getString(EXTRA_MESSAGE, null);
boolean isCancelable = arguments.getBoolean(EXTRA_CANCELABLE, true);
ProgressDialog dialog = new ProgressDialog(getActivity());
dialog.setIndeterminate(true);
if (message != null) {
dialog.setMessage(message);
}
dialog.setCancelable(isCancelable);
dialog.setCanceledOnTouchOutside(isCancelable);
return dialog;
}
}
Related
I'm testing this on an Emulator with the Android O Developer Preview. On previous versions everything works fine.
I got a LoginFragment which shows a "Please Wait" progress dialog when the login is processing.
public class ProgressDialogHud extends DialogFragment {
private String messages;
public static ProgressDialogHud newInstance(String message) {
ProgressDialogHud dialog = new ProgressDialogHud();
// ...
return Dialog;
}
}
public class LoginFragment extends Fragment {
private DialogFragment mProgressDialog;
private void login() {
mProgressDialog = ProgressDialogHud.newInstance( "..." );
mProgressDialog.show( getActivity().getSupportFragmentManager(), "PROGRESS" );
}
private void onLoginFinished() {
mProgressDialog.dismiss(); // NullPointerException here because inside Fragment (DialogFragment extends Fragment) the FragmentManager is null
}
}
I did a litle debugging session and found that the DialogFragment uses 2 different FragmentManager for showing and hiding. On showing the fragment, the manager is not null, however it's null when it's hiding.
Here is the Stacktrace
Any ideas?
You were close to the answer already: good investigation.
Use getFragmentManager() instead of getActivity().getSupportFragmentManager() when showing the dialog.
I know that Google's Material Design guidelines don't recommend using a ProgressDialog, instead using another less intrusive way to display progress, but I need to use a ProgressDialog for a specific Activity of my app.
So, the thing is that I want to wrap a ProgressDialog inside a DialogFragment, and thus my code is as follows:
public class MaterialProgressDialogFragment extends DialogFragment {
private int total;
private MaterialDialog myDialog;
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return myDialog;
}
public void incrementProgress(int by) {
myDialog.incrementProgress(by);
}
public void setTotal(int total) {
this.total = total;
}
public void setUp(Context context) {
myDialog = new MaterialDialog.Builder(context)
.title("Progress")
.content("Processing...")
.progress(false, total, true)
.build();
}
}
Because what I want to build is a determinate ProgressDialog, I want to be able to update its progress throghout the life of my app. For this I have made a method called setProgress(progress), but myDialog is always null, as well as the value returned from getDialog().
What am I doing wrong?
Thank you
EDIT: I'm showing the dialog inside my fragment's onCreateActivity() method, like follows:
MaterialProgressDialogFragment dialogFragment = new MaterialProgressDialogFragment();
dialogFragment.setTotal(100);
dialogFragment.setUp(getActivity());
dialogFragment.show(getSupportFragmentManager(), "");
dialog.incrementProgress(50);
Everything works as expected until the last line, which causes the app to throw an exception.
It isn't totally clear what the variable dialog inside setProgress(int progress) method is. But if you mean getDialog() by that, it takes time to create dialog by dialog fragment, and between the dialogFragment.show(getSupportFragmentManager(), "") and onCreateDialog(Bundle savedInstanceState) callback there will be some time interval, during which getDialog() will return null.
EDIT:
Ok, now it is more clear. But by the code above, you're violating the fragment framework rules. You should create your dialog in onCreateDialog(Bundle savedInstanceState) method, because otherwise you'll have problems with lifecycle (for example, if you'll rotate your screen, the app will crash).
I suggest you to use something like that:
public class MaterialProgressDialogFragment extends DialogFragment {
public static final String TOTAL_KEY = "total";
public static ProgressDialogFragment newInstance(int total) {
Bundle args = new Bundle();
args.putInt(TOTAL_KEY, total);
ProgressDialogFragment pdf = new ProgressDialogFragment();
pdf.setArguments(args);
return pdf;
}
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
MaterialDialog myDialog = new MaterialDialog.Builder(context)
.title("Progress")
.content("Processing...")
.progress(false, getTotal(), true)
.build();
return myDialog;
}
public void incrementProgress(int by) {
if (getDialog()!=null)
((MaterialDialog)getDialog()).incrementProgress(by);
}
public int getTotal() {
return getArguments().getInt(TOTAL_KEY);
}
}
You should save total variable to arguments, because it will be destroyed on configuration change (for example screen rotation).
Then just create and show it by:
MaterialProgressDialogFragment dialogFragment = MaterialProgressDialogFragment.newInstance(100);
dialogFragment.show(getSupportFragmentManager(), "");
When you want to change your progress, call:
dialog.incrementProgress(50);
But remember, dialog won't be created immediately, so if you'll call this right after show(), it won't take effect, because getDialog() will return null. If you want to just test it, call it delayed:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
dialog.incrementProgress(50);
}
}, 200);
But anyway in real app you will change your progress from some background process.
It's pretty common for my app to show a progress or AlertDialog to the user. If the user puts the app into the background and then returns later, I want the Dialog to still be shown. Is there a way to make Android handle this? I'd like it to either not close the dialog, or if it does reopen it automatically when the Activity resumes.
So far it's looking like no. I haven't found a ton of results about this (most people run into issues with orientation change, which my app does not allow) but very few ask about going into the background. I have tried every permutation of DialogFragment and regular Dialog, but they all disappear when the home button is pressed and the app is opened from the task manager.
I don't even have any code to show because it's all in the testing phase of various examples online. I suspect I will have to manage this myself, by checking in onResume() if something should be shown. If this is the case I can live with it, but I'd like to know for sure.
First lets clear something, like you can see in the next images, your activity or fragment can be destroyed for many reasons, so you have to deal with what you want saving "the state of your dialog".
Now the code:
public class CustomProgressDialog extends Dialog {
private static final String SHOWING_PROGRESS_DIALOG = "showing_progress_dialog";
private static final String STRING_PROGRESS_DIALOG = "string_progress_dialog";
private static final String SHOWING_POP_UP_DIALOG = "showing_pop_up_dialog";
private static final String STRING_POP_UP_DIALOG = "string_pop_up_dialog";
public TextView textView;
public CustomProgressDialog(Context context) {
super(context, android.R.style.Theme_Translucent_NoTitleBar);
setContentView(R.layout.progress_layout);
setCancelable(false);
textView = (TextView) findViewById(R.id.progress_textView);
}
}
public class MasterActivity extends FragmentActivity {
private CustomProgressDialog progressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_master);
progressDialog = new CustomProgressDialog(this);
if (savedInstanceState != null) {
boolean showingDialog = savedInstanceState.getBoolean(SHOWING_PROGRESS_DIALOG);
if (showingDialog) {
String msg = savedInstanceState.getString(STRING_PROGRESS_DIALOG, getResources().getString(R.string.progress_default_text));
progressDialog.textView.setText(msg);
progressDialog.show();
}
boolean mShowing_PopUpdialog = savedInstanceState.getBoolean(SHOWING_POP_UP_DIALOG);
String temp_msg = savedInstanceState.getString(STRING_POP_UP_DIALOG, "");
if (mShowing_PopUpdialog)
showPopUpDialog(temp_msg);
}
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (progressDialog.isShowing()) {
outState.putBoolean(SHOWING_PROGRESS_DIALOG, true);
outState.putString(STRING_PROGRESS_DIALOG, progressDialog.textView.getText().toString());
}
if (alert != null && alert.isShowing()) {
outState.putBoolean(SHOWING_POP_UP_DIALOG, true);
outState.putString(STRING_POP_UP_DIALOG, mString_dialog);
}
}
}
Try this in your DialogFragment's onPause() do this
#Override
public void onPause() {
super.onPause();
getActivity().getSupportFragmentManager().beginTransaction()
.addToBackStack("mydialogfragment").commit();
Log.v("dialog", "dialog is going down");
}
Then in your Activity's onResume() you call the DialogFragment back to life
#Override
protected void onResume() {
super.onResume();
getSupportFragmentManager().popBackStack();
Log.v("activity", "onresume called - i am bringing back the dialog");
}
Why i think this might work is a DialogFragment is a Fragment, and a Fragment's lifecycle is controlled by the Parent Activity as user #0mach0 diagram shows, so all you do is you push it do the backstack and call it back. so it should work
Try showing the dialog using parentFragmentManager. Worked for my DialogFragment
.show(parentFragmentManager, "TAG")
I'm working on an Android project. I need to use Android 1.6 or above.
My project was working, but now it is showing me some warnings about Dialogs like
"The method dismissDialog(int) from the type Activity is deprecated"
"The method showDialog(int) from the type Activity is deprecated", etc.
So I want to "update" my project to solve these warnings.
I have read and made some test projects to learn about Fragments and DialogFragment.
I have created my own ProgressDialog and I want to use it on my real project, but I have some problems.
public class MyProgressDialog extends DialogFragment {
public MyProgressDialog(){
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Context context = getActivity();
ProgressDialog dialog = new ProgressDialog(context);
Resources resources = context.getResources();
String message = resources.getText(R.string.wait).toString();
dialog.setMessage(message);
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
return dialog;
}
}
Earlier in my project, I created the ProgressDialog and then, in onPrepareDialog() method, I called an AsyncTask to connect the server, downloaded the data, etc. Then in onPostExecute of the AsyncTask, I dismissed the ProgressDialog and started the new Activity. But now I can't do that because onPrepareDialog is deprecated.
Calling ActionAsyncTask on onPrepareDialog of Activy
#Override
protected void onPrepareDialog(int id, Dialog dialog) {
switch(id){
case Constants.PROGRESS_DIALOG:
new ActionAsyncTask().execute();
break;
}
}
onPostExecute of ActionAsyncTask
#Override
protected void onPostExecute(Integer result) {
dismissDialog(Constants.PROGRESS_DIALOG);
}
How can solve this? What is the right way to do this? I want to write the best code for this, the most efficient code.
Thanks.
I want to create a dialog with a string that I build at runtime. It looks like API level 8 allows you to call showDialog with a bundle, but I have to write an app that will run on the older OSs.
How do I create a dialog with something like a simple error string and make sure it doesn't die when I rotate the screen.
I realize if I override onCreateDialog, it will do it for me. The problem is, this just takes the int constant. I need to pass a string to it so it knows what to put in the dialog.
If I build my dialog myself and then call .show() on it, it won't live through a screen orientation change.
If you're targeting API Level <8, then it's sort of a pain.
Set the string message to a property on your Activity
Use onSaveInstanceState(Bundle) and onRestoreInstanceState(Bundle) to manage your property through configuration changes (such as re-orientation)
In onPrepareDialog(int, Dialog), set the message of the dialog to this property. If you don't set this in onPrepareDialog, it'll re-display the previous dialog (in case your message needs to change between dialogs.)
Code:
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Save dialog message
if(dialogMessage != null) {
outState.putString(STATE_KEY_DIALOG_MESSAGE, dialogMessage);
}
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Load dialog message
if(savedInstanceState.containsKey(STATE_KEY_DIALOG_MESSAGE)) {
dialogMessage = savedInstanceState.getString(STATE_KEY_DIALOG_MESSAGE);
}
}
/** onCreateDialog as normal **/
#Override
protected void onPrepareDialog(int id, Dialog dialog) {
super.onPrepareDialog(id, dialog);
switch(id) {
case DIALOG_MESSAGE:
// Decorate dialog appropriately
AlertDialog messageDialog = (AlertDialog) dialog;
messageDialog.setMessage(dialogMessage);
}
}
You could just pass the string in the constructor.
public class MyDialog extends Dialog {
public MyDialog(Context context, String msg) {
super(context);
TextView textView = new TextView(context);
textView.setText(msg);
setContentView(textView);
}
}