Lỗi: BinderProxy @ 45d459c0 không hợp lệ; hoạt động của bạn có chạy không?


143

Lỗi này là gì ... tôi chưa tìm thấy bất kỳ cuộc thảo luận nào về lỗi này trong cộng đồng stackoverflow Chi tiết: -

10-18 23:53:11.613: ERROR/AndroidRuntime(3197): Uncaught handler: thread main exiting due to uncaught exception
10-18 23:53:11.658: ERROR/AndroidRuntime(3197): android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@45d459c0 is not valid; is your activity running?
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.view.ViewRoot.setView(ViewRoot.java:468)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.view.Window$LocalWindowManager.addView(Window.java:424)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.app.Dialog.show(Dialog.java:239)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at com.vishal.contacte.Locationlistener$MyLocationListener.onLocationChanged(Locationlistener.java:86)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.location.LocationManager$ListenerTransport._handleMessage(LocationManager.java:179)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.location.LocationManager$ListenerTransport.access$000(LocationManager.java:112)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.location.LocationManager$ListenerTransport$1.handleMessage(LocationManager.java:128)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.os.Handler.dispatchMessage(Handler.java:99)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.os.Looper.loop(Looper.java:123)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.app.ActivityThread.main(ActivityThread.java:4363)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at java.lang.reflect.Method.invokeNative(Native Method)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at java.lang.reflect.Method.invoke(Method.java:521)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:862)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at dalvik.system.NativeStart.main(Native Method)

kiểm tra liên kết này: Android - [Hiển thị hộp thoại từ chủ đề nền] ( dimitar.me/android-displaying-dialogs-from-background-threads )
Naveen

Liên kết của bạn giống với câu trả lời được chấp nhận, nhưng nó tốt hơn nhiều. Cảm ơn vì điều đó
LuckyMalaka


Câu trả lời:


343

Điều này rất có thể xảy ra vì bạn đang cố hiển thị hộp thoại sau khi thực hiện luồng nền, trong khi Hoạt động đang bị hủy.

Tôi đã thấy lỗi này được báo cáo thỉnh thoảng từ một số ứng dụng của tôi khi hoạt động gọi hộp thoại kết thúc vì lý do này hay lý do khác khi nó cố gắng hiển thị hộp thoại. Đây là những gì đã giải quyết nó cho tôi:

if(!((Activity) context).isFinishing())
{
    //show dialog
}

Tôi đã sử dụng điều này để khắc phục sự cố trên các phiên bản Android cũ hơn trong vài năm nay và đã không thấy sự cố kể từ đó.


1
Điều này thực sự có mẹo! Nhưng có cách nào để mở hộp thoại ngay cả khi điều đó xảy ra? Tôi không thực sự chắc chắn về cách quản lý hộp thoại khi điều này xảy ra. Bất kỳ đề xuất? Cảm ơn trước!
Carla Urrea Stabile

@CarlaStabile xin chào! Cách duy nhất tôi có thể nghĩ để hiển thị hộp thoại khi điều này xảy ra là nếu bạn có thể có được Bối cảnh hợp lệ cho một hoạt động chưa kết thúc - nó sẽ phụ thuộc vào nơi bạn gọi mã này và nếu bạn có cách lấy lại một bối cảnh từ một hoạt động khác, không hoàn thiện.
DiscDev

8
Cảm ơn rất nhiều! Đối với tôi, sự cố (có thông báo lỗi ở trên) sẽ xảy ra khi tôi nhấn nút quay lại, trước khi hộp thoại hiển thị. Vì vậy, mã sẽ tiếp tục và cố gắng hiển thị nó, mặc dù tôi đã ở trong một hoạt động khác. Nhưng điều này đã ngăn chặn sự cố và tôi đã đi đến hoạt động mới một cách dễ dàng!
Azurespot 10/11/2015

1
Có rất nhiều câu hỏi tương tự, nhưng không ai trong số họ được đề xuất điều này. Cá nhân đây là giải pháp đúng duy nhất cho kịch bản của tôi.
fillobotto

phiên bản kotlin cho việc này là gì? sẽ làFinishing () là đủ?
Alok Rajasukumaran

12

Tôi đã đối mặt với cùng một vấn đề và sử dụng mã do DiscDev đề xuất ở trên với những thay đổi nhỏ như sau:

if (!MainActivity.this.isFinishing()){
    alertDialog.show();
}

tôi đã thay đổi vì ngữ cảnh (Hoạt động) có nghĩa là MainActivity.this cho trường hợp của tôi. Ngoài ra, bạn đúng về liên kết hồ sơ người dùng, nhưng tôi nghĩ rằng bạn có thể tìm thấy nó ở trên.
Hamza Polat

4

nếu hộp thoại gặp sự cố này do luồng bạn nên chạy trên luồng UI như thế này: -

runOnUiThread(new Runnable() {
            @Override
            public void run() {
                dialog.show();

            }
        });

2

Lỗi này xảy ra khi bạn đang hiển thị hộp thoại cho một bối cảnh không còn tồn tại.

Trước khi gọi .show()kiểm tra rằng hoạt động / bối cảnh không kết thúc

if (!(context instanceof Activity && ((Activity) context).isFinishing())) {
    alert.show();
}

1

Tôi gặp phải lỗi này khi tôi có một countDownTimertrong ứng dụng của mình. Nó có một phương thức gọi GameOver trong ứng dụng của tôi là

public void onFinish() {
     GameOver();
}

nhưng thực sự trò chơi có thể kết thúc trước khi hết giờ do người dùng nhấp nhầm (đó là trò chơi nhấp chuột). Vì vậy, khi tôi đang xem hộp thoại Game Over sau 20 giây, tôi đã quên hủy countDownTimervì vậy khi hết thời gian, hộp thoại lại xuất hiện. Hoặc bị lỗi với lỗi trên vì một số lý do.


1

Cách khắc phục điều này khá đơn giản. Chỉ cần kiểm tra nếu Activity đang trải qua giai đoạn hoàn thiện trước khi hiển thị Hộp thoại:

  private Handler myHandler = new Handler() {
  @Override
  public void handleMessage(Message msg) {
    switch (msg.what) {
      case DISPLAY_DLG:
        if (!isFinishing()) {
        showDialog(MY_DIALOG);
        }
      break;
    }
  }
};

xem thêm ở đây


1

Trong trường hợp của tôi, vấn đề là nó Contextđược giữ như một tài liệu tham khảo yếu trong lớp mở rộng Handler. Sau đó, tôi đã đi qua Messenger, đó là kết thúc xử lý, thông qua một Intentđến Service. Tôi đã làm điều này mỗi khi hoạt động xuất hiện trên màn hình trong onResume()phương thức.

Vì vậy, như bạn hiểu, Messenger đã được tuần tự hóa cùng với các trường của nó (bao gồm cả ngữ cảnh), vì đó là cách duy nhất để truyền các đối tượng sử dụng Intent- để tuần tự hóa chúng. Vào thời điểm đó khi Messenger được chuyển đến dịch vụ, bản thân hoạt động vẫn chưa sẵn sàng để hiển thị các hộp thoại vì nó ở trạng thái khác (được nói là onResume (), điều đó hoàn toàn khác với khi hoạt động đã có trên màn hình). Vì vậy, khi trình nhắn tin được giải tuần tự hóa, bối cảnh vẫn ở trạng thái tiếp tục, trong khi hoạt động thực sự đã có trên màn hình. Hơn nữa, khử lưu trữ phân bổ bộ nhớ cho đối tượng mới, khác hoàn toàn với đối tượng ban đầu.

Giải pháp chỉ là liên kết với dịch vụ mỗi khi bạn cần và trả lại một chất kết dính có phương thức như 'setMesbah (Messenger messenger)' và gọi nó, khi bạn bị ràng buộc với dịch vụ.


1

Tôi giải quyết vấn đề này bằng cách sử dụng WeakReference<Activity>như một bối cảnh. Sự cố không bao giờ xuất hiện nữa. Đây là một mã mẫu trong Kotlin:

Lớp quản lý hộp thoại:

class DialogManager {

        fun showAlertDialog(weakActivity: WeakReference<Activity>) {
            val wActivity = weakActivity.get()
            wActivity?.let {
                val builder = AlertDialog.Builder(wActivity, R.style.MyDialogTheme)
                val inflater = wActivity.layoutInflater
                val dialogView = inflater.inflate(R.layout.alert_dialog_info, null)
                builder.setView(dialogView)

                // Set your dialog properties here. E.g. builder.setTitle("MyTitle")

                builder.create().show()
            }
         }

}

Và bạn hiển thị hộp thoại như thế này:

 val dialogManager = DialogManager()
 dialogManager.showAlertDialog(WeakReference<Activity>(this@MainActivity))

Nếu bạn muốn siêu lừa được bảo vệ khỏi sự cố. Thay vì builder.create().show()sử dụng:

val dialog = builder.create()
safeShow(weakActivity, dialog)

Đây là safeShowphương pháp:

private fun safeShow(weakActivity: WeakReference<Activity>, dialog: AlertDialog?) {
        val wActivity = weakActivity.get()
        if (null != dialog && null != wActivity) {
            // Api >=17
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                if (!dialog.isShowing && !(wActivity).isFinishing && !wActivity.isDestroyed) {
                    try {
                        dialog.show()
                    } catch (e: Exception) {
                        //Log exception
                    }
                }
            } else {

                // Api < 17. Unfortunately cannot check for isDestroyed()
                if (!dialog.isShowing && !(wActivity).isFinishing) {
                    try {
                        dialog.show()
                    } catch (e: Exception) {
                        //Log exception
                    }
                }
            }
        }
    }

Đây là một phương pháp tương tự mà bạn có thể sử dụng để loại bỏ hộp thoại một cách an toàn:

private fun safeDismissAlertDialog(weakActivity: WeakReference<Activity>, dialog: AlertDialog?) {
        val wActivity = weakActivity.get()
        if (null != dialog && null != wActivity) {
            // Api >=17
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                if (dialog.isShowing && !wActivity.isFinishing && !wActivity.isDestroyed) {
                    try {
                        dialog.dismiss()
                    } catch (e: Exception) {
                        //Log exception
                    }
                }
            } else {

                // Api < 17. Unfortunately cannot check for isDestroyed()
                if (!dialog.isShowing && !(wActivity).isFinishing) {
                    try {
                        dialog.dismiss()
                    } catch (e: Exception) {
                        //Log exception
                    }
                }
            }
        }
    }

0

Làm thế nào về việc tạo một Instance mới của hộp thoại mà bạn muốn gọi? Tôi thực sự đã gặp vấn đề tương tự, và đó là những gì tôi làm. thay vì:

if(!((Activity) context).isFinishing())
{
    //show dialog
}

Còn cái này thì sao?

 YourDialog mDialog = new YourDialog();
 mDialog1.show(((AppCompatActivity) mContext).getSupportFragmentManager(), "OrderbookDialog");
                        }

Vì vậy, thay vì chỉ kiểm tra xem có an toàn hay không hiển thị hộp thoại, tôi nghĩ sẽ an toàn hơn nhiều nếu chúng ta chỉ tạo một phiên bản mới để hiển thị hộp thoại.

Giống như tôi, trong trường hợp của tôi, tôi đã cố gắng tạo một phiên bản (từ Fragment onCreate ) và gọi phiên bản của hộp thoại đó trong một nội dung khác của adapterList và điều này sẽ dẫn đến "lỗi hoạt động của bạn đang chạy" - lỗi . Tôi nghĩ đó là bởi vì tôi chỉ cần tạo một ví dụ (từ onCreate) và sau đó nó được được tiêu huỷ, vì vậy khi tôi cố gắng gọi nó từ một adapterList tôi gọi thoại từ dụ cũ.

Tôi không chắc liệu giải pháp của mình có thân thiện với bộ nhớ hay không, vì tôi đã không thử cấu hình nó, nhưng nó hoạt động (chắc chắn, nó an toàn nếu bạn không tạo quá nhiều ví dụ)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.