1. ホーム
  2. アンドロイド

[解決済み] "android.view.WindowManager$BadTokenException: Buider.show()で "Unable to add window "と表示される。

2022-03-04 10:44:23

質問

私のメインから activity インナークラスを呼び出し、クラス内のメソッドに AlertDialog . 解除後、OKボタンが押されたら、Google Playに転送して購入させる。

ほとんどの場合、正常に動作していますが、一部のユーザーでは、次のような場合にクラッシュします。 builder.show() と表示され "android.view.WindowManager$BadTokenException: クラッシュログからUnable to add window"と出ました。提案お願いします。

私のコードは大体こんな感じです。

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();
      }
    }
  }
}

また、他のアラートで、他のアラートに転送していない場合にも、このエラーが発生しました。 activity . こんな感じで簡単です。

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();
}

解決方法は?

android.view.WindowManager$BadTokenException: Unable to add window"

問題点 :

この例外は、アプリからユーザーに通知しようとしたときに発生します。 バックグラウンドスレッド(AsyncTask)でダイアログをオープンする。

バックグラウンドスレッドからUIを変更しようとしている場合(通常は AsyncTaskのonPostExecute()から)であり、アクティビティが 明示的にfinish()を呼び出したり、ユーザがホームボタンを押したりしている場合。 または戻るボタン、またはAndroidによって作られたアクティビティクリーンアップが表示されます。 というエラーが発生します。

理由:

この例外が発生した理由は、例外メッセージにあるように アクティビティは終了しているのに、ダイアログを表示しようとしている。 終了したアクティビティのコンテキスト ウィンドウがないため ダイアログを表示するために、アンドロイドランタイムはこの例外をスローします。

解決策

使用方法 isFinishing() メソッドは、Android から呼び出され このアクティビティは終了の過程にあります:明示的なfinish() の呼び出し、またはAndroidによって行われるアクティビティのクリーンアップ。このメソッドを使用することで バックグラウンドスレッドからダイアログを開かないようにするのは、非常に簡単です。 は終了します。

また weak reference アクティビティに対して(強力な を参照し、不要になったら破棄できるようにする。 を使用してUIを実行する前に、アクティビティが終了していないかどうかを確認します。 アクティビティ参照(ダイアログを表示する等)。

えー .

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();
      }
    }
  }
}

更新情報 :

ウィンドウズ・トークン

ウィンドウ・トークンは、その名の通り、特殊なバインダー・トークンです。 ウィンドウ マネージャがウィンドウを一意に識別するために使用するものです。 システムで使用されます。ウィンドウ・トークンはセキュリティ上重要です。 悪意のあるアプリケーションは、そのウィンドウの上に描画することはできません。 他のアプリケーション ウィンドウ マネージャは、次の方法でこれを防止します。 アプリケーションは、自分のアプリケーションのウィンドウ・トークンを ウィンドウを追加または削除するための各リクエストの一部です。トークンが一致しない場合 が一致した場合、ウィンドウマネージャはリクエストを拒否して BadTokenException . ウィンドウ・トークンがなければ、この必要な を識別することができず、ウィンドウ・マネージャーは 悪意のあるアプリケーションから自分自身を守ることができなくなります。

実戦的なシナリオ

あるアプリケーションが初めて起動するとき。 は  ActivityManagerService  は、特殊なウィンドウ・トークンを作成します。 アプリケーションウィンドウトークンと呼ばれるもので、一意的に アプリケーションのトップレベルのコンテナウィンドウです。 アクティビティマネージャは このトークンはアプリケーションとウィンドウマネージャの両方に渡され、アプリケーションは アプリケーションはこのトークンをウィンドウマネージャに送信します。 新しいウィンドウを画面に追加することができます。これにより アプリケーションとウィンドウ・マネージャの間で、( 他のアプリケーションの上にウィンドウを追加することは不可能であり、また アクティビティ・マネージャが直接要求することを容易にします。 ウィンドウマネージャ