点击Spinner时出现“无法添加窗口,令牌无效”错误

4
我有一个安卓应用程序,当从侧边栏中选择一个选项时,它会进入一个碎片,然后进入另一个具有可点击单选按钮的碎片。当单击这些按钮时,它将创建一个带有一些文本字段的弹出窗口。
基本上,流程如下:
活动-->碎片1-->碎片2-->弹出窗口
我在这个弹出窗口上有一个下拉菜单,但当我点击它以选择一个值时,它会抛出以下异常。我不明白为什么会发生这种情况。
Process: com.informaticsint.claimassistant, PID: 5045
android.view.WindowManager$BadTokenException: Unable to add window -- token android.view.ViewRootImpl$W@945936c is not valid; is your activity running?
    at android.view.ViewRootImpl.setView(ViewRootImpl.java:849)
    at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:337)
    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
    at android.widget.PopupWindow.invokePopup(PopupWindow.java:1329)
    at android.widget.PopupWindow.showAsDropDown(PopupWindow.java:1155)
    at android.widget.ListPopupWindow.show(ListPopupWindow.java:791)
    at android.widget.Spinner$DropdownPopup.show(Spinner.java:1366)
    at android.widget.Spinner.performClick(Spinner.java:828)
    at android.view.View$PerformClick.run(View.java:22526)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:158)
    at android.app.ActivityThread.main(ActivityThread.java:7224)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

这是导致问题的Spinner代码,位于下面提到的AssignmentDetailsActivity类中的showDamagedItemEntryPopup()方法中。
    statusSpinner = (Spinner)popupView.findViewById(R.id.popup_status_spinner);
    ArrayAdapter<String> statusSpinnerArrayAdapter = new ArrayAdapter<String>(AssignmentDetailsActivity.this, android.R.layout.simple_spinner_item, statusSpinnerArray);
    statusSpinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    statusSpinner.setAdapter(statusSpinnerArrayAdapter);

这是我在AssignmentDetailsActivity类中创建弹出窗口的方法。

public void showDamagedItemEntryPopup(RadioButton radioButton, View view){

    LayoutInflater layoutInflater = (LayoutInflater)getBaseContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    View popupView = layoutInflater.inflate(R.layout.component_selection_popup, null);

    final PopupWindow popupWindow = new PopupWindow(
            popupView,
            ViewGroup.LayoutParams.WRAP_CONTENT,
            ViewGroup.LayoutParams.WRAP_CONTENT);

    // Set popup Animation style
    popupWindow.setAnimationStyle(R.style.popupAnimation);

    Button buttonClose = (Button)popupView.findViewById(R.id.close_add_component_btn);

    // Close button damaged item popop window
    buttonClose.setOnClickListener(new Button.OnClickListener(){

        @Override
        public void onClick(View v) {
            popupWindow.dismiss();
        }
    });

    originalAmount = (EditText)popupView.findViewById(R.id.popup_add_component_original_amount);
    customerContribution = (EditText)popupView.findViewById(R.id.popup_percentage);
    quantity = (EditText)popupView.findViewById(R.id.popup_quantity);
    finalAmount = (EditText)popupView.findViewById(R.id.popup_add_component_final_amount);
    remarks = (EditText)popupView.findViewById(R.id.popup_add_component_remarks);

    // Item Spinner
    itemSpinnerArray = new ArrayList<String>();
    itemSpinnerArray.add("Select Item");

    // Status Spinner
    ArrayList<String> statusSpinnerArray = new ArrayList<String>();
    statusSpinnerArray.add("FDR");
    statusSpinnerArray.add("DR");
    statusSpinnerArray.add("SP");

    damageComponenetAutoCompleteTextview = (AutoCompleteTextView) popupView.findViewById(R.id.popup_damage_component_item);
    damageComponenetAutoCompleteTextview.requestFocus();
    ArrayAdapter<String> itemSpinnerArrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, itemSpinnerArray);
    damageComponenetAutoCompleteTextview.setThreshold(1);
    damageComponenetAutoCompleteTextview.setAdapter(itemSpinnerArrayAdapter);

    damageComponenetAutoCompleteTextview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            itemSpinnerValue = (String) parent.getItemAtPosition(position);
            Log.d("SK-->", "----------------------------------------------------------");
            Log.d("SK-->","itemSpinnerValue: " + itemSpinnerValue);
        }
    });

    statusSpinner = (Spinner)popupView.findViewById(R.id.popup_status_spinner);
    ArrayAdapter<String> statusSpinnerArrayAdapter = new ArrayAdapter<String>(AssignmentDetailsActivity.this, android.R.layout.simple_spinner_item, statusSpinnerArray);
    statusSpinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    statusSpinner.setAdapter(statusSpinnerArrayAdapter);

    //Creating a text Watcher
    TextWatcher textWatcher = new TextWatcher() {

        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

        }

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

        }

        @Override
        public void afterTextChanged(Editable editable) {
            //here, after we introduced something in the EditText we get the string from it
            //String answerString = originalAmount.getText().toString();

            if (originalAmount.getText().toString().trim().equals("") || customerContribution.getText().toString().trim().equals("")
                    || quantity.getText().toString().trim().equals("")) {

                // Error , one or more editText are empty

            }
            else
            {
                calculateFinalAmount();
            }

            //and now we make a Toast
            //modify "yourActivity.this" with your activity name .this
            //Toast.makeText(yourActivity.this,"The string from EditText is: "+answerString,0).show();

        }
    };

    // Adding Text Watcher to our text boxes
    originalAmount.addTextChangedListener(textWatcher);
    customerContribution.addTextChangedListener(textWatcher);
    quantity.addTextChangedListener(textWatcher);

    // Show the popup
    popupWindow.showAtLocation(view, Gravity.CENTER, 0, 0);

}


public void onSaveItem(View view) {

    statusSpinnerValue = (String) statusSpinner.getItemAtPosition(statusSpinner.getSelectedItemPosition());

    statusSpinnerValue = "ABC";
    itemSpinnerValue = "TEST ITEM";
    originalAmount.setText("50");
    customerContribution.setText("25");
    quantity.setText("1");

    if(itemSpinnerValue.matches("Select Item") ||itemSpinnerValue.matches("") || statusSpinnerValue.matches("") || originalAmount.getText().toString().matches("") || customerContribution.getText().toString().matches("") ||
            quantity.getText().toString().matches("")){

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("ERROR!");
        builder.setMessage("Please Fill the Required Fields.")
                .setCancelable(false)
                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        //do things
                        dialog.dismiss();
                    }
                });
        AlertDialog alert = builder.create();
        alert.show();

    }
    else{

        Log.e("TEST", "Check Passed");

        Date date = new Date();

        if(mDbHandler.itemAlreadyExist(reportID,"item_name", itemSpinnerValue, "DamageComponent") == false){

            mDbHandler.addDamageComponent(reportID, itemSpinnerValue, statusSpinnerValue, originalAmount.getText().toString(), Double.parseDouble(customerContribution.getText().toString()),
                    Integer.parseInt(quantity.getText().toString()), finalAmount.getText().toString(), remarks.getText().toString());

            mDbHandler.updateReport(reportID, date.toString(), "time_last_modified");

            Toast.makeText(this,"Component Successfully Added",Toast.LENGTH_SHORT).show();

        }
        else{
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("ERROR!");
            builder.setMessage("Item Already Exist.")
                    .setCancelable(false)
                    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            //do things
                            dialog.dismiss();
                        }
                    });
            AlertDialog alert = builder.create();
            alert.show();
        }

        mDbHandler.close();
    }

}
2个回答

8

我花了两天时间解决完全相同的问题 :(

我找到的唯一解决方法是在对话框模式下使用旋转器(spinner)

android:spinnerMode="dialog"

我也浪费了很多时间在这上面。所以我只能将屏幕带到另一个片段,而不是在弹出窗口中显示它。很高兴至少对你有用。 - k9yosh

1
很高兴再次为您服务,请查看this问题的答案。您显示弹出窗口过早,因此需要像这样延迟运行。
 view.post(new Runnable() {
   public void run() {
     popupWindow.showAtLocation(view, Gravity.CENTER, 0, 0);
   }
});

更新:

或尝试

new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
    @Override
    public void run() {
        popupWindow.showAtLocation(view, Gravity.CENTER, 0, 0);
    }
}, 1000); //Delay one second

@k9yosh 请看我的更新,尝试增加延迟时间直到它起作用。 - Shree Krishna
我会尝试并回复您。 - k9yosh
无法使用该代码,提示Handler类是一个抽象类。当我实现必要的方法来解决这个问题时,它说Handler()在Handler中不能应用于(android.os.Looper)。 - k9yosh
顺便说一句,我不认为这是我的问题。我的PopupWindow正常工作。Spinner条目也被正确地提供给了Spinner。(可以在下拉菜单中看到项目)。我不太确定设置Spinner数组适配器的那一行代码。我在那里设置的上下文可能是错误的。我尝试了不同的方法,但都没有起作用。 - k9yosh
但它不起作用,我将延迟增加到10秒。仍然没有反应。请查看我的先前(长)评论。希望您能从中得到线索。 - k9yosh
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接