showDialog() is accessing old View => Error: Activity has leaked window [...] - java

I am writing the app and I have the following scenario:
First i show an Acitivty and I show a ProgressDialog while loading data from a Server. I do the loading task in a Thread because I found this to be a solution so that the Dialog is shown correctly
showDialog(DIALOG_LOAD);
loadListThread = new Thread(new Runnable(){
#Override
public void run(){
service.execRequest();
loadingFinishedHandler.sendEmptyMessage(0);
MyActivity.this.dismissDialog(MyActivity.DIALOG_LOAD);
}
});
loadListThread.start();
After the Thread is finished I notify a Handler. Again this is a solution I found for the problem to access Views in the activity without being in the Thread anymore
loadingFinishedHandler = new Handler(){
#Override
public void handleMessage(Message msg){
showList();
}
};
After loading is finished, I check whether I received data correctly. If not, i want to show an error dialog:
showDialog(DIALOG_ERROR);
I call the dialogs with the onCreateDialog method
public Dialog onCreateDialog(int dialogId){
switch(dialogId){
case DIALOG_LOAD:
String message = getString(R.string.load);
ProgressDialog loadDialog = new ProgressDialog(this);
loadDialog.setMessage(message);
loadDialog.setCancelable(false);
return loadDialog;
case DIALOG_ERROR:
String message = getString(R.string.error);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(errorMessage);
builder.setNeutralButton(getString(R.string.ok), null);
return builder.create();
}
return null;
}
And here is the problem: If I change the Orientation of my phone while data is loading and an error dialog shall be created afterwards, I get this message
Activity [...] has leaked window [...] that was originally added here
I understand why this is happening. The View has been re-created, when i rotated my phone and showDialog() is obviously trying to access the old one. But I do not know how to fix it.
Does anyone has an idea?
Edit: solved it :-)
I found out that I can prevent my Activity from restarting on orientation change. I read about it in this article
Handling Runtime Changes
I declared in the AndroidManifest by adding
android:configChanges="orientation"
that i handle orientation changes by myself. These changes can now be handled with this method
public void onConfigurationChanged(Configuration newConfig){
super.onConfigurationChanged(newConfig);
}
But for my case it was not necessary to add any code!

public Dialog onCreateDialog(int dialogId){
if(isFinishing()){
return null;)}...

Related

How to start and stop progressbar in android?

I have an activity that calls a second java class. I want after the second class is called to show a progressbar and then return to normal activity execution. I found some other threads but i couldn't make the progressbar to stop.
There's a full example over here.
Quote:
Declare your progress dialog:
ProgressDialog progress;
When you're ready to start the progress dialog:
progress = ProgressDialog.show(this, "dialog title",
"dialog message", true);
and to make it go away when you're done:
progress.dismiss();
Here's a little thread example for you:
// Note: declare ProgressDialog progress as a field in your class.
progress = ProgressDialog.show(this, "dialog title",
"dialog message", true);
new Thread(new Runnable() {
#Override
public void run()
{
// do the thing that takes a long time
runOnUiThread(new Runnable() {
#Override
public void run()
{
progress.dismiss();
}
});
}
}).start();
ProgressDialog is deprecated, so you might want to use a ProgressBar.
I've found this post about deleting one of them.
Well, I think this is rather ridiculous, but here is how I fixed it.
In my xml for the ProgressBar, I added android:visibility="gone"
to hide it by default. Then, in my code, I first told it to display
(View.VISIBLE) before it tried getting the server list, then I told
it to hide (View.GONE) after it was done. This worked (I could see
the progress indicator while the data loaded, then it went away). So
I suppose I couldn't get it to hide in the code because the code is
not what forced it to be visible to begin with... That seems like a
bug to me.
Its very Simple:
to show a Progress
ProgressDialog dialog = ProgressDialog.show(getContext(), "Title", "Message");
and to stop it:
dialog.dismiss();

Android View onResume method?

When returning to an activity using the back button and
startActivity(new Intent(this, ActivityMainMenu.class));
is called, are there any methods that automatically go to a custom view?
I've noticed that when going back to the view, it's no longer invalidated.
Basically without using the activity's onResume I want to be able to resume my custom view.
For anyone else who wants to know you can use:
protected void onAttachedToWindow()
It's called every time a view is attached to the Window.
In the Android Source for TextView, it posts a Runnable.
if (ss.error != null) {
final CharSequence error = ss.error;
// Display the error later, after the first layout pass
post(new Runnable() {
public void run() {
setError(error);
}
});
}

Check if dialog can be safely dismissed

In my app, I am showing a dialog during a long-running background process which is modal.
This dialog is dismissed when android returns from the background task.
final ProgressDialog progressDialog = ProgressDialog.show(activity, "", "Doing something long running", true, true);
new Thread(new Runnable() {
public void run() {
someLongRunningCode(); // (not using AsyncTask!)
activity.runOnUiThread(new Runnable() {
public void run() {
progressDialog.dismiss();
}
});
}
}).start();
Now, however, when the user rotates his device while the background process is still running the activity is recreated and thus, the progressdialog gets detached from the activity.
When the long running process is done, android obviously tries to hide the (now detached) progress dialog which then results in an exception: java.lang.IllegalArgumentException: View not attached to window manager.
Is there any way to check if it is safe to dismiss the dialog?
Edit: Or better still, is there any way to attach the existing dialog to the newly created activity?
A new, cloned dialog would be fine aswell.
Just catch the exception and ignore it. Android's decision to restart the activity on rotation makes threads have a few odd exceptions like that. But the end result you want is no dialog box displayed. If you just catch the exception, no dialog box is displayed. So you're good.
If you aren't using a separate layout/drawables for landscape and portrait, you can just override configChange in your manifest for the activity so it doesn't destroy the activity (it will still correctly rotate and resize everything for you). That way the same dialog will be up and you shouldn't get the exception. The other option would require a lot of work around onSaveInstanceState and onRestoreInstanceState, and you'd need to be very careful of timing issues if the thread actually finishes during that time. The whole recreate activity on rotation idea doesn't work well with multithreading.
if (progressDialog != null) {
progressDialog.dismiss();
}
I've faced this issue before and solved using the below code.
private boolean isDialogViewAttachedToWindowManager() {
if (dialog.getWindow() == null) return false;
View decorView = progressDialog.getWindow().getDecorView();
return decorView != null && decorView.getParent() != null;
}

Using a progressdialog and handler

I'm working on an app that connect to a webpage to get some content. I want to show a progressdialog, but I think I'm doing something wrong.
This is my code:
final ProgressDialog myProgressDialog = ProgressDialog.show(WhoisBeyondActivity.this, "Wait...", "Fetching data...", true);
Handler handler=new Handler();
handler.post(new Runnable()
{
public void run()
{
try {
// code to execute
Thread.sleep(2000);
} catch (Exception e) {
}
myProgressDialog.dismiss();
}
});
The problem is that the progressdialog is only shown one second at the end of the operation I want to make. I think the progressdialog is only executing when I execute the dismiss() because it appears and dissapears quickly. Is like the progressdialog appears only to dissapear ... help me please!!! I have read a lot of tutorials, and I have try a lot of option, like THREAD instead of HANDLER, but it is not usefull for me, because I have to edit UI.
There's an excellent example and tutorial here:
http://www.helloandroid.com/tutorials/using-threads-and-progressdialog
That's what I used the first time I did a threaded dialog in Android, and I bookmarked it. Hopefully it helps.
The reason you are getting the described behaviour is that the post method will just execute the passed in runnable against the thread to which the Handler is attached. In your case this is the UI thread.
You are calling ProgressDialog.show(), which is asynchronous. This does not actually show the dialog as soon as the method returns, rather you have just requested that the UI display a dialog. You then immediately post a thread that sleeps for 2 seconds, which is added to the UI queue and blocks the UI from performing the dialog show. The UI then wakes from your sleep, shows the dialog then is dismissed.
You should perform any network operation in either a new Thread or in an AsyncTask. Have a look at these links for more details:
AsyncTask
Painless threading
Threading
Designing for responsiveness
Thread documentation
Handler documentation
You don't want to use a separate thread per-say. What you really want is an AsynTask. This will allow you to create the progress dialog and do the background processing right there in the task. Simple to write and easier to implement. If your refer to the link, what you need is actually really similar to your question. With a little tweaking, it should work just fine for you.
public class HelloActivity extends Activity {
protected static final String TAG = "HelloActivity";
ProgressDialog myProgressDialog;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//
showDialog(1);
final Handler handler=new Handler(){
#Override
public void handleMessage(Message msg) {
//update UI here depending on what message is received.
switch(msg.what){
case 0:
myProgressDialog.dismiss();
}
super.handleMessage(msg);
}
};
Thread t = new Thread(){
public void run(){
try {
// code to execute
Thread.sleep(5000);
} catch (Exception e) {
}
handler.sendEmptyMessage(0);//nothing to send
}
};
t.start();
}
#Override
protected Dialog onCreateDialog(int id) {
myProgressDialog = ProgressDialog.show(HelloActivity.this, "Wait...", "Fetching data...", true);
return myProgressDialog;
}
}

PopUp dialog Android from background thread

I need a popup dialog to be shown when i get a message from different thread but the dialog should be not dependent on Activity i.e, it should display the dialog wherever the screen focus is.
Can it be done? Because the dialog is handled per Activity, I thought of using a service but again it would be one more thread added and I want to avoid that.
Any other options available?
If you're trying to ask how to show a dialog when your activity is not the focused activity on the user's phone then try using Notifications instead. Popping up a dialog over a different application interrupts the user when they may be doing something else. From the Android UI guidelines:
Use the notification system — don't
use dialog boxes in place of
notifications
If your background service needs to
notify a user, use the standard
notification system — don't use a
dialog or toast to notify them. A
dialog or toast would immediately take
focus and interrupt the user, taking
focus away from what they were doing:
the user could be in the middle of
typing text the moment the dialog
appears and could accidentally act on
the dialog. Users are used to dealing
with notifications and can pull down
the notification shade at their
convenience to respond to your
message.
A guide to create notifications is here: http://developer.android.com/guide/topics/ui/notifiers/notifications.html
Alternative solution :
AlertDialog dialog;
//add this to your code
dialog = builder.create();
Window window = dialog.getWindow();
WindowManager.LayoutParams lp = window.getAttributes();
lp.token = mInputView.getWindowToken();
lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
window.setAttributes(lp);
window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
//end addons
alert.show();
if I understand you correctly you could use a base class for all of your activities
public abstract class BaseActivity extends Activity{
protected static BaseActivity current_context = null;
#override
protected void onPause(){
current_context = null;
super.onPause();
}
#override
protected void onResume(){
current_context = this;
super.onResume();
}
public static void showDialog(/*your parameters*/){
//show nothing, if no activity has focus
if(current_context == null)return;
current_context.runOnUiThread(new Runnable() {
#override
public void run(){
AlertDialog.Builder builder =
new AlertDialog.Builder(current_context);
//your dialog initialization
builder.show();
}
});
}
}
in your thread show your dialog with BaseActivity.showDialog(..) But this approach doesn't work if you want to show your dialog on top of any activity of the target device.

Categories