studio programacion móviles libros extensions desarrollo desarrollar curso aprende aplicaciones android kotlin kotlin-android-extensions

móviles - manual de programacion android pdf



NullPointerException al intentar acceder a vistas en un fragmento de Kotlin (10)

Agregándolo a la respuesta de @Egor Neliuba, Sí, cada vez que llama a una vista sin referencia, kotlinex busca un rootView, y dado que está dentro de un fragmento y el fragmento no tiene el método getView() . Por lo tanto, podría arrojar NullPointerException

Hay dos formas de superar esto,

  • O anula onViewCreated() como se mencionó
  • O bien, si desea vincular vistas en otra clase (por ejemplo, anónima), simplemente puede crear una función de extensión como esta,

    fun View.bindViews(){...}

El segundo enfoque es útil cuando tiene un solo fragmento con múltiples comportamientos.

¿Cómo usar Kotlin Android Extensions con Fragment s? Si los uso dentro de onCreateView() , obtengo esta excepción NullPointerException :

Causado por: java.lang.NullPointerException: intento de invocar el método virtual ''android.view.View android.view.View.findViewById (int)'' en una referencia de objeto nulo

Aquí está el código de fragmento:

package com.obaied.testrun.Fragment import android.os.Bundle import android.support.v4.app.Fragment import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.obaied.acaan.R import kotlinx.android.synthetic.main.fragment_card_selector.* public class CardSelectorFragment : Fragment() { val TAG = javaClass.canonicalName companion object { fun newInstance(): CardSelectorFragment { return CardSelectorFragment() } } override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? { var rootView = inflater?.inflate(R.layout.fragment_card_selector, container, false) btn_K.setOnClickListener { Log.d(TAG, "onViewCreated(): hello world"); } return rootView } } `


En Fragments, escriba su código en onActivityCreated: -

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { super.onCreateView(inflater, container, savedInstanceState) return inflater.inflate(R.layout.login_activity, container, false) } override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) callbackManager = CallbackManager.Factory.create() initialization() onClickLogin() onClickForgot() onClickSocailLogIn() }


En mi caso, nada funcionó hasta que seguí el consejo de en los comentarios. Limpiar, reconstruir (no es necesario reiniciar), vuelva a ejecutar la aplicación. Tampoco necesitaba onActivityCreated y solo onCreateView hizo el truco.

Una vez también cometí el error de inflar el diseño incorrecto, por lo que obviamente no obtuve los controles esperados.


Está llamando a este btn_K demasiado pronto ya que en ese momento devuelve un valor nulo y le está dando una excepción de puntero nulo.

Puede usar estas vistas mediante este complemento sintético en el método onActivityCreated() que se llama justo después de onCreateView() del ciclo de vida de Fragment.

onActivityCreated() { super.onActivityCreated(savedInstanceState) btn_K.setOnClickListener{} }


Las propiedades sintéticas de Kotlin no son mágicas y funcionan de una manera muy simple. Cuando accede a btn_K , llama a getView().findViewById(R.id.btn_K) .

El problema es que está accediendo demasiado pronto. getView() devuelve null en onCreateView . Intenta hacerlo en el método onViewCreated :

override fun onViewCreated(view: View, savedInstanceState: Bundle?) { btn_K.setOnClickListener { Log.d(TAG, "onViewCreated(): hello world"); } }


Las propiedades sintéticas de Kotlin no son mágicas y funcionan de una manera muy simple. Cuando accede a btn_K, llama a getView().findViewById(R.id.btn_K) .

override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { if (mRootView == null) { mRootView = inflater.inflate(R.layout.fragment_profile, container, false) } return mRootView }

Entonces, si está utilizando devoluciones de llamada de interfaces, obtendrá NPE porque la vista no estará disponible en este momento -> debe anular el método getView()

override fun getView(): View? { return mRootView }

y siempre use sus vistas en onViewCreated()

if (mCreatedView == null) { mCreatedView = view btn_K.setOnClickListener{ //------------do something } }


Las propiedades sintéticas generadas por el complemento Kotlin Android Extensions necesitan una view para que Fragment/Activity se configure de antemano.

En su caso, para Fragment , debe usar view.btn_K en onViewCreated

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { super.onCreateView(inflater, container, savedInstanceState) val view = inflater.inflate(R.layout.fragment_card_selector, container, false) view.btn_K.setOnClickListener{} // access with `view` return view }

O mejor, solo debe acceder a las propiedades sintéticas en onViewCreated

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { super.onCreateView(inflater, container, savedInstanceState) return inflater.inflate(R.layout.fragment_card_selector, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) btn_K.setOnClickListener{} // access without `view` }

Tenga en cuenta que el parámetro savedInstanceState debe ser nulo Bundle? y también marque Importar propiedades sintéticas

Es conveniente importar todas las propiedades del widget para un diseño específico de una sola vez:

import kotlinx.android.synthetic.main.<layout>.*

Por lo tanto, si el nombre del archivo de diseño es activity_main.xml, importaríamos kotlinx.android.synthetic.main.activity_main.*.

Si queremos llamar a las propiedades sintéticas en View, también deberíamos importar kotlinx.android.synthetic.main.activity_main.view.*.


lo único que debes hacer es:

override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? { var rootView = inflater?.inflate(R.layout.fragment_card_selector, container, false) rootView.btn_K.setOnClickListener { Log.d(TAG, "onViewCreated(): hello world"); } return rootView }


no es necesario definir un objeto complementario, solo llame a cada id por una vista como

lateinit var mView: View override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { mView=inflater.inflate(R.layout.product_list,container,false) mView.addProduct.setOnClickListener { val intent=Intent(activity,ProductAddActivity::class.java) startActivity(intent) } return mView }


class CardSelectorFragment : Fragment() { val TAG = javaClass.canonicalName companion object { fun newInstance(): CardSelectorFragment { return CardSelectorFragment() } } override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? { var rootView = inflater?.inflate(R.layout.fragment_card_selector, container, false) rootView?.findViewById<TextView>(R.id.mTextView)?.setOnClickListener{ Log.d(TAG, "onViewCreated(): hello world"); } //btn_K.setOnClickListener { Log.d(TAG, "onViewCreated(): hello world"); } return rootView }

}

** Aquí está utilizando btn_K.setOnClickListener antes de encontrar -Debe encontrar el elemento xml en su código java / kotlin utilizando findViewById y luego solo puede realizar la operación en esa vista o elemento.

-Así que es por eso que tienes puntero nulo

** **