Я работаю над приложением с макетом вкладок, где пользовательский интерфейс с различными функциями из разных фрагментов. Приведение в действие слушателей кнопки onClick вызывает у меня проблемы и некоторое замешательство. У меня есть фрагмент, в котором есть несколько числовых входов как EditText и кнопки, которые активируют методы (теоретически). Я хочу реализовать простую кнопку, которая просто сбрасывает значение во вводе числа на 1. Я думал, что это переопределение onClick() сработало бы в файле фрагмента .kt:

class RatioFragment : Fragment(), View.OnClickListener {
    private var param1: String? = null
    private var param2: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            param1 = it.getString(ARG_PARAM1)
            param2 = it.getString(ARG_PARAM2)
        }
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment_ratio, container, false)
        val offsetResetButton: Button = view.findViewById(R.id.offsetResetButton)
        offsetResetButton.setOnClickListener(this)
        return view
    }

    companion object {
        @JvmStatic
        fun newInstance(param1: String, param2: String) =
                RatioFragment().apply {
                    arguments = Bundle().apply {
                        putString(ARG_PARAM1, param1)
                        putString(ARG_PARAM2, param2)
                    }
                }
    }


    override fun onClick(view: View?) {
        when (view?.id) {
            R.id.offsetResetButton -> {
                hideKeyboard()
                offsetNum = 1
                offsetDen = 1
                view.findViewById<EditText>(R.id.offsetNum).setText("1")
                view.findViewById<EditText>(R.id.offsetDen).setText("1")
            }
        }
    }


}

Но приложение вылетает, когда я нажимаю кнопку offsetResetButton. var s offsetNum и offsetDen взяты из других частей проекта, но кажется, что попытка доступа к двум моим редактированным текстам и установка нового текста вызывает проблемы. В частности, я получаю сообщение об ошибке

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.EditText.setText(java.lang.CharSequence)' on a null object reference

Интересно, что здесь не так, или есть лучший способ сделать это.

1
Thomas Nicholson 27 Фев 2021 в 22:54

2 ответа

Лучший ответ

Как сказал @Ben P., вы пытаетесь получить доступ к EditText из кнопки, которая вызывает исключение вы можете изменить свой код, чтобы иметь доступ к EditText из onClick с помощью findViewById (), используйте requireView() вместо просмотра в onClickListener.

Вот код

class RatioFragment : Fragment(), View.OnClickListener {
    private var param1: String? = null
    private var param2: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            param1 = it.getString(ARG_PARAM1)
            param2 = it.getString(ARG_PARAM2)
        }
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment_ratio, container, false)
        val offsetResetButton: Button = view.findViewById(R.id.offsetResetButton)
        offsetResetButton.setOnClickListener(this)
        return view
    }

    companion object {
        @JvmStatic
        fun newInstance(param1: String, param2: String) =
                RatioFragment().apply {
                    arguments = Bundle().apply {
                        putString(ARG_PARAM1, param1)
                        putString(ARG_PARAM2, param2)
                    }
                }
    }


    override fun onClick(view: View?) {
        when (view?.id) {
            R.id.offsetResetButton -> {
                hideKeyboard()
                offsetNum = 1
                offsetDen = 1
                requireView().findViewById<EditText>(R.id.offsetNum).setText("1")
                requireView().findViewById<EditText>(R.id.offsetDen).setText("1")
            }
        }
    }
}
0
Shay Kin 27 Фев 2021 в 20:49

Я думаю, вы запутались из-за переменного затенения. Обычно в Fragment с Kotlin view будет относиться к любому представлению, которое вы вернули из onCreateView(), что, вероятно, включает EditText, которые вы ищете. Однако ваша реализация onClick() называет его параметр view, поэтому view.findViewById() будет сканировать только иерархию представления, на которое был выполнен щелчок.

override fun onClick(view: View?) {
    // ...
    // these only search within the parameter view, i.e. a Button
    view.findViewById<EditText>(R.id.offsetNum).setText("1")
    view.findViewById<EditText>(R.id.offsetDen).setText("1")
}

Измените свою подпись onClick(), чтобы использовать другое имя параметра:

override fun onClick(v: View?) {
    // ...
    // these now search the entire fragment hierarchy
    view.findViewById<EditText>(R.id.offsetNum).setText("1")
    view.findViewById<EditText>(R.id.offsetDen).setText("1")
}

Не имеет отношения, но я рекомендую не внедрять View.OnClickListener в свои фрагменты / действия. Скорее просто используйте лямбду при установке прослушивателя кликов:

val offsetResetButton: Button = view.findViewById(R.id.offsetResetButton)
offsetResetButton.setOnClickListener { onOffsetResetClick() }
private fun onOffsetResetClick() {
    // your code here
}

Когда вы делаете это таким образом, вам не нужно беспокоиться о when(view.id) или чем-то подобном, потому что вы знаете, что метод может быть вызван только щелчком по одной конкретной кнопке.

2
Ben P. 27 Фев 2021 в 20:10