wake-up-neo.com

NullPointerException beim Versuch, auf Ansichten in einem Kotlin-Fragment zuzugreifen

Wie verwende ich Kotlin Android Extensions mit Fragments? Wenn ich sie in onCreateView() verwende, erhalte ich diese NullPointerException-Ausnahme: 

Verursacht durch: Java.lang.NullPointerException: Versuch, die virtuelle .__ aufzurufen. Methode 'Android.view.View Android.view.View.findViewById (int)' auf einem NULL-Objektreferenz

Hier ist der Fragmentcode: 

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

Kotlins synthetische Eigenschaften sind keine Zauberei und funktionieren auf sehr einfache Weise. Wenn Sie auf btn_K zugreifen, wird getView().findViewById(R.id.btn_K) aufgerufen.

Das Problem ist, dass Sie zu früh darauf zugreifen. getView() gibt null in onCreateView zurück. Versuchen Sie es mit der onViewCreated-Methode:

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

Sie rufen diesen btn_K zu früh auf, da zu diesem Zeitpunkt eine Null zurückgegeben wird und Sie eine Nullzeiger-Ausnahme erhalten. 

Sie können diese Ansichten mit diesem synthetischen Plugin in der onActivityCreated()-Methode verwenden, die direkt nach onCreateView() des Fragment-Lebenszyklus aufgerufen wird.

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

das einzige, was Sie tun müssen, ist:

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

es ist nicht erforderlich, ein Begleitobjekt zu definieren. Rufen Sie einfach jede ID über eine Ansicht wie auf

 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

Synthetische Eigenschaften, die vom Kotlin Android Extensions-Plugin generiert werden, benötigen eine view, damit Fragment/Activity vorab eingestellt werden kann.

In Ihrem Fall müssen Sie für Fragmentview.btn_K in onViewCreated verwenden.

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
}

Oder besser, Sie sollten nur auf synthetische Eigenschaften in onViewCreated zugreifen.

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

Bitte beachten Sie, dass der savedInstanceState-Parameter nullfähig sein sollte Bundle?, und prüfen Sie auch Import synthetischer Eigenschaften .

Es ist praktisch, alle Widget-Eigenschaften für ein bestimmtes Layout zu importieren auf einmal:

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

Wenn also der Layout-Dateiname activity_main.xml ist, importieren wir kotlinx.Android.synthetic.main.activity_main.*.

Wenn wir die synthetischen Eigenschaften in View aufrufen wollen, sollten wir auch kotlinx.Android.synthetic.main.activity_main.view.*. importieren

2
onmyway133

In Fragmente schreiben Sie bitte Ihren Code in 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

Die synthetischen Eigenschaften von Kotlin sind nicht magisch und wirken auf sehr einfache Weise. Wenn Sie auf btn_K zugreifen, wird getView().findViewById(R.id.btn_K) aufgerufen.

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {

    if (mRootView == null) {
        mRootView = inflater.inflate(R.layout.fragment_profile, container, false)
    }

    return mRootView
}

wenn Sie Interfaces-Callbacks verwenden, erhalten Sie NPE, da die Ansicht zu diesem Zeitpunkt nicht verfügbar ist -> Sie sollten die getView() -Methode überschreiben

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

und benutze immer deine Ansichten in onViewCreated()

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

In meinem Fall funktionierte nichts, bis ich den Ratschlägen von Otziii in den Kommentaren folgte. Reinigen, neu erstellen (kein Neustart erforderlich), führen Sie die App erneut aus. Ich brauchte auch nicht mit onActivityCreated und nur onCreateView machte den Trick.

Einmal habe ich auch den Fehler gemacht, ein falsches Layout aufzublasen, wodurch die erwarteten Steuerelemente offensichtlich nicht angezeigt wurden.

0
ZzZombo

Hinzufügen zu @Egor Neliubas Antwort: Ja, wenn Sie eine Ansicht ohne Referenz aufrufen, sucht kotlinex nach einer rootView, und da Sie sich in einem Fragment befinden und das Fragment keine getView() -Methode hat. Daher könnte es NullPointerException werfen

Es gibt zwei Möglichkeiten, dies zu überwinden:

  • Entweder Sie überschreiben onViewCreated() wie erwähnt
  • Oder wenn Sie Ansichten in einer anderen Klasse binden möchten (sagen wir anonym), können Sie einfach eine Erweiterungsfunktion wie diese erstellen.

    fun View.bindViews(){...}

Der zweite Ansatz ist hilfreich, wenn Sie ein einzelnes Fragment mit mehreren Verhaltensweisen haben.

0
Aziz