it-swarm.dev

NullPointerException podczas próby uzyskania dostępu do widoków w fragmencie Kotlin

Jak używać rozszerzeń Kotlin Android z Fragments? Jeśli użyję ich w onCreateView(), otrzymam wyjątek NullPointerException

Przyczyna: Java.lang.NullPointerException: Próba wywołania wirtualnego metoda 'Android.view.View Android.view.View.findViewById (int)' na odwołanie do pustego obiektu

Oto kod fragmentu: 

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

Właściwości syntetyczne Kotlina nie są magiczne i działają w bardzo prosty sposób. Gdy uzyskasz dostęp do btn_K, wywołuje on getView().findViewById(R.id.btn_K).

Problem polega na tym, że dostęp do niego jest zbyt wcześnie. getView() zwraca null w onCreateView. Spróbuj to zrobić w metodzie onViewCreated:

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

Nazywasz to btn_K zbyt wcześnie, ponieważ wtedy zwraca null i daje ci wyjątek Null Pointer.

Możesz użyć tych widoków za pomocą tej syntetycznej wtyczki w metodzie onActivityCreated(), która jest wywoływana zaraz po onCreateView() cyklu życia Fragmentu.

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

Właściwości syntetyczne generowane przez Kotlin Android Wtyczka rozszerzeń wymaga view, aby Fragment/Activity był ustawiony wcześniej.

W twoim przypadku w przypadku Fragment musisz użyć view.btn_K w 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
}

Lub lepiej, powinieneś uzyskać dostęp do właściwości syntetycznych tylko w 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`
}

Zauważ, że parametr savedInstanceState powinien mieć wartość null Bundle?, a także sprawdź Importowanie właściwości syntetycznych

Wygodnie jest zaimportować wszystkie właściwości widżetu dla określonego układu za jednym razem:

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

Zatem jeśli nazwa pliku układu to activity_main.xml, zaimportowalibyśmy kotlinx.Android.synthetic.main.activity_main.*.

Jeśli chcemy wywołać właściwości syntetyczne w View, powinniśmy również zaimportować kotlinx.Android.synthetic.main.activity_main.view.*.

5
onmyway133

jedyne co musisz zrobić, to:

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

nie ma potrzeby definiowania obiektu towarzyszącego, wystarczy wywołać każdy identyfikator w widoku takim jak

 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

W Fragmentach napisz swój kod w onActivityTworzono: -

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

Syntetyczne właściwości Kotlina nie są magiczne i działają w bardzo prosty sposób. Gdy uzyskujesz dostęp do btn_K, wzywa on 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
}

więc jeśli używasz wywołań zwrotnych interfejsów, otrzymasz NPE, ponieważ widok nie będzie w tej chwili dostępny -> powinieneś zastąpić metodę getView()

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

i zawsze używaj swoich widoków w onViewCreated()

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

W moim przypadku nic nie działało, dopóki nie zastosowałem się do rad z Otziii w komentarzach. Wyczyść, odbuduj (bez konieczności ponownego uruchamiania), ponownie uruchom aplikację. Nie musiałem też iść z onActivityCreated i tylko onCreateView załatwiło sprawę.

Pewnego razu popełniłem też błąd pompowania niewłaściwego układu, a więc oczywiście nie otrzymałem oczekiwanych kontroli.

0
ZzZombo

Dodając go do odpowiedzi @Egor Neliuba, Tak, za każdym razem, gdy wywołujesz widok bez odniesienia, kotlinex szuka rootView, a ponieważ jesteś wewnątrz fragmentu i fragmentu nie ma metody getView(). Dlatego może wyrzucić NullPointerExceptionname__

Istnieją dwa sposoby na przezwyciężenie tego,

  • Albo zastąpisz onViewCreated(), jak wspomniano
  • Lub jeśli chcesz powiązać widoki w innej klasie (powiedzmy anonimowy), możesz po prostu utworzyć funkcję rozszerzenia taką jak ta,

    fun View.bindViews(){...}

Drugie podejście jest pomocne, gdy masz jeden fragment z wieloma zachowaniami.

0
Aziz