Reputation: 4727
From my main activity
, I need to call an inner class and in a method within the class, I need to show AlertDialog
. After dismissing it, when the OK button is pressed, forward to Google Play for purchase.
Things work perfectly for most of the times, but for few users it is crashing on builder.show()
and I can see "android.view.WindowManager$BadTokenException:
Unable to add window" from crash log. Please suggest.
My code is pretty much like this:
public class classname1 extends Activity{
public void onCreate(Bundle savedInstanceState) {
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.<view>);
//call the <className1> class to execute
}
private class classNamename2 extends AsyncTask<String, Void, String>{
protected String doInBackground(String... params) {}
protected void onPostExecute(String result){
if(page.contains("error"))
{
AlertDialog.Builder builder = new AlertDialog.Builder(classname1.this);
builder.setCancelable(true);
builder.setMessage("");
builder.setInverseBackgroundForced(true);
builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton){
dialog.dismiss();
if(!<condition>)
{
try
{
String pl = "";
mHelper.<flow>(<class>.this, SKU, RC_REQUEST,
<listener>, pl);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
});
builder.show();
}
}
}
}
I have also seen the error in another alert where I am not forwarding to any other activity
. It's simple like this:
AlertDialog.Builder builder = new AlertDialog.Builder(classname1.this);
builder.setCancelable(true);
//if successful
builder.setMessage(" ");
builder.setInverseBackgroundForced(true);
builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton){
// dialog.dismiss();
}
});
builder.show();
}
Upvotes: 135
Views: 153380
Reputation: 5357
I've read this and a a whole range of other responses and could not solve it for my case; in the end I found that the problem in my case was that when creating the Builder I used a context retrieved through GetApplicationContext instead of the activity.
I know this is not the case here, but as this is the first and best thread on this exception I'm posing here in case it's useful to others
Upvotes: 0
Reputation: 11267
I got this error, but mine was coming from the Toasts, not a Dialog.
I have Activity and Fragments in my layout. Code for the Toast was in the Activity class. Fragments gets loaded before the Activity.
I think the Toast code was hit before the Context/Activity finished initializing. I think it was the getApplicationContext()
in the command Toast.makeText(getApplicationContext(), "onMenutItemActionCollapse called", Toast.LENGTH_SHORT).show();
Upvotes: 0
Reputation: 915
In my case I refactored code and put the creation of the Dialog in a separate class. I only handed over the clicked View because a View contains a context object already. This led to the same error message although all ran on the MainThread.
I then switched to handing over the Activity as well and used its context in the dialog creation -> Everything works now.
fun showDialogToDeletePhoto(baseActivity: BaseActivity, clickedParent: View, deletePhotoClickedListener: DeletePhotoClickedListener) {
val dialog = AlertDialog.Builder(baseActivity) // <-- here
.setTitle(baseActivity.getString(R.string.alert_delete_picture_dialog_title))
...
}
I , can't format the code snippet properly, sorry :(
Upvotes: 0
Reputation: 11
I try this it solved.
AlertDialog.Builder builder = new AlertDialog.Builder(
this);
builder.setCancelable(true);
builder.setTitle("Opss!!");
builder.setMessage("You Don't have anough coins to withdraw. ");
builder.setMessage("Please read the Withdraw rules.");
builder.setInverseBackgroundForced(true);
builder.setPositiveButton("OK",
(dialog, which) -> dialog.dismiss());
builder.create().show();
Upvotes: 1
Reputation: 801
with this globals variables idea, I saved MainActivity instance in onCreate(); Android global variable
public class ApplicationController extends Application {
public static MainActivity this_MainActivity;
}
and Open dialog like this. it worked.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Global Var
globals = (ApplicationController) this.getApplication();
globals.this_MainActivity = this;
}
and in a thread, I open dialog like this.
AlertDialog.Builder alert = new AlertDialog.Builder(globals.this_MainActivity);
: )
Upvotes: -3
Reputation: 2303
The possible reason is the context of the alert dialog. You may be finished that activity so its trying to open in that context but which is already closed. Try changing the context of that dialog to you first activity beacause it won't be finished till the end.
e.g
rather than this.
AlertDialog alertDialog = new AlertDialog.Builder(this).create();
try to use
AlertDialog alertDialog = new AlertDialog.Builder(FirstActivity.getInstance()).create();
Upvotes: 9
Reputation: 10038
I had dialog showing function:
void showDialog(){
new AlertDialog.Builder(MyActivity.this)
...
.show();
}
I was getting this error and i just had to check isFinishing()
before calling this dialog showing function.
if(!isFinishing())
showDialog();
Upvotes: 32
Reputation: 2484
Try this :
public class <class> extends Activity{
private AlertDialog.Builder builder;
public void onCreate(Bundle savedInstanceState) {
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.<view>);
builder = new AlertDialog.Builder(<class>.this);
builder.setCancelable(true);
builder.setMessage(<message>);
builder.setInverseBackgroundForced(true);
//call the <className> class to execute
}
private class <className> extends AsyncTask<String, Void, String>{
protected String doInBackground(String... params) {
}
protected void onPostExecute(String result){
if(page.contains("error")) //when not subscribed
{
if(builder!=null){
builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton){
dialog.dismiss();
if(!<condition>)
{
try
{
String pl = "";
mHelper.<flow>(<class>.this, SKU, RC_REQUEST,
<listener>, pl);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
});
builder.show();
}
}
}
}
Upvotes: -1
Reputation: 2230
second try to create AlterDailog from the builder then call show().
private boolean visible = false;
class chkSubscription extends AsyncTask<String, Void, String>
{
protected void onPostExecute(String result)
{
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setCancelable(true);
builder.setMessage(sucObject);
builder.setInverseBackgroundForced(true);
builder.setNeutralButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton)
{
dialog.dismiss();
}
});
AlertDialog myAlertDialog = builder.create();
if(visible) myAlertDialog.show();
}
@Override
protected String doInBackground(String... arg0)
{
// TODO Auto-generated method stub
return null;
}
}
@Override
protected void onResume()
{
// TODO Auto-generated method stub
super.onResume();
visible = true;
}
@Override
protected void onStop()
{
visible = false;
super.onStop();
}
Upvotes: 3
Reputation: 9574
I am creating Dialog in onCreate
and using it with show
and hide
. For me the root cause was not dismissing onBackPressed
, which was finishing the Home
activity.
@Override
public void onBackPressed() {
new AlertDialog.Builder(this)
.setTitle("Really Exit?")
.setMessage("Are you sure you want to exit?")
.setNegativeButton(android.R.string.no, null)
.setPositiveButton(android.R.string.yes,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
Home.this.finish();
return;
}
}).create().show();
I was finishing the Home Activity onBackPressed
without closing / dismissing my dialogs.
When I dismissed my dialogs the crash disappeared.
new AlertDialog.Builder(this)
.setTitle("Really Exit?")
.setMessage("Are you sure you want to exit?")
.setNegativeButton(android.R.string.no, null)
.setPositiveButton(android.R.string.yes,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
networkErrorDialog.dismiss() ;
homeLocationErrorDialog.dismiss() ;
currentLocationErrorDialog.dismiss() ;
Home.this.finish();
return;
}
}).create().show();
Upvotes: 1
Reputation: 16729
android.view.WindowManager$BadTokenException: Unable to add window"
Problem :
This exception occurs when the app is trying to notify the user from the background thread (AsyncTask) by opening a Dialog.
If you are trying to modify the UI from background thread (usually from onPostExecute() of AsyncTask) and if the activity enters finishing stage i.e.) explicitly calling finish(), user pressing home or back button or activity clean up made by Android then you get this error.
Reason :
The reason for this exception is that, as the exception message says, the activity has finished but you are trying to display a dialog with a context of the finished activity. Since there is no window for the dialog to display the android runtime throws this exception.
Solution:
Use
isFinishing()
method which is called by Android to check whether this activity is in the process of finishing: be it explicit finish() call or activity clean up made by Android. By using this method it is very easy to avoid opening dialog from background thread when activity is finishing.Also maintain a
weak reference
for the activity (and not a strong reference so that activity can be destroyed once not needed) and check if the activity is not finishing before performing any UI using this activity reference (i.e. showing a dialog).
eg.
private class chkSubscription extends AsyncTask<String, Void, String>{
private final WeakReference<login> loginActivityWeakRef;
public chkSubscription (login loginActivity) {
super();
this.loginActivityWeakRef= new WeakReference<login >(loginActivity)
}
protected String doInBackground(String... params) {
//web service call
}
protected void onPostExecute(String result) {
if(page.contains("error")) //when not subscribed
{
if (loginActivityWeakRef.get() != null && !loginActivityWeakRef.get().isFinishing()) {
AlertDialog.Builder builder = new AlertDialog.Builder(login.this);
builder.setCancelable(true);
builder.setMessage(sucObject);
builder.setInverseBackgroundForced(true);
builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton){
dialog.dismiss();
}
});
builder.show();
}
}
}
}
Update :
Window Tokens:
As its name implies, a window token is a special type of Binder token that the window manager uses to uniquely identify a window in the system. Window tokens are important for security because they make it impossible for malicious applications to draw on top of the windows of other applications. The window manager protects against this by requiring applications to pass their application's window token as part of each request to add or remove a window. If the tokens don't match, the window manager rejects the request and throws a BadTokenException. Without window tokens, this necessary identification step wouldn't be possible and the window manager wouldn't be able to protect itself from malicious applications.
A real-world scenario:
When an application starts up for the first time, the ActivityManagerService creates a special kind of window token called an application window token, which uniquely identifies the application's top-level container window. The activity manager gives this token to both the application and the window manager, and the application sends the token to the window manager each time it wants to add a new window to the screen. This ensures secure interaction between the application and the window manager (by making it impossible to add windows on top of other applications), and also makes it easy for the activity manager to make direct requests to the window manager.
Upvotes: 296