Search code examples
androidkotlinandroid-spinnerpopupwindow

Dropdown spinner in PopUp window in fragment keeps crashing the app


I am creating a filter inside a map fragment and therefore I need a popUp window, where the user can set the filters. Inside the popUp window I want to add a dropdown spinner, but every time I click on the spinner the app crashes and I get this error:

2021-02-18 15:13:58.162 31233-31233/com.example.discoverme E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.discoverme, PID: 31233
    android.view.WindowManager$BadTokenException: Unable to add window -- token android.view.ViewRootImpl$WEx@6667b18 is not valid; is your activity running?
        at android.view.ViewRootImpl.setView(ViewRootImpl.java:702)
        at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:342)
        at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:94)
        at android.widget.PopupWindow.invokePopup(PopupWindow.java:1391)
        at android.widget.PopupWindow.showAsDropDown(PopupWindow.java:1247)
        at androidx.appcompat.widget.AppCompatPopupWindow.showAsDropDown(AppCompatPopupWindow.java:77)
        at androidx.core.widget.PopupWindowCompat.showAsDropDown(PopupWindowCompat.java:69)
        at androidx.appcompat.widget.ListPopupWindow.show(ListPopupWindow.java:754)
        at androidx.appcompat.widget.AppCompatSpinner$DropdownPopup.show(AppCompatSpinner.java:1050)
        at androidx.appcompat.widget.AppCompatSpinner.showPopup(AppCompatSpinner.java:608)
        at androidx.appcompat.widget.AppCompatSpinner.performClick(AppCompatSpinner.java:452)
        at android.view.View$PerformClick.run(View.java:22433)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6247)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:872)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:762)

does somebody have an idea how to fix this?

I am calling the PopUp class in my maps fragment onCreate function like this:

val popupButton : Button= rootView.findViewById(R.id.filter_button);
       popupButton.setOnClickListener { v ->

           val popUpClass = PopUpClass()
           popUpClass.showPopupWindow(v)

           }

and this is the PopUp window class:

import android.annotation.SuppressLint
import android.content.Context
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.internal.ViewUtils.getContentView
import com.google.android.material.slider.RangeSlider


class PopUpClass {
    //PopupWindow display method
    @SuppressLint("ClickableViewAccessibility", "RestrictedApi", "InflateParams")
    fun showPopupWindow(view: View) {


        //Create a View object yourself through inflater
        val inflater =
            view.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        val popupView: View = inflater.inflate(R.layout.popup_layout, null)

        //val slider: RangeSlider = popupView.findViewById(R.id.slider)
        //slider.setValues(1.0f, 5.0f)

        val spinner: Spinner = popupView.findViewById(R.id.filter_spinner)

        getContentView(spinner)?.let {
            ArrayAdapter.createFromResource(
                it.getContext(),
                R.array.auswahl_filter,
                android.R.layout.simple_spinner_item
            ).also {  adapter ->
                // Specify the layout to use when the list of choices appears
                adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
                // Apply the adapter to the spinner
                spinner.adapter = adapter
                spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
                    override fun onItemSelected(
                        parent: AdapterView<*>?,
                        view: View?,
                        position: Int,
                        id: Long
                    ) {
                        val selectedItem = parent?.getItemAtPosition(position).toString()
                    }

                    override fun onNothingSelected(parent: AdapterView<*>?) {

                    }
                }
            }
        }


        //Specify the length and width through constants
        val width = LinearLayout.LayoutParams.MATCH_PARENT
        val height = LinearLayout.LayoutParams.MATCH_PARENT

        //Make Inactive Items Outside Of PopupWindow
        val focusable = true

        //Create a window with our parameters
        val popupWindow = PopupWindow(popupView, width, height, focusable)

        //Set the location of the window on the screen
        popupWindow.showAtLocation(view, Gravity.CENTER, 0, 0)

        //Initialize the elements of our window, install the handler
        val test2 = popupView.findViewById<TextView>(R.id.titleText)
        //test2.setText(R.string.textTitle)
        val buttonEdit = popupView.findViewById<Button>(R.id.messageButton)
        buttonEdit.setOnClickListener { //As an example, display the message
            Toast.makeText(view.context, "Wow, popup action button", Toast.LENGTH_SHORT).show()
        }


        //Handler for clicking on the inactive zone of the window
        popupView.setOnTouchListener { v, event -> //Close the window when clicked
            popupWindow.dismiss()
            true
        }
    }
}

and this the popUp.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:paddingLeft="10dp"
    android:paddingRight="10dp"
    android:gravity="center">

    <androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cardCornerRadius="5dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:padding="10dp">

            <TextView
                android:id="@+id/titleText"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:padding="10dp"
                android:text="Bearbeite deine Suche"
                android:textSize="20sp"
                android:textStyle="bold" />

            <Spinner
                android:id="@+id/filter_spinner"
                android:layout_width="match_parent"
                android:layout_height="51dp"
                android:layout_marginTop="20dp"
                android:spinnerMode="dropdown"/>


            <Button
                android:id="@+id/messageButton"
                android:layout_width="300dp"
                android:layout_height="wrap_content"
                android:layout_marginTop="80dp"
                android:text="Filter anwenden" />

        </LinearLayout>

    </androidx.cardview.widget.CardView>
</LinearLayout>

Solution

  • So, I fixed this by changing the getContentView(spinner)? to getConentView(view)? and adding android:spinnerMode="dialog" to the spinner in my xml.