web-dev-qa-db-fra.com

NullPointerException lors de la tentative d'accès à des vues d'un fragment Kotlin

Comment utiliser les extensions Android Kotlin avec Fragments? Si je les utilise dans onCreateView(), j'obtiens cette exception NullPointerException

Causée par: Java.lang.NullPointerException: tente d'appeler virtual méthode 'Android.view.View Android.view.View.findViewById (int)' sur un référence d'objet null

Voici le code de fragment: 

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
    }
}
`
156
Solidak

Les propriétés synthétiques de Kotlin ne sont pas magiques et fonctionnent de manière très simple. Lorsque vous accédez à btn_K, il appelle getView().findViewById(R.id.btn_K).

Le problème est que vous y accédez trop tôt. getView() renvoie null en onCreateView. Essayez de le faire avec la méthode onViewCreated:

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

Vous appelez ce btn_K trop tôt car à ce moment-là, il renvoie une valeur null et vous donne une exception de pointeur nul. 

Vous pouvez utiliser ces vues avec ce plugin synthétique dans la méthode onActivityCreated() qui est appelée juste après onCreateView() du cycle de vie du fragment.

onActivityCreated()
{
        super.onActivityCreated(savedInstanceState)
        btn_K.setOnClickListener{}
}
5
Kashish luthra

la seule chose à faire est de:

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
}
3
Rhusfer

pas besoin de définir un objet compagnon, il suffit d'appeler chaque identifiant par une vue comme

 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
}
3
Rahul ShaRma

Les propriétés synthétiques générées par le plug-in Kotlin Android Extensions nécessitent la définition d'une view pour Fragment/Activity.

Dans votre cas, pour Fragment, vous devez utiliser view.btn_K dans 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
}

Ou mieux, vous ne devriez accéder aux propriétés synthétiques que dans 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`
}

Veuillez noter que le paramètre savedInstanceState devrait avoir la valeur nullable Bundle? et également cocher Importer des propriétés synthétiques

Il est pratique d’importer toutes les propriétés du widget pour une présentation spécifique en une fois:

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

Ainsi, si le fichier de mise en page est activity_main.xml, nous importerions kotlinx.Android.synthetic.main.activity_main.*.

Si nous voulons appeler les propriétés synthétiques sur View, nous devrions également importer kotlinx.Android.synthetic.main.activity_main.view.*.

2
onmyway133

Dans Fragments, veuillez écrire votre code dans 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()

  }
1
abhilasha Yadav

Les propriétés synthétiques de Kotlin ne sont pas magiques et fonctionnent de manière très simple. Lorsque vous accédez à btn_K, il appelle 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
}

soo, si vous utilisez des rappels d’interface, vous obtiendrez NPE car la vue ne sera pas disponible pour le moment -> vous devez remplacer la méthode getView()

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

et utilisez toujours vos vues dans onViewCreated()

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

Dans mon cas, rien n'a fonctionné jusqu'à ce que j'ai suivi les conseils de Otziii dans les commentaires. Nettoyer, reconstruire (pas de redémarrage nécessaire), réexécuter l'application. Je n'avais pas non plus besoin d'aller avec onActivityCreated et juste onCreateView a fait l'affaire.

Une fois, j’ai également commis l’erreur de gonfler une mauvaise mise en page et de ne pas obtenir les contrôles attendus de toute évidence.

0
ZzZombo

En l'ajoutant à la réponse de @Egor Neliuba, Oui, chaque fois que vous appelez une vue sans référence, kotlinex recherche un rootView et, puisque vous êtes à l'intérieur d'un fragment, ce dernier n'a pas de méthode getView(). Par conséquent, il pourrait lancer NullPointerException

Il y a deux façons de surmonter cela,

  • Soit vous remplacez onViewCreated() comme mentionné
  • Ou si vous souhaitez lier des vues dans une autre classe (par exemple, anonyme), vous pouvez simplement créer une fonction d'extension comme celle-ci,

    fun View.bindViews(){...}

La deuxième approche est utile lorsque vous avez un seul fragment avec plusieurs comportements.

0
Aziz