Kotlin parçasındaki görünümlere erişmeye çalışırken NullPointerException


240

Kotlin Android Uzantıları ile Fragments nasıl kullanılır ? Bunları içeride kullanırsam onCreateView(), bu NullPointerExceptionistisnayı alıyorum :

Nedeni: java.lang.NullPointerException: Boş bir nesne başvurusunda 'android.view.View android.view.View.findViewById (int)' sanal yöntemini çağırmayı deneyin.

İşte parça kodu:

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

4
Bunu onCreateView içinde yapmak istiyorsanız, btn_K rootView üzerinde de bir özellik olacaktır. YapabilirsinizrootView.btn_K.setOnClickListener
Makotosan

Teşekkürler @ Makotosan Cevabın benim için çalıştı.
Mehdi Bagjani

Android stüdyosu benim için çalıştı, yeniden inşa et ve yeniden başlat
Otziii

@Otziii Bu konu ilk olarak 2015 yılında yazılmıştır. İlk cevap 259 oy almıştır ve kabul edildi. Daha fazla cevap eklemenin gerekli olduğunu düşünmüyorum.
solidak

2
@Solidak Son zamanlarda bu sorunu yaşadım, tüm cevapları denedim ve işe yarayan tek şey şimdi yorum yaptığım şeydi. Bu konu üzerinde bir cevap vardı, ama sadece aşağı indirildi, bu yüzden bir yorum olarak değiştirdim. İnsanlar hala bu sorunu yaşıyor gibi görünüyor ve hiç kimse temizlemek ve yeniden başlatmak için bahsetmedi.
Otziii

Yanıtlar:


443

Kotlin sentetik özellikleri sihir değildir ve çok basit bir şekilde çalışır. Erişim yaptığınızda btn_K, bu çağrı yapılır getView().findViewById(R.id.btn_K).

Sorun şu ki, çok erken erişiyorsunuz. getView()döner nulliçinde onCreateView. onViewCreatedYöntemde yapmayı deneyin :

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

2
İşe yaradı!! Teşekkürler. İleride başvurmak için hızlı bir uyarı. Başka bir istisna vardı ve biraz daha derin kazdık ve Null Referans İstisnası, sentetik özelliğe erişmeye çalışacağı UI iş parçacığına bir eşzamansız geri arama geliyordu, ama o zaman zaten boştu. Güvenli Arama operatörünü (?.) Veya başka bir boş güvenlik operatörü kullandığınızdan emin olun . Ayrıca görünümün sınıf referansını tutmaya ve dışındaki sentetik özelliklere güvenmemeye yardımcı oluronViewCreated()
solidak

2
Yine de bir soru - Etkinlik ve Parça için farklı kod üretir mi? İçermeyen getView()veya çağıramayan başka bir yapı kullanırsak, bunun üzerinde findViewById()çalışmanın bir yolu var mı? Örneğin, hangi fonksiyonun düzenimi döndüreceğini öğretin?
milosmlar

7
Ayrıca rootView.btn_Kbir görüşünüz varmış gibi erişebilirsiniz (ve sadece parçalarda değil, bu her yerde yapılabilir)
Adib Faramarzi

İşe yarıyor ! Ancak Kotlin belgelerinden daha fazla vurgulanmalıdır. Bu gönderiye kadar bu yöntemi fark etmedim .. Yine de teşekkürler!
sokarcreative

2
Her zaman onViewCreated kullandım, ama yine de bazı cihazlarda (Crashlytics rapor aldım) "boş olmamalı" istisnası var. Görünüm orada. Doğru düzeni şişiriyorum, cihazımda çalışıyor. Sadece rastgele cihazda çalışmamak garip.
Arie Agung

9

Bunu btn_Ko anda bir null döndürdüğünde ve size Null Pointer Exception (Durum Göstergesi İstisnası) veriyor gibi çok erken çağırıyorsunuz .

Bu görünümleri , Fragment yaşam döngüsünden onActivityCreated()hemen sonra adlandırılan yöntemde bu sentetik eklentiyle kullanabilirsiniz onCreateView().

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

Sadece bazı nedenlerden ötürü, bu cevabın benim için işe yaradığını, ancak kabul edilen cevap işe yaramadığını belirtmek istiyorum. Görüşlerim boş onViewCreatedama sonra içinde tanımlandı onActivityCreated. Neden olduğunu bilmiyorum.
NathanL

6

Tarafından üretilen sentetik özellikler Kotlin Android Uzantıları eklentisi bir ihtiyacı viewiçin Fragment/Activityelden önce ayarlanmalıdır.

Senin durumunda, için Fragment, kullanmak gerek view.btn_KiçindeonViewCreated

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
}

Ya da daha iyisi, sadece sentetik özelliklere 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`
}

Lütfen savedInstanceStateparametrenin boş bırakılması gerektiğini unutmayın Bundle?ve ayrıca Sentetik özellikleri içe aktarma seçeneğini işaretleyin

Belirli bir düzen için tüm widget özelliklerinin tek seferde içe aktarılması uygundur:

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

Dolayısıyla, düzen dosya adı etkinlik_etki.xml ise, içe aktarırız kotlinx.android.synthetic.main.activity_main.*.

View'daki sentetik özellikleri çağırmak istiyorsak, kotlinx.android.synthetic.main.activity_main.view.*.


3

yapmanız gereken tek şey:

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
}

1
Evet, sadece kullan val view = inflater.inflate() view.button.text = "caption".
CoolMind

Bu en iyi cevap - kesinlikle en iyi çözüm!
CacheMeOutside

@CacheMeOutside no, çünkü hala kaynak plakası kodu rootView.subView.doSomething. ' onViewCreated
Den

3

tamamlayıcı nesneyi tanımlamanıza gerek yok, sadece

 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
}

1

Parçalar bölümünde lütfen kodunuzu onActivityCreated'a yazın: -

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
Neden? Bu bilgi nerede? Neden olmasın onViewCreated?
kuzdu

0

Benim durumumda yorumlarda Otziii'nin tavsiyelerini takip edene kadar hiçbir şey işe yaramadı . Temizleyin, yeniden oluşturun (yeniden başlatma gerekmez), uygulamayı yeniden çalıştırın. Ben de gitmek zorunda değildi onActivityCreatedve sadece onCreateViewhile yaptı.

Bir kez de yanlış düzen şişirme hatası yaptım, böylece beklenen kontrolleri açıkça alamıyorum.


ben oluyor gördük onActivityCreatedçok
Jemshit iskenderov

0

@Egor Neliuba'nın cevabına ekleyerek, Evet, referans olmadan bir görünüm çağırdığınızda, kotlinex bir rootView arar ve bir parçanın içindeyseniz ve parçanın getView()yöntemi yoktur. Bu nedenle fırlayabilirNullPointerException

Bunun üstesinden gelmenin iki yolu vardır,

  • Ya onViewCreated()belirtildiği gibi geçersiz kılınırsınız
  • Veya başka bir sınıftaki (anonim diyelim) görünümleri bağlamak istiyorsanız, bunun gibi bir uzantı işlevi oluşturabilirsiniz,

    fun View.bindViews(){...}

İkinci yaklaşım, birden fazla davranışa sahip tek bir parçanız olduğunda yardımcı olur.


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

}

** Burada bulmadan önce btn_K.setOnClickListener kullanıyorsunuz -O zaman findViewById kullanarak xml eleman formunu java / kotlin kodunuza bulmak zorundasınız ve sonra sadece o görünüm veya eleman üzerinde işlem yapabilirsiniz.

-Bu yüzden boş gösterici uygulaması var

**

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.