Выбор Android Spinner вызывает WindowManager $ BadTokenException - PullRequest
1 голос
/ 29 сентября 2010

Я создал специальный AlertDialog для отображения Spinner и некоторых элементов EditText. Когда я выбираю пункт меню, запускается этот пользовательский AlertDialog. Все работает нормально, пока я на самом деле не выбрал счетчик, чтобы попытаться выбрать элемент, и в этот момент я получаю исключение BadTokenException. Я читал другие посты StackOverflow, в которых говорилось, что подобные исключения были результатом попытки отобразить диалог, используя getApplicationContext (), а не передавая Activity.this. Я не передаю явно getApplicationContext () ни на что, связанное с этим AlertDialog.

Чтобы настроить этот пользовательский журнал AlertDiaglog, я создал файл макета, содержащий элементы Spinner и EditText, а затем заставил AlertDialog использовать этот макет:

LayoutInflater inflater = (LayoutInflater)getApplication().getSystemService(LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.custom_layout, (ViewGroup)findViewById(R.id.custom_layout_root));
spinner = (Spinner)layout.findViewById(R.id.custom_layout_spinner);
ArrayAdapter adap = ArrayAdapter.createFromResource(Activity.this, R.array.data, android.R.layout.simple_spinner_item);
adap.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adap);
spinner.setOnItemSelectedListener(new SpinnerItemListener());

AlertDialog.Builder dialog = new AlertDialog.Builder(Activity.this);
dialog.setTitle("Title");
dialog.setPositiveButton("Ok", new Dialog.OnClickListener() ...
...
dialog.show();

Этот код отлично работает для отображения AlertDialog. Однако, когда я фактически касаюсь Spinner, я получаю следующую проблему:

Thread [<3> main] (Suspended (exception WindowManager$BadTokenException)) 
ViewRoot.handleMessage(Message) line: 1704
ViewRoot(Handler).dispatchMessage(Message) line: 99 
Looper.loop() line: 123 
ActivityThread.main(String[]) line: 4203
Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]
Method.invoke(Object, Object...) line: 521
ZygoteInit$MethodAndArgsCaller.run() line: 791
ZygoteInit.main(String[]) line: 549
NativeStart.main(String[]) line: not available [native method]

Кто-нибудь имеет представление о том, что происходит? Сообщение об исключении говорит:

Unable to add window -- token null is not for an application

Я полагаю, что это сообщение, которое другие видели для этого типа проблемы, поэтому я предполагаю, что ApplicationContext находится где-то в миксе, но я не уверен, где. Мой манифест настроен с minSdk 1.5 с Target SDK 1.6.

Ответы [ 2 ]

8 голосов
/ 30 сентября 2010

Я читал другие посты StackOverflow, в которых говорилось, что подобные исключения были результатом попытки отобразить диалог с использованием getApplicationContext () вместо передачи Activity.this.
Я не передаю явно getApplicationContext ()все, что связано с этим AlertDialog.

Предположительно, эта строка кода на самом деле делает именно это - вы просите Application использовать его контекстчтобы получить доступ к сервису, а не к текущему Window:

LayoutInflater inflater = 
  (LayoutInflater) getApplication().getSystemService(LAYOUT_INFLATER_SERVICE);

Вы не можете просто заменить его на версию ниже, так как вы запускаете AlertDialog из Activity?

LayoutInflater inflater =
  (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);

Или даже проще:

LayoutInflater inflater = <a href="http://developer.android.com/reference/android/app/Activity.html#getLayoutInflater%28%29" rel="noreferrer">getLayoutInflater()</a>;

2 голосов
/ 16 октября 2012

Я потерял много времени из-за этой странной проблемы, но в итоге решил следующее. Посмотрите этот код:

/**
 * Initializes the body of the screen that serves a user to edit a new question.
 */
private void onStart_initializeNewQuestion()
{
    /**
     * 0. Local variables.
     */
    Spinner spinner, spinner2;
    ArrayAdapter<CharSequence> arrayAdapter;
    EditText editText;

    /**
     * 1. Inflate the layout, and configure useful pointers.
     */
    this.viewGroup_body_newquestion= (ViewGroup) this.layoutInflater.inflate(R.layout.create_survey_newquestion, null);

    /**
     * 2. Populate the spinner with user choices, and then set responding spinner to user selections
     */
    spinner= (Spinner) this.viewGroup_body_newquestion.findViewById(R.id.create_survey_newquestion_spinner_questionType);

    // Create an ArrayAdapter using the string array and a default spinner layout
    arrayAdapter= ArrayAdapter.createFromResource(this, R.array.create_surveys_newquestion_spinnerOptions,
            android.R.layout.simple_spinner_item);
    // Specify the layout to use when the list of choices appears
    arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    // Apply the adapter to the spinner
    spinner.setAdapter(arrayAdapter);
    // spinner.setOnItemSelectedListener(this);

    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
    {

        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int pos, long id)
        {
            String choice;
            choice= parent.getItemAtPosition(pos).toString();
            U.e(U.VERBOSE, "CreateSurveyActivity.onStart_initializeNewQuestion(listener@spinner_questionType): " + choice);

        }

        @Override
        public void onNothingSelected(AdapterView<?> arg0)
        {
            // TODO Auto-generated method stub

        }
    });

    spinner2= new Spinner(this);
    spinner2.setAdapter(arrayAdapter);
    spinner2.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
    {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int pos, long id)
        {
            String choice;
            choice= parent.getItemAtPosition(pos).toString();
            U.e(U.VERBOSE, "CreateSurveyActivity.onStart_initializeNewQuestion(listener@spinner_questionType): " + choice);

        }

        @Override
        public void onNothingSelected(AdapterView<?> arg0)
        {
            // TODO Auto-generated method stub

        }
    });
    LinearLayout linearLayout= (LinearLayout) this.viewGroup_body_newquestion.getChildAt(0);
    linearLayout.addView(spinner2);


}

Посмотрите, как spinner vs spinner2: spinner существует внутри раздутого макета (корнем которого является ScrollView), и spinner2 создается программно на этом объекте Activity.

Поскольку я не могу изменить контекст spinner1, чтобы он совпадал с этим контекстом, в конце концов я создал новый Spinner непосредственно в этом контексте. И поэтому спиннер не работает, а spinner2 работает.

PS: использованный инфлятор для макета используется так же, как и для инфляции многих других макетов:

    this.layoutInflater= (LayoutInflater) this.getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

PS2: решение, предоставленное Кристофером, позволяет продолжать использовать оригинальный счетчик, так что это лучшее решение! :)

...