选择Android Spinner会导致WindowManager $ BadTokenException

时间:2010-09-29 16:58:48

标签: android exception spinner

我创建了一个自定义AlertDialog来显示Spinner和一些EditText元素。当我选择菜单选项时,会启动此自定义AlertDialog。一切正常,直到我实际选择微调器来尝试选择一个项目,此时我得到了BadTokenException。我已经读过其他StackOverflow帖子,说类似的异常是尝试使用getApplicationContext()而不是传递Activity.this来显示diaglog的结果。我没有明确地将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,目标SDK为1.6。

2 个答案:

答案 0 :(得分:8)

  

我已经读过其他StackOverflow帖子说类似的异常是尝试使用getApplicationContext()显示diaglog而不是传递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 = getLayoutInflater();

答案 1 :(得分:2)

我在这个奇怪的问题上失去了很多时间,但最后我解决了如下问题。看看这段代码:

/**
 * 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);


}

Look spinner vs spinner2:spinner存在于一个膨胀的布局中(其根是一个ScrollView),spinner2是以编程方式创建的,这是一个Activity对象。

由于我无法更改spinner1上下文以与此上下文一致,最后我直接在此上下文中创建了一个新的Spinner。因此,当spinner2工作时,微调器不起作用。

PS:使用的布局inflater用于夸大许多其他布局:

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

PS2:Christopher提供的解决方案允许继续使用原始微调器,因此它是更好的解决方案! :)