Android: ProgressDialog.show () gặp sự cố với getApplicationContext


109

Tôi dường như không thể hiểu tại sao điều này lại xảy ra. Mã này:

mProgressDialog = ProgressDialog.show(this, "", getString(R.string.loading), true);

hoạt động tốt. Tuy nhiên, mã này:

mProgressDialog = ProgressDialog.show(getApplicationContext(), "", getString(R.string.loading), true);

ném ngoại lệ sau:

W/WindowManager(  569): Attempted to add window with non-application token WindowToken{438bee58 token=null}.  Aborting.
D/AndroidRuntime( 2049): Shutting down VM
W/dalvikvm( 2049): threadid=3: thread exiting with uncaught exception (group=0x4001aa28)
E/AndroidRuntime( 2049): Uncaught handler: thread main exiting due to uncaught exception
E/AndroidRuntime( 2049): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tastekid.TasteKid/com.tastekid.TasteKid.YouTube}: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
E/AndroidRuntime( 2049):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2401)
E/AndroidRuntime( 2049):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2417)
E/AndroidRuntime( 2049):    at android.app.ActivityThread.access$2100(ActivityThread.java:116)
E/AndroidRuntime( 2049):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
E/AndroidRuntime( 2049):    at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime( 2049):    at android.os.Looper.loop(Looper.java:123)
E/AndroidRuntime( 2049):    at android.app.ActivityThread.main(ActivityThread.java:4203)
E/AndroidRuntime( 2049):    at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 2049):    at java.lang.reflect.Method.invoke(Method.java:521)
E/AndroidRuntime( 2049):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
E/AndroidRuntime( 2049):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549)
E/AndroidRuntime( 2049):    at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime( 2049): Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
E/AndroidRuntime( 2049):    at android.view.ViewRoot.setView(ViewRoot.java:460)
E/AndroidRuntime( 2049):    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
E/AndroidRuntime( 2049):    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
E/AndroidRuntime( 2049):    at android.app.Dialog.show(Dialog.java:238)
E/AndroidRuntime( 2049):    at android.app.ProgressDialog.show(ProgressDialog.java:107)
E/AndroidRuntime( 2049):    at android.app.ProgressDialog.show(ProgressDialog.java:90)
E/AndroidRuntime( 2049):    at com.tastekid.TasteKid.YouTube.onCreate(YouTube.java:45)
E/AndroidRuntime( 2049):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
E/AndroidRuntime( 2049):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364)
E/AndroidRuntime( 2049):    ... 11 more

Có ý kiến ​​giải thích tại sao điều này lại xảy ra không? Tôi đang gọi điều này từ onCreatephương thức.


Nếu bạn đang sử dụng Fragment, stackoverflow.com/questions/24825114/…
Yeo

Câu trả lời:


42

Bạn đang sử dụng phiên bản API nào? Nếu tôi đúng về vấn đề thì điều này đã được khắc phục trong Android 1.6 (phiên bản API 4).

Có vẻ như tham chiếu đối tượng getApplicationContext()đang trả về chỉ là null. Tôi nghĩ rằng bạn đang gặp vấn đề tương tự như tôi đã gặp ở chỗ một số mã trong mã onCreate()đang được chạy trước khi cửa sổ thực sự được xây dựng xong. Đây sẽ là một vụ hack, nhưng hãy thử khởi chạy một Chủ đề mới trong vài trăm mili giây (IIRC: 300-400 dường như phù hợp với tôi, nhưng bạn sẽ cần phải mày mò) để mở ProgressDialog của bạn và bắt đầu bất kỳ thứ gì khác mà bạn cần ( ví dụ: mạng IO). Một cái gì đó như thế này:

@Override
public void onCreate(Bundle savedInstanceState) {
    // do all your other stuff here

    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            mProgressDialog = ProgressDialog.show(
               YouTube.this.getApplicationContext(), "",
               YouTube.this.getString(R.string.loading), true);

            // start time consuming background process here
        }
    }, 1000); // starting it in 1 second
}

6
Tôi đang sử dụng 1.6. Tôi khá chắc chắn rằng bất kỳ hoạt động giao diện người dùng nào cũng phải được thực hiện trong chuỗi giao diện người dùng, do đó việc gọi ProgressDialog.show () trong một chuỗi riêng có thể dễ dàng là một vấn đề lớn. Vẫn nghĩ rằng điều này là kỳ lạ.
Felix

3
Trong ví dụ tôi đưa ra, bạn không thực hiện các hoạt động giao diện người dùng trong một luồng khác, luồng khác chỉ đang gọi lại luồng giao diện người dùng yêu cầu nó mở hộp thoại.
Jeremy Logan

Nó chắc chắn là kỳ lạ và đó là một vụ hack hoàn toàn, nhưng nó đã hiệu quả với tôi. Tôi cần kiểm tra lỗi mà tôi gặp phải trong 1.6 để xem liệu tôi có thể NGỪNG sử dụng lỗi này không.
Jeremy Logan

1
Nó không phải là 'kỳ lạ' cũng không phải là 'hack tổng thể', đó là một cách tiếp cận hoàn toàn hợp pháp!
KomodoDave

1
@KomodoDave Tôi vừa nhận ra rằng mình gặp vấn đề tương tự. Tuy nhiên, vụ hack tồi tệ là trong bộ đếm thời gian. Đây là cửa sổ thời gian chờ không liên tục trong một số tình huống. Chìa khóa thành công có thể nằm ở việc đặt bộ đếm thời gian ngắn hơn, kiểm tra xem ứng dụng đã sẵn sàng chưa, thực hiện lại hành động cho đến khi đúng. Có thể giới hạn số lần thử là tốt.
Jim Rush

129

Tôi đang sử dụng phiên bản Android 2.1 với API Cấp 7. Tôi đã gặp phải sự cố này (hoặc tương tự) và đã giải quyết bằng cách sử dụng:

Dialog dialog = new Dialog(this);

thay vì cái này:

Dialog dialog = new Dialog(getApplicationContext());

Hi vọng điêu nay co ich :)


4
Tôi gặp sự cố tương tự nhưng đang sử dụng ActivityGroup. Cách duy nhất tôi có thể giải quyết lỗi này là sử dụng getParent () để thay thế.
brack

20
Làm thế nào để trả lời câu hỏi của mình? Anh ta hỏi TẠI SAO cái thứ hai không hoạt động, trong khi cái đầu tiên thì có.
Burkhard

3
-1, 'this' cũng giống như 'getApplicationContext ()' đối với một số người trong chúng ta.
kellogs,

Vẫn là một mẹo hữu ích đang phát triển cho 2.1
Carlos P

64

Đối với tôi đã làm việc thay đổi

builder = new AlertDialog.Builder(getApplicationContext());

đến

builder = new AlertDialog.Builder(ThisActivityClassName.this);

Điều kỳ lạ là cái đầu tiên có thể được tìm thấy trong hướng dẫn của google và mọi người gặp lỗi về điều này ..


1
Giải pháp duy nhất làm việc cho tôi với một cảnh báo bên trong một sự kiện onclick
Tobias

Đây là cách chính xác để làm điều đó. Không bao giờ sử dụng ApplicationContext trừ khi thực sự cần thiết và trên hết, không bao giờ sử dụng nó để hiển thị các phần tử giao diện người dùng. Đó là những gì các hoạt động (và cuối cùng là các mảnh).
Martin Marconcini

Đây là một trong những. thistất cả một mình sẽ không hoạt động nếu bạn đang làm điều đó bên trong, ví dụ, nhấp vào trình nghe.
Ayman Salah

23

Tôi không nghĩ rằng đây là vấn đề về thời gian xung quanh ngữ cảnh ứng dụng rỗng

Thử mở rộng Ứng dụng trong ứng dụng của bạn (hoặc chỉ sử dụng nếu bạn đã có)

public class MyApp extends Application

Làm cho phiên bản có sẵn dưới dạng một singleton riêng tư. Điều này không bao giờ rỗng

private static MyApp appInstance;

Tạo một trình trợ giúp tĩnh trong MyApp (sẽ sử dụng singleton)

    public static void showProgressDialog( CharSequence title, CharSequence message )
{
    prog = ProgressDialog.show(appInstance, title, message, true); // Never Do This!
}

BÙM !!

Ngoài ra, hãy xem câu trả lời của kỹ sư android tại đây: WindowManager $ BadTokenException

Một nguyên nhân gây ra lỗi này có thể là cố gắng hiển thị cửa sổ / hộp thoại ứng dụng thông qua Ngữ cảnh không phải là Hoạt động.

Bây giờ, tôi đồng ý, sẽ không hợp lý khi phương thức sử dụng tham số Ngữ cảnh, thay vì Hoạt động ..


10

Sau khi đọc các câu trả lời ở trên, tôi thấy rằng đối với tình huống của mình, phần sau đã khắc phục được sự cố.

Điều này đã gây ra lỗi

myButton.setOnClickListener(new OnClickListener(){
    public void onClick(View v) {
        MyDialogue dialog = new MyDialogue(getApplicationContext());
        dialog.show();              
    }
});

Dựa trên các câu trả lời trước đó cho thấy ngữ cảnh là sai, tôi đã thay đổi getApplicationContext () để truy xuất ngữ cảnh từ Chế độ xem được chuyển vào phương thức onClick của các nút.

myButton.setOnClickListener(new OnClickListener(){
    public void onClick(View v) {
        MyDialogue dialog = new MyDialogue(v.getContext());
        dialog.show();              
    }
});

Tôi không hiểu đầy đủ về hoạt động của Java nên tôi có thể sai, nhưng tôi đoán rằng đối với tình huống cụ thể của tôi, nguyên nhân có thể liên quan đến thực tế là đoạn mã trên được định nghĩa trong một lớp Hoạt động Tóm tắt; được thừa kế và sử dụng bởi nhiều Hoạt động, có lẽ điều đó đã góp phần vào việc getApplicationContext () không trả về ngữ cảnh hợp lệ ?? (Chỉ là phỏng đoán).


Các giải pháp được ghi điểm tốt hơn có thể phù hợp với hầu hết các trường hợp, nhưng kỹ thuật v.getContext () của bạn dường như giải quyết được các trường hợp khó xử nhất như của tôi. Kiến thức java theo kinh nghiệm của tôi khiến tôi nghĩ rằng ngữ cảnh đến từ một phương thức onCreate không hoàn toàn giống với một ngữ cảnh đến từ Chế độ xem của một phương thức onClick. Hãy bình chọn!
Josh

Điều này đã cứu ngày của tôi!
Alejandro Luengo

6

Tôi đang tạo chế độ xem bản đồ với các lớp phủ được chia thành từng mục. Tôi đang tạo lớp phủ thành từng khoản như thế này từ mapActivity của mình:

OCItemizedOverlay currentLocationOverlay = new OCItemizedOverlay(pin,getApplicationContext);

Tôi nhận thấy rằng tôi sẽ nhận được ngoại lệ "android.view.WindowManager $ BadTokenException: Không thể thêm cửa sổ - mã thông báo null không dành cho ứng dụng" khi phương thức onTap của lớp phủ mục của tôi được kích hoạt (khi vị trí được nhấn vào chế độ xem bản đồ).

Tôi thấy rằng nếu tôi chỉ đơn giản chuyển 'this' thay vì 'getApplicationContext ()' cho hàm tạo của mình, thì sự cố đã biến mất. Điều này dường như ủng hộ kết luận của aliejazzcat. kỳ dị.


1
Cảm ơn, đây chính xác là vấn đề của tôi.
Kon

4

Đối với các Hoạt động được hiển thị trong TabA Hoạt động, hãy sử dụng getParent ()

final AlertDialog.Builder builder = new AlertDialog.Builder(getParent());

thay vì

final AlertDialog.Builder builder = new AlertDialog.Builder(this);

3

Đối với Android 2.2
Sử dụng mã này:

//activity is an instance of a class which extends android.app.Activity
Dialog dialog = new Dialog(activity);

thay vì mã này:

// this code produces an ERROR:
//android.view.WindowManager$BadTokenException: 
//Unable to add window -- token null is not for an application
Context mContext = activity.getApplicationContext();
Dialog dialog = new Dialog(mContext);

Ghi chú: Hộp thoại tùy chỉnh của tôi được tạo bên ngoài activity.onCreateDialog(int dialogId)phương pháp.


3

Thử -

AlertDialog.Builder builder = new AlertDialog.Builder(getParent());

Cần thiết khi hoạt động hiện nay là bên trong một activitygroup
htafoya

2

Đã gặp sự cố tương tự với (khả năng tương thích) Fragment trong đó sử dụng getActivity()bên trong làm ProgressDialog.show()hỏng nó. Tôi đồng ý rằng đó là do thời gian.

Có thể sửa chữa:

mContext = getApplicationContext();

if (mContext != null) {
    mProgressDialog = ProgressDialog.show(mContext, "", getString(R.string.loading), true);
}

thay vì sử dụng

mProgressDialog = ProgressDialog.show(getApplicationContext(), "", getString(R.string.loading), true);

Đặt mContext càng sớm càng tốt để có thêm thời gian lấy bối cảnh. Vẫn không có gì đảm bảo rằng điều này sẽ hoạt động, nó chỉ làm giảm khả năng xảy ra sự cố. Nếu nó vẫn không hoạt động, bạn phải dùng đến hack bộ đếm thời gian (có thể gây ra các vấn đề về thời gian khác như loại bỏ hộp thoại sau này).

Tất nhiên, nếu bạn có thể sử dụng thishoặc ActivityName.this, nó ổn định hơn vì thisđã chỉ ra một cái gì đó. Nhưng trong một số trường hợp, như với một số kiến ​​trúc Fragment, nó không phải là một tùy chọn.


2

(Để tham khảo sau này)

Tôi nghĩ đó là do có sự khác biệt trong Bối cảnh ứng dụng và Bối cảnh hoạt động, như được giải thích ở đây: http://www.doubleencore.com/2013/06/context/

Điều đó có nghĩa là chúng tôi không thể hiển thị hộp thoại sử dụng Ngữ cảnh ứng dụng. Đó là nó.


2

Để sử dụng hộp thoại bên trong các hoạt động, hãy làm theo cách này:

private Context mContext;
private AlertDialog.Builder mBuilder;

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

     //using mContext here refering to activity context
     mBuilder = new AlertDialog.Builder(mContext);
     //...
     //rest of the code
     //...
}

Để sử dụng hộp thoại bên trong các đoạn, hãy làm theo cách này:

private Context mContext;
private AlertDialog.Builder mBuilder;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      View mRootView = inflater.inflate(R.layout.fragment_layout, container, false);
      mContext = getActivity();

      //using mContext here refering to fragment's hosting activity context
      mBuilder = new AlertDialog.Builder(mContext);
      //...
      //rest of the code
      //...
      return mRootView;
}

Vậy là xong ^ _ ^


1

Những gì tôi đã làm để giải quyết vấn đề này là tạo một lớp cơ sở cho tất cả các hoạt động của tôi, nơi tôi lưu trữ dữ liệu toàn cầu. Trong hoạt động đầu tiên, tôi đã lưu ngữ cảnh trong một biến trong lớp cơ sở của mình như sau:

Lớp cơ sở

public static Context myucontext; 

Hoạt động đầu tiên bắt nguồn từ Lớp cơ sở

mycontext = this

Sau đó, tôi sử dụng mycontext thay vì getApplicationContext khi tạo hộp thoại.

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

Thật xấu hổ khi giải pháp này không nhận được bất kỳ phiếu ủng hộ nào nữa. Trong số tất cả các giải pháp có thể trình bày ở đây, đây là điều duy nhất mà làm việc cho tôi trong một AsyncTask
ckn

1

Nếu bạn đang gọi ProgressDialog.show () trong một phân đoạn, việc truyền mContext tới Activity phù hợp với tôi.

     ProgressDialog pd = new ProgressDialog((Activity) mContext);

1

Đây là một vấn đề phổ biến. Sử dụng thisthay vì getApplicationContext() Điều đó sẽ giải quyết vấn đề của bạn


0

Tôi đã triển khai Hộp thoại cảnh báo để ngoại lệ chuyển sang chế độ xem hoạt động hiện tại. Bất cứ khi nào tôi đưa ra như thế này

AlertDialog.Builder builder = new AlertDialog.Builder(context);

Đưa ra cùng một Ngoại lệ Cửa sổ, Tôi viết mã cảnh báo ra khỏi onCreate (). Rất đơn giản, tôi đã sử dụng câu lệnh context = this;sau setContentView()trong onCreate()phương thức. Lấy biến ngữ cảnh làm toàn cục nhưContext context;

Mẫu mã là

static Context context;

 public void onCreate(Bundle savedInstanceState)  { 
        super.onCreate(savedInstanceState); 


        setContentView(R.layout.network); 
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

        context = this;
.......

Mẫu Phương pháp Cảnh báo mới là

private void alertException(String execMsg){
        Log.i(TAG,"in alertException()..."+context);
        Log.e(TAG,"Exception :"+execMsg);
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
.......

Nó hoạt động tốt đối với tôi. Thực tế tôi đã tìm kiếm lỗi này trên StackOverflow, tôi tìm thấy truy vấn này. Sau khi đọc tất cả các phản hồi của bài đăng này, tôi đã thử theo cách này để nó hoạt động. Tôi nghĩ đây là một giải pháp đơn giản để khắc phục ngoại lệ.

Cảm ơn, Rajendar


0

nếu bạn gặp sự cố trên groupActivity, đừng sử dụng cái này. PARENT là một tĩnh từ Nhóm hoạt động dành cho cha mẹ.

final AlertDialog.Builder builder = new AlertDialog.Builder(GroupActivityParent.PARENT);

thay vì

final AlertDialog.Builder builder = new AlertDialog.Builder(getParent());

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.