In my activity, I show a dialog under some condition like this:
public void showADialog(String title, String msg) {
if (mIsActivityRunning) {
new AlertDialog.Builder(this)
.show();
}
}
My question is what do I need to do to ensure there is no resource leak? From the logcat, i see there is a case where it said a window is leaking or something like that.
When the dialog box closes, how are you dismissing it? If you are using the hide() method, this won't actually dismiss the dialog.
EDIT: You need to dispose of the dialog box as the Activity is disposed of - see this question for more details
Related
I made a dialog with builder.setSingleChoiceItem with array of items that a user can choose from. But when a user adds something to that array, the list in that dialog is not updated, showing the previous list.
I read that you need to recreate the dialog in order to achieve this goal. How do you recreate it? How do you destroy the dialog and recreate its content all over again? so that you can refresh the list?
Thanks a lot for your answer in advance.
I found the answer
#Override
public void onPrepareDialog(int id, Dialog dialog)
{
switch(id)
{
//name of the case of the dialog you want to REFRESH -meaning destroy and recreate
case REMOVE_WATCH_WORD :
removeDialog(REMOVE_WATCH_WORD);
break;
}
}
I found a way to do this. In order to recreate your dialog every time in order to refresh everything, title, list, array, everything in the dialog, remove your dialog in onPrepareDialog. This will allow ALL the values to be reset, because onCreate dialog will be called again. This is the best, easy way solve this.
The custom dialog does dismiss at certain points in my program, for example when they press an "Edit" button, but the dialog will not dismiss if I select something from a list view and press an "Add" button. Both buttons end up using this same code below, but the if statements decide which will execute. Either way, the problem is that pcDialog.dismiss() is outside of the if statements, so it should dismiss always...but it doesn't.
Any ideas on what the problem might be? My dialog is declared outside of any methods as a member.
createDoneBtn.setOnClickListener(
new View.OnClickListener()
{
#Override
public void onClick(View v)
{
if ( !editingPC )
{
...
}
else if ( editingPC )
{
...
}
adapter.notifyDataSetChanged();
pcDialog.dismiss();
}
});
Maybe this one dismisses ok, but your code makes a second one to immediately appear?
Or maybe an exception is thrown but gets silently caught so you never step into dismiss() ?
Why not first debug?
And I think it's best practice to put it in try - catch - finally. Then you can call dismiss in the finally.
I've been poking around at this problem and I can't seem to figure it out. I have a simple app with a few normal views and a GL surface view, I make a few dialog boxes using onCreateDialog() and everything seems fine.
#Override
protected Dialog onCreateDialog(int id)
{
super.onCreateDialog(id);
Dialog m_Dialog = null;
// help dialog
if (id == HELP_DIALOG)
{
m_Dialog = new Dialog(this);
m_Dialog.setContentView(R.layout.help_dialog);
m_Dialog.setTitle("Instructions - Press BACK to close");
}
}
However if I use home to exit the app then go back into the app the dialogs no longer appear, however the screen dims as if the dialog was being displayed. I am getting the call to onPrepareDialog() even when the dialog does not show, I tried some things in there like calling show() off of the dialog. It gets a bit more strange, if I then switch to my GL surface view and back the dialogs work again. I am using a ViewAnimator to switch between my views. I am pretty sure I am handling the lifecycle correctly, over riding onPause() / onResume()
#Override
protected void onResume()
{
super.onResume();
m_Sensors.StartSensors();
m_GameThread.Pause(false);
glSurface.onResume();
}
As always, thanks for the help.
I haven't tried working with GL on android, but I have experienced some home button/re-open app weirdness myself recently - in my case it turned out to be connected to the issues below, which you might want to check out:
http://code.google.com/p/android/issues/detail?id=5277
http://code.google.com/p/android/issues/detail?id=2373
Hope it can help you get on the right track.
1) I launch a background task (via AsyncTask)
new FindJourneyTask().execute(); // FindJourneyTask extends AsyncTask
2) Still in the main thread (just before new thread is launched) I create a dialog with showDialog(dialogId)
// this method is in FindJourneyTask
protected void onPreExecute() {
showDialog(DIALOG_FINDING_JOURNEY);
}
3) Screen orientation changes and the Activity is recreated
4) How can I now dismiss the dialog from the FindJourneyTask? Calling dismissDialog(dialogId) does nothing.
// this method is in FindJourneyTask
protected void onPostExecute(FindJourneyResult result) {
dismissDialog(DIALOG_FINDING_JOURNEY); // does nothing
}
This is a common problem, and there are no real good solutions. The issue is that on screen orientation change, the entire Activity is destroyed and recreated. At the same time, the Dialog you previously had is re-created in the new Activity, but the old background task still refers to the old Activity when it tries to dismiss the dialog. The result is that it dismisses a dialog which was long ago destroyed, rather than dismissing the dialog the new orientation created.
There are three basic solutions:
Override the default orientation-handling code so that your Activity is not destroyed upon rotation. This is probably the least satisfactory answer, as it blocks a lot of code that is automatically run upon orientation changes.
Create a static member variable of your Activity that references the Activity itself, so you can call STATIC_ACTIVITY_VARIABLE.dismissDialog().
Code a solution in which the background task keeps track of the current Activity and updates itself as necessary.
These three solutions are discussed at length here: http://groups.google.com/group/android-developers/browse_thread/thread/bf046b95cf38832d/
There is a better solution to this problem now which involves using fragments.
If you create a dialog using DialogFragment, then this fragment will be responsible for maintaining your dialog's lifecycle. When you show a dialog, you supply a tag for your fragment (DialogFragment.show()). When you need to access your dialog, you just look for the necessary DialogFragment using FragmentManager.findFragmentByTag instead of having a reference to the dialog itself.
This way if device changes orientation, you will get a new fragment instead of the old one, and everything will work.
Here's some code based also in #peresisUser answer:
public void onSaveInstanceState(Bundle outState) {
AppCompatActivity activity = (AppCompatActivity) context;
FragmentManager fragmentManager = activity.getSupportFragmentManager();
DialogFragment dialogFragment = (DialogFragment) fragmentManager.findFragmentByTag("your_dialog_tag");
if(dialogFragment!=null) {
Dialog dialog = dialogFragment.getDialog();
if(dialog!=null && dialog.isShowing()) {
dialogFragment.dismiss();
}
}
}
This is long after the question was asked and answered, but i stumbled upon this problem also and wanted to share my solution...
I check in onSavedInstance() which runs on orientation change, whether the dialog is showing or not with dialog.isShowing(), and pass it into outState variable. Then in your onCreate(), you check this var if it's true. If it is, you simply dismiss your dialog with dialog.dismiss()
Hope this helps others :()
I tried adding setRetainInstance(true); on OnCreate function of DialogFragment. This will cause dialog to dismiss on rotation.
Just add this line to specific activity in your Manifest to solve this problem android:configChanges="orientation|screenSize|smallestScreenSize"
like this,
<activity
android:name=".PDFTools"
android:exported="false"
android:configChanges="orientation|screenSize|smallestScreenSize"
android:theme="#style/Theme.DocScanner.NoActionBar" />
In my activity, I'd like to show simple info dialogs, stuff like:
new AlertDialog.Builder(context).setMessage(message).show();
if I do that, the dialog will leak when I rotate that phone (not to mention it will disappear as well, so the user may miss it). I can use the managed dialogs, but I'm not sure how you use it sensibly for these types of short messages? Looks like you have to do this:
showDialog(SOME_DLG_ID);
...
#Override
onCreateDialog(int id) {
if (id == SOME_DLG_ID) {
new AlertDialog.Builder(context).setMessage(message).show();
}
}
there's no way to pass what the message should be into onCreateDialog since its an override method. I'd hate to make a member variable of the parent activity that just stores whatever the current message should be. How do you all do it?
Thanks
if I do that, the dialog will leak
when I rotate that phone (not to
mention it will disappear as well, so
the user may miss it)
You can add
<activity
android:configChanges="orientation|keyboardHidden"
>
to your AndroidManifest.xml to prevent restarting the activity when the phone rotates. I am using it in my app and my AlertDialog survives the rotation of phone.
You can implement Activity.onPrepareDialog(int, Dialog) to switch out the message before the dialog is shown on the screen. So you could do something like:
#Override protected void onPrepareDialog(int id, Dialog dialog) {
if (id == SOME_DLG_ID) {
((AlertDialog) dialog).setMessage(message);
}
}
You'd still have to keep track of the message you're current showing in your activity, but at least this way, you're not creating a Dialog object for each message you want to show.
Using DialogFragment to manage the dialog ensures that it correctly handles lifecycle events such as when the user rotates the screen or presses the Back button.