java.lang.IllegalArgumentException: ดูไม่แนบกับตัวจัดการหน้าต่าง


148

ฉันมีกิจกรรมที่เริ่มต้น AsyncTask และแสดงกล่องโต้ตอบความคืบหน้าในช่วงระยะเวลาของการดำเนินการ กิจกรรมถูกประกาศว่าไม่ถูกสร้างขึ้นใหม่โดยการหมุนหรือการสไลด์คีย์บอร์ด

    <activity android:name=".MyActivity" 
              android:label="@string/app_name"
              android:configChanges="keyboardHidden|orientation"
              >
        <intent-filter>
        </intent-filter>
    </activity>

เมื่องานเสร็จสิ้นฉันจะยกเลิกการโต้ตอบ แต่ในโทรศัพท์บางรุ่น (กรอบงาน: 1.5, 1.6) ข้อผิดพลาดดังกล่าวถูกโยน:

java.lang.IllegalArgumentException: View not attached to window manager
    at android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java:356)
    at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:201)
    at android.view.Window$LocalWindowManager.removeView(Window.java:400)
    at android.app.Dialog.dismissDialog(Dialog.java:268)
    at android.app.Dialog.access$000(Dialog.java:69)
    at android.app.Dialog$1.run(Dialog.java:103)
    at android.app.Dialog.dismiss(Dialog.java:252)
    at xxx.onPostExecute(xxx$1.java:xxx)

รหัสของฉันคือ:

final Dialog dialog = new AlertDialog.Builder(context)
    .setTitle("Processing...")
    .setCancelable(true)
    .create();

final AsyncTask<MyParams, Object, MyResult> task = new AsyncTask<MyParams, Object, MyResult>() {

    @Override
    protected MyResult doInBackground(MyParams... params) {
        // Long operation goes here
    }

    @Override
    protected void onPostExecute(MyResult result) {
        dialog.dismiss();
        onCompletion(result);
    }
};

task.execute(...);

dialog.setOnCancelListener(new OnCancelListener() {
    @Override
    public void onCancel(DialogInterface arg0) {
        task.cancel(false);
    }
});

dialog.show();

จากสิ่งที่ฉันได้อ่าน ( http://bend-ing.blogspot.com/2008/11/properly-handle-progress-dialog-in.html ) และเห็นในแหล่ง Android ดูเหมือนว่าสถานการณ์ที่เป็นไปได้เท่านั้นที่จะได้รับสิ่งนั้น ข้อยกเว้นคือเมื่อกิจกรรมถูกทำลาย แต่ดังที่ฉันได้กล่าวฉันห้ามกิจกรรมสันทนาการสำหรับกิจกรรมพื้นฐาน

ดังนั้นข้อเสนอแนะใด ๆ ที่มีความนิยมมาก


1
คำถามนี้มีคำตอบมากมายถ้ามีใครช่วยคุณโปรดเลือกเป็นคำตอบที่ถูกต้อง
Parag Kadam

คำตอบ:


228

ฉันได้รับข้อผิดพลาดนี้เช่นกันในบางครั้งเมื่อฉันปิดกล่องโต้ตอบและทำกิจกรรมจากเมธอด onPostExecute ฉันเดาว่าบางครั้งกิจกรรมจะเสร็จสิ้นก่อนที่กล่องโต้ตอบจะยกเลิกได้สำเร็จ

โซลูชันที่เรียบง่ายและมีประสิทธิภาพที่เหมาะกับฉัน

@Override
protected void onPostExecute(MyResult result) {
    try {
        if ((this.mDialog != null) && this.mDialog.isShowing()) {
            this.mDialog.dismiss();
        }
    } catch (final IllegalArgumentException e) {
        // Handle or log or ignore
    } catch (final Exception e) {
        // Handle or log or ignore
    } finally {
        this.mDialog = null;
    }  
}

44
วิธีง่ายๆ ใช่. ที่มีประสิทธิภาพ? บางทีในกรณีนี้ ฉันจะแนะนำไหม NO! อย่ากลืนข้อยกเว้นทั้งหมดแบบนั้น! ฉันจะไม่ได้จับ IllegalArgumentException แต่หาวิธีอื่น
Simon Forsberg

6
เพราะโดยทั่วไปแล้วการลองจับที่ว่างเปล่าเป็นความคิดที่ไม่ดี ... แม้ว่าบางครั้งมันอาจเป็นสิ่งที่ถูกต้องก็ตาม
Thomas

3
@Damjan จากการตอบกลับของคุณคุณแนะนำให้จับยกเว้นประเภท นี่เป็นข้อปฏิบัติที่ไม่ดีของ Google คุณสามารถอ่านได้ที่นี่: อย่าจับข้อยกเว้นทั่วไป
Yaniv

17
ฉันเชื่อว่านี่เป็นการแก้ไขที่มีประสิทธิภาพ ในกรณีทั่วไปเราไม่ควรทำเช่นนี้ แต่เนื่องจาก Android Framework ไม่ได้ให้การตรวจสอบที่ง่ายสำหรับเราเราจึงต้องใช้วิธีที่ผิดปกติ นอกจากนี้หากการเรียก isShowing () ของไดอะล็อกทำงานได้ตามที่เราคาดหวังเราไม่จำเป็นต้องแฮ็คประเภทนี้
SXC

1
แก้ไขอย่างรวดเร็วจนกระทั่งพบสิ่งที่ดีกว่า
Rohit Tigga

13

นี่คือโซลูชัน "bullet Proof" ของฉันซึ่งรวบรวมคำตอบที่ดีทั้งหมดที่ฉันพบในหัวข้อนี้ (ขอบคุณ @Damjan และ @Kachi) ข้อยกเว้นนี้จะถูกกลืนก็ต่อเมื่อวิธีการตรวจจับอื่น ๆ ทั้งหมดไม่ประสบความสำเร็จ ในกรณีของฉันฉันจำเป็นต้องปิดกล่องโต้ตอบโดยอัตโนมัติและนี่เป็นวิธีเดียวที่จะปกป้องแอพจากความผิดพลาด ฉันหวังว่ามันจะช่วยคุณ! กรุณาลงคะแนนและแสดงความคิดเห็นหากคุณมีข้อสังเกตหรือทางออกที่ดีกว่า ขอบคุณ!

public void dismissWithCheck(Dialog dialog) {
        if (dialog != null) {
            if (dialog.isShowing()) {

                //get the Context object that was used to great the dialog
                Context context = ((ContextWrapper) dialog.getContext()).getBaseContext();

                // if the Context used here was an activity AND it hasn't been finished or destroyed
                // then dismiss it
                if (context instanceof Activity) {

                    // Api >=17
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                        if (!((Activity) context).isFinishing() && !((Activity) context).isDestroyed()) {
                            dismissWithTryCatch(dialog);
                        }
                    } else {

                        // Api < 17. Unfortunately cannot check for isDestroyed()
                        if (!((Activity) context).isFinishing()) {
                            dismissWithTryCatch(dialog);
                        }
                    }
                } else
                    // if the Context used wasn't an Activity, then dismiss it too
                    dismissWithTryCatch(dialog);
            }
            dialog = null;
        }
    }

    public void dismissWithTryCatch(Dialog dialog) {
        try {
            dialog.dismiss();
        } catch (final IllegalArgumentException e) {
            // Do nothing.
        } catch (final Exception e) {
            // Do nothing.
        } finally {
            dialog = null;
        }
    }

1
ทางออกที่ดีมาก! การตั้งค่าdialog = nullไม่มีผลใด ๆ และควรอ่านเพียงแค่StatusEventDialog Dialog
hgoebl

1
StatusEventDialog ควรเปลี่ยนเป็นไดอะล็อก
Sreekanth Karumanaghat

คำตอบนี้ควรเป็นคำตอบที่ได้รับการยอมรับเป็นอย่างดี
blueware

ฉันเข้าใจว่าคุณต้องการที่จะ "ถูกต้อง" และใช้ลอง / จับในกรณีที่isDestroyed()ไม่พร้อมใช้งาน แต่สำหรับวัตถุประสงค์ในทางปฏิบัติมันจะไม่เหมือนกันถ้าใช้ลอง / จับเสมอ?
zundi

11

ฉันอาจมีวิธีแก้ปัญหา

ก็มีปัญหาเดียวกันที่ผมโหลดจำนวนมากของรายการ (ผ่านระบบแฟ้ม) ลงผ่านListView AsyncTaskมีonPreExecute()การยิงขึ้นProgressDialogและจากนั้นทั้งสองonPostExecute()และonCancelled()(เรียกว่าเมื่องานถูกยกเลิกอย่างชัดแจ้งผ่านAsyncTask.cancel()) .cancel()ปิดมันผ่าน

พบข้อผิดพลาด "java.lang.IllegalArgumentException: ดูไม่ได้แนบกับตัวจัดการหน้าต่าง" เมื่อฉันฆ่ากล่องโต้ตอบในonCancelled()วิธีการของAsyncTask(ฉันเห็นสิ่งนี้ทำในแอปชั้นวางที่ยอดเยี่ยม)

วิธีแก้ปัญหาคือการสร้างเขตข้อมูลสาธารณะในAsyncTaskที่มีProgressDialog:

public ProgressDialog mDialog;

จากนั้นonDestroy()เมื่อฉันยกเลิกAsyncTaskฉันสามารถฆ่าข้อความโต้ตอบที่เกี่ยวข้องผ่านทาง:

AsyncTask.mDialog.cancel();

การเรียกAsyncTask.cancel()ใช้ทริกเกอร์onCancelled()ในAsyncTaskแต่ด้วยเหตุผลบางอย่างตามเวลาที่เรียกว่าวิธีการมุมมองได้ถูกทำลายไปแล้วและการยกเลิกการโต้ตอบจะล้มเหลว


ฉันพบว่าการติดตั้ง UserTask นั้นยอดเยี่ยมมากตามที่ @Paul พูดถึง ซอร์สโค้ดอยู่ที่นี่: code.google.com/p/shelves/source/browse/trunk/Shelves/src/org/…
Evi Song

ในขณะที่กรณีการใช้งานสามารถพบได้ในโครงการเดียวกัน: code.google.com/p/shelves/source/browse/trunk/Shelves/src/org/…
Evi Song

9

นี่คือทางออกที่ถูกต้องในการแก้ปัญหานี้:

public void hideProgress() {
    if(mProgressDialog != null) {
        if(mProgressDialog.isShowing()) { //check if dialog is showing.

            //get the Context object that was used to great the dialog
            Context context = ((ContextWrapper)mProgressDialog.getContext()).getBaseContext();

            //if the Context used here was an activity AND it hasn't been finished or destroyed
            //then dismiss it
            if(context instanceof Activity) { 
                if(!((Activity)context).isFinishing() && !((Activity)context).isDestroyed()) 
                    mProgressDialog.dismiss();
            } else //if the Context used wasnt an Activity, then dismiss it too
                mProgressDialog.dismiss();
        }
        mProgressDialog = null;
    }
}

แทนที่จะจับข้อยกเว้นทั้งหมดสุ่มสี่สุ่มห้าโซลูชันนี้เน้นที่รากของปัญหา: พยายามลดระดับไดอะล็อกเมื่อกิจกรรมที่ใช้ในการเริ่มต้นไดอะล็อกเสร็จสิ้นแล้ว ทำงานกับ Nexus 4 ที่กำลังใช้งาน KitKat แต่ควรใช้ได้กับ Android ทุกรุ่น


3
isDestroyedต้องใช้ API 17+
Androiderson

ทำไมคุณต้องตั้งค่า mProgressDialog เป็น null? เกี่ยวข้องกับหน่วยความจำรั่วหรือไม่? คุณช่วยอธิบายได้มั้ย
Pawan

@Pawan มันเป็นรายละเอียดการดำเนินการในตอนท้ายของฉัน ไม่ต้องการมันเป็นเพียงวิธีการใช้งานฟังก์ชั่นในชั้นเรียนนี้ หลังจากกล่องโต้ตอบความคืบหน้าถูกซ่อนฉันจะตั้งค่าเป็นโมฆะ เมื่อผู้ใช้ต้องการที่จะแสดงกล่องโต้ตอบความคืบหน้าอื่นอินสแตนซ์ใหม่จะถูกยกตัวอย่าง
Kachi

แน่นอน! ((กิจกรรม) บริบท) ต้องใช้. () ขอขอบคุณ! :)
Daniel Krzyczkowski

5

ฉันเห็นด้วยกับความคิดเห็นของ 'Damjan'
หากคุณใช้กล่องโต้ตอบหลายกล่องควรปิดกล่องโต้ตอบทั้งหมดใน onDestroy () หรือ onStop ()
จากนั้นคุณอาจสามารถลดข้อยกเว้น 'java.lang.IllegalArgumentException: ข้อยกเว้นมุมมองไม่ได้แนบกับตัวจัดการหน้าต่าง' เกิดขึ้น

@Override
protected void onDestroy() {
    Log.d(TAG, "called onDestroy");
    mDialog.dismiss();
    super.onDestroy();
}



แต่เกินเล็กน้อย ...
เพื่อให้ชัดเจนยิ่งขึ้นคุณป้องกันไม่ให้แสดงข้อความโต้ตอบหลังจากเรียกเดสรอย
ฉันไม่ได้ใช้ดังต่อไปนี้ แต่มันชัดเจน

private boolean mIsDestroyed = false;

private void showDialog() {
    closeDialog();

    if (mIsDestroyed) {
        Log.d(TAG, "called onDestroy() already.");
        return;
    }

    mDialog = new AlertDialog(this)
        .setTitle("title")
        .setMessage("This is DialogTest")
        .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        })
        .create();
    mDialog.show();
}

private void closeDialog() {
    if (mDialog != null) {
        mDialog.dismiss();
    }
}

@Override
protected void onDestroy() {
    Log.d(TAG, "called onDestroy");
    mIsDestroyed = true;
    closeDialog();
    super.onDestroy();
}


โชคดี!


ฉันจะชอบหลีกเลี่ยงบล็อก catch ที่ว่างอยู่เสมอ ควรลองดู แต่เนื่องจากข้อผิดพลาดนี้ยากที่จะผลิต - มีเพียงครั้งเดียวเท่านั้นที่จะบอกได้ว่ามันใช้งานได้จริง ขอบคุณอยู่ดี
Dror Fichman

บล็อก catch ว่างเปล่าคืออะไร ฉันไม่ใช้ลอง / จับ ตัวแปร mIsDestroyed ทำงานเกิน แต่ถ้าคุณเขียนโค้ดที่ไดอะล็อกแสดงหลังจากที่ทำงานในเธรดอื่นคุณอาจต้องการตัวแปรนี้ เมื่อเธรดอื่นทำงานถ้ากิจกรรมเสร็จสิ้นคุณสามารถดูข้อยกเว้นนี้ได้
Hogun

ฉันมีปัญหาเดียวกันและเมื่อฉันเพิ่ม @Override โมฆะสาธารณะ onPause () {ถ้า (โต้ตอบ! = null) dialog.dismiss (); super.onPause (); } จนถึงปัจจุบันฉันไม่มีข้อผิดพลาดนี้ ... ดังนั้นฉันจึงคิดว่ามันเหมือนคำตอบของคุณและมันมีประโยชน์จริงๆ
Chris Sim

@ChrisSim สวัสดี! onPuase () และ onDestroy () เป็นแบบ defference เมื่อกิจกรรมคือ onPuase กล่องโต้ตอบจะปิด และเมื่อคุณดำเนินการแอพกล่องโต้ตอบจะไม่ปรากฏขึ้น คุณต้องการมันไหม
Hogun

@ โฮแกนใช่แน่นอนฉันหมายถึงความคิดเดียวกันฉันปิดกล่องโต้ตอบในการหยุดชั่วคราวแทนการทำลายเพราะฉันต้องการมันในการหยุดชั่วคราวไม่ได้อยู่ที่การทำลาย ประการที่สองฉันปิดมันเมื่อไม่เป็นโมฆะ ขอบคุณที่อธิบายเรื่องนี้ให้คนอื่น
Chris Sim

4

ใช้สิ่งนี้

if(_dialog!=null && _dialog.isShowing())
_dialog.dismiss();

2
มันเกือบเป็นโซลูชันเดียวกับที่ @Damjan เสนอ
ยูรี

28
ไม่เพียงพอ IllegalArgumentException ยังคงเกิดขึ้นกับการตรวจสอบนี้
เมอร์ฟี

ฉันทำแบบเดียวกัน แต่ก็ยังไม่รู้ว่ามันมีประสิทธิภาพหรือไม่ ความแตกต่างเท่านั้นฉันซ้อนสองถ้าเพื่อให้แน่ใจว่าส่วนที่สอง. isShowing () จะไม่ได้รับการประเมินถ้าเป็นโมฆะ
Nick

2
สิ่งนี้ไม่เพียงพอ
trante

1
@Nick: ไม่จำเป็นต้องซ้อนหลาย ๆ ตัวifในกรณีนี้&&ตัวดำเนินการของ Java มีการประเมินผลที่ขี้เกียจ (หรือที่เรียกว่าการลัดวงจร) ซึ่งหมายความว่าตัวถูกดำเนินการตัวที่สองจะไม่ถูกประเมินถ้าตัวแรกประเมินผลfalse(ซึ่งหมายถึงผลลัพธ์ของ&&จะเป็นfalseอยู่แล้วเพราะฉะนั้น "ขี้เกียจ" การประเมินผล) ในทำนองเดียวกัน||จะไม่ถูกดำเนินการประเมินครั้งที่ 2 trueถ้าคนแรกที่จะประเมิน หมายเหตุ: &และ|ตัวดำเนินการไม่มีลักษณะการทำงานนี้และประเมินค่าตัวถูกดำเนินการทั้งสองเสมอ
Matthias

3

ฉันมีปัญหาเดียวกันคุณสามารถแก้ไขได้โดย:

@Override
protected void onPostExecute(MyResult result) {
    try {
        if ((this.mDialog != null) && this.mDialog.isShowing()) {
            this.mDialog.dismiss();
        }
    } catch (final IllegalArgumentException e) {
        // Handle or log or ignore
    } catch (final Exception e) {
        // Handle or log or ignore
    } finally {
        this.mDialog = null;
    }  
}

2

ฉันคิดว่ารหัสของคุณถูกต้องไม่เหมือนกับคำตอบอื่น ๆ ที่แนะนำ onPostExecute จะทำงานบนเธรด UI นั่นคือจุดรวมของ AsyncTask - คุณไม่ต้องกังวลกับการเรียกใช้ runOnUi เธรดหรือจัดการกับตัวจัดการ นอกจากนี้ตามเอกสารการเลิกจ้าง () สามารถเรียกได้อย่างปลอดภัยจากหัวข้อใด ๆ (ไม่แน่ใจว่าพวกเขาทำข้อยกเว้นนี้)

อาจเป็นปัญหาเกี่ยวกับเวลาที่ dialog.dismiss () ถูกเรียกใช้หลังจากที่กิจกรรมไม่แสดงอีกต่อไป?

สิ่งที่เกี่ยวกับการทดสอบจะเกิดอะไรขึ้นถ้าคุณใส่เครื่องหมายออกจาก setOnCancelListener แล้วออกจากกิจกรรมในขณะที่ทำงานเบื้องหลัง จากนั้น onPostExecute ของคุณจะพยายามยกเลิกกล่องโต้ตอบที่ถูกยกเลิกไปแล้ว หากแอปขัดข้องคุณสามารถตรวจสอบได้ว่าเปิดกล่องโต้ตอบหรือไม่

ฉันมีปัญหาเดียวกันแน่นอนดังนั้นฉันจะลองใช้ในรหัส


ฉันยังดูเป็นรหัส dimiss () และแน่นอนมันสามารถเรียกได้อย่างปลอดภัยจากหัวข้อใด ๆ BTW ฉันมีปัญหากับการทดสอบเนื่องจากปัญหานี้เกิดขึ้นบนโทรศัพท์ของผู้ใช้และฉันไม่สามารถทำซ้ำได้ด้วยตัวเอง :-( ดังนั้นพยายามคิดโดยการวิเคราะห์รหัส ... ตามเวลาฉันคิดเกี่ยวกับเรื่องนี้ แต่นึกไม่ออกว่าสถานการณ์จะปิด Activity ก่อน Dialog ได้อย่างไรถ้ากด BACK มากกว่าจะเป็นการยกเลิก Dialog ก่อนและห้ามมิให้กิจกรรมนันทนาการอัตโนมัติเป็นไฟล์ Manifest แต่อาจจะสามารถสร้างใหม่ได้อย่างไร? ฉันรู้ว่าถ้าคุณพบบางสิ่งบางอย่าง!
alex2k8

2

อเล็กซ์

ฉันอาจจะผิดที่นี่ แต่ฉันสงสัยว่าโทรศัพท์หลายเครื่อง 'ในป่า' มีข้อผิดพลาดที่ทำให้พวกเขาสลับการวางแนวในการใช้งานที่มีการทำเครื่องหมายเป็นแบบคงที่ สิ่งนี้เกิดขึ้นได้เล็กน้อยบนโทรศัพท์ส่วนตัวของฉันและในโทรศัพท์ทดสอบหลายรุ่นที่กลุ่มของเราใช้ (รวมถึง droid, n1, g1, hero) โดยทั่วไปแล้วแอปที่ทำเครื่องหมายว่าเป็นแนวตั้งแบบคงที่ (อาจเป็นแนวตั้ง) จะวางตัวเองเป็นเวลาหนึ่งหรือสองวินาทีโดยใช้การวางแนวแนวนอนจากนั้นสลับกลับทันที ผลลัพธ์ที่ได้คือแม้ว่าคุณไม่ต้องการให้แอปสลับการวางแนว แต่คุณต้องเตรียมให้พร้อม ฉันไม่ทราบภายใต้เงื่อนไขที่แน่นอนว่าพฤติกรรมนี้สามารถทำซ้ำได้ฉันไม่ทราบว่าเป็นรุ่นเฉพาะของ Android หรือไม่ ทั้งหมดที่ฉันรู้คือฉันได้เห็นมันเกิดขึ้นมากมายครั้ง :(

ฉันขอแนะนำให้ใช้วิธีการแก้ปัญหาที่ให้ไว้ในลิงก์ที่คุณโพสต์ซึ่งแนะนำการเอาชนะวิธีการ onCreateDialog และให้ระบบปฏิบัติการ Android จัดการวงจรชีวิตของไดอะล็อกของคุณ ดูเหมือนว่าฉันจะชอบแม้ว่าคุณจะไม่ต้องการให้กิจกรรมของคุณเปลี่ยนทิศทาง แต่เป็นการเปลี่ยนการวางแนวที่อื่น คุณสามารถลองหาวิธีที่จะป้องกันการเปลี่ยนทิศทางได้ แต่ฉันพยายามจะบอกคุณว่าโดยส่วนตัวแล้วฉันไม่เชื่อว่ามีวิธีที่เข้าใจผิดที่ทำงานบนโทรศัพท์ Android ทุกรุ่นในตลาด


1
คุณสามารถป้องกันอุปกรณ์ของคุณจากการสลับทิศทาง แต่มีการเปลี่ยนแปลงการกำหนดค่าอื่น ๆ อีกมากมายที่ทำลาย / สร้างกิจกรรมของคุณอีกครั้งหนึ่งโดยทั่วไปการเลื่อนแป้นพิมพ์เข้าหรือออก
MaximumGoat

2

สิ่งที่ได้ผลสำหรับฉันเป็นส่วนใหญ่คือการตรวจสอบว่ากิจกรรมยังไม่จบ

if (!mActivity.isFinishing()) {
    dialog.dismiss();
}

2

กิจกรรมถูกประกาศว่าไม่ถูกสร้างขึ้นใหม่โดยการหมุนหรือการสไลด์คีย์บอร์ด

เพิ่งได้รับปัญหาเดียวกัน แก้ไขสำหรับ API ระดับ 13 หรือสูงขึ้น
จากเอกสาร Android:

หมายเหตุ: หากแอปพลิเคชันของคุณกำหนดเป้าหมาย API ระดับ 13 ขึ้นไป (ตามที่ประกาศโดยแอ็ตทริบิวต์ minSdkVersion และ targetSdkVersion) ดังนั้นคุณควรประกาศการกำหนดค่า "screenSize" เนื่องจากจะเปลี่ยนเมื่ออุปกรณ์สลับระหว่างแนวตั้งและแนวนอน

ดังนั้นฉันได้เปลี่ยนรายการของฉันเป็นแบบนี้:

<activity
        android:name="MyActivity"
        android:configChanges="orientation|screenSize"
        android:label="MyActivityName" >
</activity>

และตอนนี้ก็ใช้งานได้ดี กิจกรรมไม่ได้ถูกสร้างขึ้นใหม่เมื่อฉันหมุนโทรศัพท์กล่องโต้ตอบความคืบหน้าและมุมมองจะยังคงเหมือนเดิม ไม่มีข้อผิดพลาดสำหรับฉัน


นี่ไม่ใช่ทางออก ตัวอย่างเช่นฉันมีและกิจกรรม Adview จากผู้ดูแลระบบและควรสร้างกิจกรรมใหม่สำหรับการเปลี่ยนแปลงขนาด
batmaci

2

ก่อนอื่นให้จัดการกับข้อผิดพลาดที่เคยพยายามปิดกล่องโต้ตอบ

 if ((progressDialog != null) && progressDialog.isShowing()) {
            progressDialog.dismiss();
            progressDialog = null;
        }

หากไม่ได้รับการแก้ไขให้ยกเลิกมันในวิธีการ onStop () ของกิจกรรม

 @Override
    protected void onStop() {
        super.onStop();
        if ((progressDialog != null) && progressDialog.isShowing()) {
            progressDialog.dismiss();
            progressDialog = null;
        }
    }

1

ฉันมีปัญหาเดียวกันในขณะที่ใช้ปุ่มเพื่อซิงค์รายการจากเซิร์ฟเวอร์: 1) ฉันคลิกที่ปุ่ม 2) กล่องโต้ตอบความคืบหน้าปรากฏขึ้นในขณะที่ dowloading รายการจากเซิร์ฟเวอร์ 3) ฉันเปิดอุปกรณ์ไปยังทิศทางอื่น 4) java.lang .IllegalArgumentException: มุมมองไม่ได้แนบกับตัวจัดการหน้าต่างบน postExecute () ของ AsyncTask ในระหว่าง progress.dismiss ()

ขณะที่ฉันลองแก้ไขฉันคิดว่าแม้ว่าปัญหาจะไม่เกิดขึ้นรายชื่อของฉันก็ไม่แสดงรายการทั้งหมด

ฉันคิดว่าสิ่งที่ฉันต้องการคือการให้ AsyncTask เสร็จสิ้น (และยกเลิกกล่องโต้ตอบ) ก่อนที่กิจกรรมจะถูกทำลายดังนั้นฉันจึงสร้างวัตถุ asynctask เป็นแอตทริบิวต์และแทนที่เมธอด onDestroy ()

หาก asynctask ใช้เวลานานผู้ใช้อาจจะรู้สึกว่าอุปกรณ์ช้า แต่ฉันคิดว่านั่นเป็นราคาที่เขาจ่ายสำหรับการพยายามเปลี่ยนการวางแนวของอุปกรณ์ในขณะที่กล่องโต้ตอบความคืบหน้าปรากฏขึ้น และแม้ว่ามันจะใช้เวลาสักครู่ที่แอพจะไม่พัง

private AsyncTask<Boolean, Void, Boolean> atask;

@Override
protected void onDestroy() {
    if (atask!=null)
        try {
            atask.get();
        } catch (InterruptedException e) {
        } catch (ExecutionException e) {
        }
    super.onDestroy();
}

1
@Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);

            if (progressDialog != null && progressDialog.isShowing()) {
                Log.i(TAG, "onPostexucte");
                progressDialog.dismiss();
}
}

3
ในขณะที่ข้อมูลโค้ดนี้อาจตอบคำถามที่ให้คำอธิบายเกี่ยวกับวิธีการแก้ไขปัญหาจะช่วยให้ผู้เยี่ยมชมเว็บไซต์เข้าใจคำตอบของคุณในอนาคต
RobV

0

โค้ดด้านล่างนี้ใช้งานได้สำหรับคุณมันใช้ได้ผลดีกับฉัน:

private void viewDialog() {
    try {
        Intent vpnIntent = new Intent(context, UtilityVpnService.class);
        context.startService(vpnIntent);
        final View Dialogview = View.inflate(getBaseContext(), R.layout.alert_open_internet, null);
        final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_DIM_BEHIND,
                PixelFormat.TRANSLUCENT);
        params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL;
        windowManager.addView(Dialogview, params);

        Button btn_cancel = (Button) Dialogview.findViewById(R.id.btn_canceldialog_internetblocked);
        Button btn_okay = (Button) Dialogview.findViewById(R.id.btn_openmainactivity);
        RelativeLayout relativeLayout = (RelativeLayout) Dialogview.findViewById(R.id.rellayout_dialog);

            btn_cancel.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Handler handler = new Handler(Looper.getMainLooper());
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                if (Dialogview != null) {
//                                ( (WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE)).removeView(Dialogview);
                                    windowManager.removeView(Dialogview);
                                }
                            } catch (final IllegalArgumentException e) {
                                e.printStackTrace();
                                // Handle or log or ignore
                            } catch (final Exception e) {
                                e.printStackTrace();
                                // Handle or log or ignore
                            } finally {
                                try {
                                    if (windowManager != null && Dialogview != null) {
//                                    ((WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE)).removeView(Dialogview);
                                        windowManager.removeView(Dialogview);
                                    }
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                            //    ((WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE)).removeView(Dialogview);
//                        windowManager.removeView(Dialogview);


                        }
                    });
                }
            });
            btn_okay.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Handler handler = new Handler(Looper.getMainLooper());
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            //        ((WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE)).removeView(Dialogview);
                            try {
                                if (windowManager != null && Dialogview != null)
                                    windowManager.removeView(Dialogview);
                                Intent intent = new Intent(getBaseContext(), SplashActivity.class);
                                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//                        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
//                        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);


                                context.startActivity(intent);
                            } catch (Exception e) {
                                windowManager.removeView(Dialogview);
                                e.printStackTrace();
                            }
                        }
                    });
                }
            });
        } catch (Exception e) {
            //` windowManager.removeView(Dialogview);
            e.printStackTrace();
        }
    }

อย่ากำหนดมุมมองของคุณทั่วโลกถ้าคุณเรียกมันจากบริการพื้นหลัง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.