android-alertdialog custom - "android.view.WindowManager $ BadTokenException:غير قادر على إضافة إطار" على buider.show()




intent example (7)

كان لدي حوار يظهر الوظيفة:

void showDialog(){
    new AlertDialog.Builder(MyActivity.this)
    ...
    .show();
}

كنت أتلقى هذا الخطأ وكان عليّ فقط التحقق من isFinishing() قبل أن نطلق على هذا الحوار إظهار الوظيفة.

if(!isFinishing())
    showDialog();

من نشاطي الأساسي ، أحتاج إلى الاتصال بفصل داخلي وفي طريقة داخل الصف ، أحتاج إلى إظهار AlertDialg واستبعاده عند الضغط على زر OK وإرساله إلى Google Play للشراء.

الأشياء تعمل بشكل مثالي لمعظم الأوقات ، ولكن بالنسبة لعدد قليل من المستخدمين هو تحطمها على builder.show() وأستطيع أن أرى "android.view.WindowManager$BadTokenException: غير قادر على إضافة نافذة" من سجل التعطل. الرجاء الاقتراح.

رمز بلدي يشبه إلى حد كبير هذا:

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

لقد رأيت أيضًا الخطأ في تنبيه آخر حيث لا أعيد توجيه أي نشاط آخر. انها بسيطة مثل هذا:

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

  • أولاً لا يمكنك توسيع AsyncTask دون تجاوز doInBackground
  • محاولة ثانية لخلق AlterDailog من باني ثم استدعاء المعرض ().

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

مع هذه الفكرة المتغيرات globals ، أنقذت MainActivity على سبيل المثال في onCreate () ؛ المتغير العالمي Android

public class ApplicationController extends Application {

    public static MainActivity this_MainActivity;
}

وفتح الحوار مثل هذا. انها عملت.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Global Var
    globals = (ApplicationController) this.getApplication();
    globals.this_MainActivity = this;
}

وفي سلسلة محادثات ، أفتح حوارًا مثل هذا.

AlertDialog.Builder alert = new AlertDialog.Builder(globals.this_MainActivity);
  1. افتح MainActivity
  2. بدء موضوع.
  3. فتح الحوار من الموضوع -> العمل.
  4. انقر فوق "زر العودة" (سيتم استدعاء onCreate وإزالة MainActivity الأول)
  5. سوف تبدأ MainActivity جديدة. (وحفظ هذا المثال على globals)
  6. فتح الحوار من أول موضوع -> سوف تفتح وتعمل.

:)


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

المشكلة:

يحدث هذا الاستثناء عندما يحاول التطبيق إعلام المستخدم من مؤشر ترابط الخلفية (AsyncTask) عن طريق فتح مربع حوار.

إذا كنت تحاول تعديل واجهة المستخدم من مؤشر ترابط الخلفية (عادةً من onPostExecute () من AsyncTask) وإذا دخل النشاط في مرحلة الانتهاء (أي استدعاء النهاية الصريحة () ، قم بالضغط على زر "رجوع" أو زر "رجوع" المستخدم أو تنظيف النشاط الذي قام به Android ثم الحصول على هذا الخطأ.

السبب :

يرجع سبب هذا الاستثناء ، كما تقول رسالة الاستثناء ، إلى أن النشاط قد انتهى ولكنك تحاول عرض مربع حوار مع سياق للنشاط النهائي. نظرًا لعدم وجود نافذة لعرض مربع الحوار ، يعرض وقت تشغيل Android هذا الاستثناء.

حل:

استخدم طريقة isFinishing() التي يطلق عليها Android للتحقق من ما إذا كان هذا النشاط في مرحلة الإنهاء: سواء كان ذلك اتصالًا صريحًا بالإنهاء () أو نشاطًا للتنظيف يتم إجراؤه بواسطة Android. باستخدام هذا الأسلوب من السهل جداً تجنب فتح مربع حوار من مؤشر ترابط الخلفية عند الانتهاء من النشاط.

يجب أيضًا الحفاظ على weak reference للنشاط (وليس مرجعًا قويًا بحيث يمكن تدمير النشاط بمجرد عدم الحاجة) والتحقق مما إذا كان النشاط لا ينتهي قبل تنفيذ أي واجهة مستخدم باستخدام مرجع النشاط هذا (أي إظهار مربع حوار).

على سبيل المثال .

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 بإنشاء نوع خاص من رمز مميز يسمى رمز نافذة التطبيق ، والذي يعرّف بشكل فريد نافذة حاوية المستوى الأعلى للتطبيق. يعطي مدير النشاط هذا الرمز المميز لكل من التطبيق ومدير النوافذ ، ويقوم التطبيق بإرسال الرمز المميز إلى مدير النافذة في كل مرة تريد فيها إضافة نافذة جديدة إلى الشاشة. وهذا يضمن التفاعل الآمن بين التطبيق ومدير النوافذ (عن طريق جعله من المستحيل إضافة إطارات فوق التطبيقات الأخرى) ، ويسهّل أيضًا على مدير النشاط تقديم طلبات مباشرة إلى مدير النوافذ.


جرب هذا :

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

}
}

السبب المحتمل هو سياق مربع حوار التنبيه. قد تنتهي من هذا النشاط بحيث يحاول فتحه في هذا السياق ولكنه مغلق بالفعل. حاول تغيير سياق هذا الحوار إلى نشاطك الأول لأنه لا ينتهي حتى النهاية.

على سبيل المثال

بدلا من ذلك.

AlertDialog alertDialog = new AlertDialog.Builder(this).create();

حاول استخدام

AlertDialog alertDialog = new AlertDialog.Builder(FirstActivity.getInstance()).create();

إذا كنت تستخدم جزءًا وتستخدم رسالة AlertDialog / Toast ، فاستخدم getActivity () في معلمة السياق.

مثله

ProgressDialog pdialog;
pdialog = new ProgressDialog(getActivity());
pdialog.setCancelable(true);
pdialog.setMessage("Loading ....");
pdialog.show();






android android-alertdialog