在下拉模式下单击展开时微调器崩溃但在对话框模式下工作(仅在 API < 26 时)

Spinner crashes when clicked to expand in dropdown mode but works in dialog mode (only in API < 26)

我在 Android 中的 Spinner 有问题。

点击展开时崩溃。只有当它处于 Dropdown 模式(Dialog 模式工作正常)并且应用程序在 API 低于 26 的设备上 运行 时才会发生。使用微调器在片段内打开的弹出窗口中。

我得到这个异常:

android.view.WindowManager$BadTokenException: Unable to add window -- token android.view.ViewRootImpl$W@4dc3e2a is not valid; is your activity running?

我已经检查了弹出窗口中的上下文是否为空,但它不是。

这是我的弹出窗口代码:

 private fun entryFunction(toChangeEntry: Entry?) {

    val view = inflater.inflate(R.layout.add_entry_popup, calendarLayout, false)

    val popupWindow = PopupWindow(
        view, ConstraintLayout.LayoutParams.MATCH_PARENT,
        ConstraintLayout.LayoutParams.WRAP_CONTENT, true
    )

    popupWindow.elevation = 10.0F

    val slideIn = Slide()
    slideIn.slideEdge = Gravity.START
    popupWindow.enterTransition = slideIn

    val slideOut = Slide()
    slideOut.slideEdge = Gravity.END
    popupWindow.exitTransition = slideOut

    val et = view.findViewById<EditText>(R.id.mahlzeitEditText)
    val cancelBtn = view.findViewById<Button>(R.id.cancelButton)
    val okBtn = view.findViewById<Button>(R.id.okButton)
    val rb = view.findViewById<RatingBar>(R.id.ratingBar)
    val deleteBtn = view.findViewById<ImageButton>(R.id.deleteButton)

    val spinner = view.findViewById<Spinner>(R.id.mealtype_spinner)

    //Fehler wegen dropdown spinner (dialog funktioniert)

    ArrayAdapter.createFromResource(
        view.context,
        R.array.mealtypeStringArray, android.R.layout.simple_spinner_dropdown_item
    ).also { spinnerAdapter ->
        spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
        spinner.adapter = spinnerAdapter
    }

    val day = view.findViewById<EditText>(R.id.dayEditText)
    val month = view.findViewById<EditText>(R.id.monthEditText)
    val year = view.findViewById<EditText>(R.id.yearEditText)

    val cal = Calendar.getInstance()

    if (toChangeEntry != null) {
        et.setText(toChangeEntry.meal)
        rb.rating = toChangeEntry.rating.toFloat()
        spinner.setSelection(toChangeEntry.mealType)
        cal.timeInMillis = toChangeEntry.date

        deleteBtn.setOnClickListener { deleteEntry(toChangeEntry, popupWindow) }
    } else deleteBtn.visibility = View.GONE

    day.setText(dayFormatter.format(cal.time))
    month.setText(monthFormatter.format(cal.time))
    year.setText(yearFormatter.format(cal.time))

    val clickListener = View.OnClickListener {
        cal.clear()

        if (day.text.toString().toInt() <= 31 && month.text.toString().toInt() <= 12) {
            cal[Calendar.DAY_OF_MONTH] = day.text.toString().toInt()
            cal[Calendar.MONTH] = month.text.toString().toInt() - 1
            cal[Calendar.YEAR] = year.text.toString().toInt()

            if (toChangeEntry != null) editEntry(
                toChangeEntry, cal.timeInMillis,
                et.text.toString(), rb.rating.toInt(), spinner.selectedItemPosition, popupWindow)
            else createEntry(
                cal.timeInMillis, et.text.toString(),
                rb.rating.toInt(), spinner.selectedItemPosition, popupWindow)
        } else if (view != null) Toast.makeText(view.context, R.string.checkDate, Toast.LENGTH_LONG).show()
    }

    val editorListener = TextView.OnEditorActionListener { _, actionID, _ ->
        if (actionID == EditorInfo.IME_ACTION_DONE) {
            cal.clear()

            if (day.text.toString().toInt() <= 31 && month.text.toString().toInt() <= 12) {
                cal[Calendar.DAY_OF_MONTH] = day.text.toString().toInt()
                cal[Calendar.MONTH] = month.text.toString().toInt() - 1
                cal[Calendar.YEAR] = year.text.toString().toInt()

                if (toChangeEntry != null) editEntry(
                    toChangeEntry, cal.timeInMillis,
                    et.text.toString(), rb.rating.toInt(), spinner.selectedItemPosition, popupWindow)
                else createEntry(
                    cal.timeInMillis, et.text.toString(),
                    rb.rating.toInt(), spinner.selectedItemPosition, popupWindow)
            } else if (view != null) Toast.makeText(view.context, R.string.checkDate, Toast.LENGTH_LONG).show()

            true
        } else false
    }

    okBtn.setOnClickListener(clickListener)
    et.setOnEditorActionListener(editorListener)
    day.setOnEditorActionListener(editorListener)
    month.setOnEditorActionListener(editorListener)
    year.setOnEditorActionListener(editorListener)

    cancelBtn.setOnClickListener {
        popupWindow.dismiss()
    }

    day.addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(text: Editable?) {
            if (text?.length == 2) {
                month.requestFocus()
                month.setSelection(month.length())
            }
        }

        override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
        override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
    })

    month.addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(text: Editable?) {
            if (text?.length == 2) {
                year.requestFocus()
                year.setSelection(year.length())
            }
        }

        override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
        override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
    })

    TransitionManager.beginDelayedTransition(calendarLayout)
    popupWindow.showAtLocation(calendarLayout, Gravity.CENTER, 0, 0)

    et.requestFocus()
    imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY)

    popupWindow.setOnDismissListener {
        imm.hideSoftInputFromWindow(view.windowToken, 0)
    }
}

这就是它使用的片段:

class CalendarFragment : Fragment() , AdapterView.OnItemSelectedListener {

private lateinit var viewAdapter: RecyclerView.Adapter<*>
private lateinit var viewManager: RecyclerView.LayoutManager
private lateinit var inflater: LayoutInflater
private lateinit var imm: InputMethodManager
private lateinit var calendarLayout: ConstraintLayout
private lateinit var recycler: RecyclerView

private var entryList = ArrayList<Entry>()

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    return inflater.inflate(R.layout.calendar_fragment_layout, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

    if (activity != null) {
        inflater = layoutInflater
        imm = activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        calendarLayout = view.findViewById(R.id.calendar_fragment_layout)
        recycler = view.findViewById(R.id.scrollCalendar)!!
        setUpAdapter()
}

这是弹出窗口 xml:

android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:background="#a4aebf">

<RatingBar
        android:id="@+id/ratingBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:rating="3"
        android:stepSize="1"
        android:isIndicator="false"
        android:layout_marginStart="5dp"
        android:layout_marginTop="5dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/mahlzeitTextView"
        style="@android:style/Widget.Material.RatingBar.Indicator"
/>

<ImageButton
        android:id="@+id/deleteButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="10dp"
        android:layout_marginTop="10dp"
        android:src="@drawable/delete_icon"
        android:background="@android:color/transparent"
        android:contentDescription="@string/delete"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
/>

<TextView
        android:id="@+id/mahlzeitTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:layout_marginStart="10dp"
        android:text="@string/foodNameRequest"
        app:layout_constraintTop_toBottomOf="@id/ratingBar"
        app:layout_constraintStart_toStartOf="parent"
/>

<EditText
        android:id="@+id/mahlzeitEditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:layout_marginEnd="10dp"
        android:hint="@string/mahlzeit"
        android:inputType="textImeMultiLine"
        android:imeOptions="actionDone"
        app:layout_constraintTop_toBottomOf="@id/mahlzeitTextView"
        app:layout_constraintStart_toStartOf="@id/mahlzeitTextView"
        app:layout_constraintEnd_toEndOf="parent"
/>

<EditText
        android:id="@+id/dayEditText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:maxLength="2"
        android:inputType="number"
        android:hint="@string/two0"
        app:layout_constraintTop_toBottomOf="@id/mahlzeitEditText"
        app:layout_constraintStart_toStartOf="parent"
/>

<EditText
        android:id="@+id/monthEditText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:maxLength="2"
        android:inputType="number"
        android:hint="@string/two0"
        app:layout_constraintTop_toBottomOf="@id/mahlzeitEditText"
        app:layout_constraintStart_toEndOf="@id/dayEditText"
/>

<Spinner
        android:id="@+id/mealtype_spinner"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_marginEnd="10dp"
        android:spinnerMode="dropdown"
        android:gravity="end"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/mahlzeitEditText"
/>

<EditText
        android:id="@+id/yearEditText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:maxLength="4"
        android:inputType="number"
        android:hint="@string/four0"
        app:layout_constraintTop_toBottomOf="@id/mahlzeitEditText"
        app:layout_constraintStart_toEndOf="@id/monthEditText"
/>

<Button
        android:id="@+id/cancelButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:text="@string/cancleButton"
        android:background="@android:color/transparent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/dayEditText"
/>

<Button
        android:id="@+id/okButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="10dp"
        android:text="@string/OK"
        android:background="@android:color/transparent"
        app:layout_constraintTop_toBottomOf="@id/dayEditText"
        app:layout_constraintEnd_toEndOf="parent"
/>

我已经看过类似的问题,但仍然无法正常工作。

更新: 我试图获取我的 PopupWindow 的 Windowtoken 并通过调用 Log.d() 打印它:

Log.d("debugLog", view.windowToken.toString())

我的应用程序因为这个带有 NullPointerException 的调用而崩溃:

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference

我不知道这是否与我的问题有关,但我希望它能有所帮助。

显然,如果 API 低于 26,则不可能在弹出窗口中设置 Spinner,并且 Spinner 模式设置为下拉。