4

I have an android application when clicked on an option from a side bar it goes to a fragment, and then into another fragment which has clickable radio buttons. When clicked on these it will create a popup window with some text fields in it.

Basically this is how the flow goes,

Activity --> Fragment 1 --> Fragment 2 --> PopupWindow

And i have a spinner on this PopupWindow, but when i click on it to select a value it throws the following exception. I don't understand why this happen.

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)

This is the Spinner code that cause the problem. Which is in the below mentioned AssignmentDetailsActivity class, showDamagedItemEntryPopup() method

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

This is my method that creates the popup which is in my AssignmentDetailsActivity class

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();
    }

}
k9yosh
  • 858
  • 1
  • 11
  • 31

2 Answers2

7

Spent 2 days for exactly the same problem :(

The only workaround I find is to use spinner in dialog mode

android:spinnerMode="dialog"
Nick Moskalenko
  • 941
  • 9
  • 10
  • I wasted lot of time with this too. So all i could do was just take the screen to another fragment instead of showing it in a popup. Glad at least something worked for you. – k9yosh Jan 19 '17 at 09:19
1

Glad to help you again, Have a look at this question's answers. You are showing popup too early so that you need to delay the run like this

 view.post(new Runnable() {
   public void run() {
     popupWindow.showAtLocation(view, Gravity.CENTER, 0, 0);
   }
});

UPDATE :

OR try

new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
    @Override
    public void run() {
        popupWindow.showAtLocation(view, Gravity.CENTER, 0, 0);
    }
}, 1000); //Delay one second
Community
  • 1
  • 1
Shree Krishna
  • 8,474
  • 6
  • 40
  • 68
  • @k9yosh See my update, Try increasing the delay time till it works, – Shree Krishna Apr 25 '16 at 10:50
  • i will try that and get back to you – k9yosh Apr 25 '16 at 10:54
  • Cannot use that code, Says the Handler class is an Abstract class and when i implement the necessary method to resolve that, it says Handler() in Handler cannot be applied to (android.os.Looper) – k9yosh Apr 25 '16 at 11:05
  • BTW, i don't think this is the problem in my case. I mean my PopupWindow works properly. And the Spinner entries are fed to the Spinner properly. (Items can be seen in the spinner drop down). i'm not quite sure about the line where i set the Spinner Array Adapter. The context i'm setting there could be wrong. I tried different methods but nothing worked for me. – k9yosh Apr 25 '16 at 11:11
  • Sorry yeah it is fine, i was using the wrong Handler Package :) – k9yosh Apr 25 '16 at 11:22
  • But it doesn't work, i increased the delay to 10 seconds. Still nothing. Take a look at my previous (long) comment. Hope you can get a lead with this – k9yosh Apr 25 '16 at 11:25
  • All the items shown in spinner, Then only after that the code crashes or after some event like you choose an item, Or something else, Which line did the compiler pointed as cause of the error actually ? And another thing is If you were unable to add handler, It's better using runOnUiThread like shown in [this answer](http://stackoverflow.com/a/16886486/5067493). I'll be back on this after several hours. – Shree Krishna Apr 25 '16 at 11:32
  • It is possible to think that all the items are shown in the Spinner because when i change the first one it shows the change. Problem is i cant click on the spinner to view the drop down, that's where the app crash. (It crashes the moment i click on the Spinner) And the compiler doesn't point to any line. It just gives the above mentioned error. – k9yosh Apr 25 '16 at 11:39
  • Try adding `setOnItemSelectedListener` in `statusSpinner`, And another thing is what happens if `onSaveItem` method fired without tapping to spinner currently? – Shree Krishna Apr 26 '16 at 05:00
  • I tried adding that. Didn't work. Currently i bypass everything and pass some test values to these variables. And it saves successfully. – k9yosh Apr 26 '16 at 05:39
  • @k9yosh See [this](http://stackoverflow.com/a/7631687/5067493) answer, Its very similar to yours. The Edit Section changed setContentView by inflating the layout. – Shree Krishna Apr 26 '16 at 05:47