NullPointerException ketika mencoba mengakses tampilan di fragmen Kotlin


240

Bagaimana cara menggunakan Kotlin Android Extensions with Fragments? Jika saya menggunakannya di dalam onCreateView(), saya mendapatkan NullPointerExceptionpengecualian ini :

Disebabkan oleh: java.lang.NullPointerException: Mencoba untuk memanggil metode virtual 'android.view.View android.view.View.findViewById (int)' pada referensi objek nol

Ini adalah kode fragmen:

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
Jika Anda ingin melakukannya di onCreateView, btn_K juga akan menjadi properti di rootView. Anda bisa melakukannyarootView.btn_K.setOnClickListener
Makotosan

Terima kasih @ Makotosan jawaban Anda bekerja untuk saya.
Mahdi Bagjani

Bersihkan,
bangun

@Otziii Utas ini pertama kali ditulis pada tahun 2015. Jawaban pertama memiliki 259 suara dan diterima. Saya pikir tidak perlu menambahkan lebih banyak jawaban.
solidak

2
@ Solidak, saya memiliki masalah ini baru-baru ini, mencoba semua jawaban dan satu-satunya hal yang membuatnya bekerja adalah apa yang sekarang saya komentari. Saya punya jawaban di utas ini, tetapi baru saja dibatalkan suara, jadi saya mengubahnya menjadi komentar. Sepertinya orang masih mengalami masalah ini, dan tidak ada yang disebutkan untuk membersihkan dan memulai kembali.
Otziii

Jawaban:


443

Sifat sintetis Kotlin bukanlah sihir dan bekerja dengan cara yang sangat sederhana. Ketika Anda mengakses btn_K, itu panggilan untuk getView().findViewById(R.id.btn_K).

Masalahnya adalah Anda terlalu cepat mengaksesnya. getView()kembali nulldi onCreateView. Coba lakukan dalam onViewCreatedmetode:

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

2
Berhasil !! Terima kasih. Hanya kepala-up cepat untuk referensi di masa mendatang. Saya memiliki pengecualian lain, dan saya menggali sedikit lebih dalam dan ternyata Null Reference Exception berasal dari panggilan balik async ke utas UI di mana ia akan mencoba mengakses properti sintetis, tetapi itu sudah nol pada saat itu. Pastikan untuk menggunakan operator Panggilan Aman (?) Atau operator keselamatan nol lainnya. Ini juga akan membantu untuk menjaga referensi kelas tampilan dan tidak bergantung pada sifat-sifat sintetis di luaronViewCreated()
solidak

2
Satu pertanyaan - menghasilkan kode yang berbeda untuk Aktivitas dan Fragmen? Jika kita menggunakan struktur lain yang tidak mengandung getView()atau tidak dapat dipanggil findViewById(), apakah ada cara untuk mengatasinya? Misalnya, ajarkan fungsi mana yang akan mengembalikan tata letak saya?
milosmns

7
Anda juga dapat mengaksesnya seperti rootView.btn_Kjika Anda memiliki tampilan (dan tidak hanya dalam fragmen, ini dapat dilakukan di mana-mana)
Adib Faramarzi

Berhasil ! Namun harus lebih digarisbawahi dari dokumentasi Kotlin. Saya tidak melihat metode ini sampai posting ini .. Terima kasih!
sokarcreative

2
Saya selalu menggunakannya di onViewCreated, tetapi masih pada beberapa perangkat (saya mendapat laporan dari Crashlytics) itu mendapat pengecualian "tidak boleh nol". Pemandangan ada di sana. Saya mengembang tata letak yang benar, itu berfungsi pada perangkat saya. Hanya aneh tidak bekerja di perangkat acak.
Arie Agung

9

Anda memanggil ini btn_Kterlalu cepat karena pada saat itu mengembalikan nol dan memberi Anda Null Pointer Exception.

Anda dapat menggunakan tampilan ini dengan plugin sintetis ini dalam onActivityCreated()metode yang disebut hanya setelah onCreateView()siklus hidup Fragmen.

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

Saya hanya ingin menunjukkan bahwa untuk beberapa alasan, jawaban ini bekerja untuk saya sedangkan jawaban yang diterima tidak. Pandangan saya adalah nol onViewCreatedtetapi kemudian didefinisikan dalam onActivityCreated. Tidak tahu kenapa.
NathanL

6

Sifat sintetik yang dihasilkan oleh Kotlin Android Ekstensi Plugin membutuhkan viewuntuk Fragment/Activityharus ditetapkan sebelum tangan.

Dalam kasus Anda, untuk Fragment, Anda perlu menggunakan view.btn_KdionViewCreated

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
}

Atau lebih baik, Anda hanya boleh mengakses properti sintetis di 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`
}

Harap perhatikan bahwa savedInstanceStateparameter harus nullable Bundle?, dan periksa juga Mengimpor properti sintetis

Lebih mudah untuk mengimpor semua properti widget untuk tata letak tertentu dalam sekali jalan:

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

Jadi jika nama file tata letak adalah activity_main.xml, kami akan mengimpor kotlinx.android.synthetic.main.activity_main.*.

Jika kami ingin memanggil properti sintetis di Tampilan, kami juga harus mengimpor kotlinx.android.synthetic.main.activity_main.view.*.


3

satu-satunya hal yang perlu Anda lakukan adalah:

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
Ya, gunakan saja val view = inflater.inflate() view.button.text = "caption".
CoolMind

Ini adalah jawaban terbaik - solusi paling pasti!
CacheMeOutside

@CacheMeOutside tidak, karena masih kode boilerplate rootView.subView.doSomething. Lebih baik menggunakan tampilan mulai darionViewCreated
user924

3

tidak perlu mendefinisikan objek pendamping cukup panggil setiap id dengan tampilan seperti

 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

Dalam Fragmen, harap tulis kode Anda di 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
Mengapa? Di mana memiliki pengetahuan ini? Kenapa tidak onViewCreated?
kuzdu

0

Dalam kasus saya, tidak ada yang berhasil sampai saya mengikuti saran dari Otziii dalam komentar. Bersihkan, bangun kembali (tidak perlu restart), jalankan kembali aplikasi. Saya juga tidak perlu ikut onActivityCreateddan hanya onCreateViewmelakukan trik.

Suatu kali saya juga membuat kesalahan karena menggelembungkan tata letak yang salah, sehingga tidak mendapatkan kontrol yang diharapkan.


saya telah melihat hal itu terjadi di onActivityCreatedterlalu
Jemshit Iskenderov

0

Menambahkannya ke jawaban @Egor Neliuba, Ya setiap kali Anda memanggil tampilan tanpa referensi, kotlinex mencari rootView, dan karena Anda berada di dalam sebuah fragmen dan fragmen tidak memiliki getView()metode. Karena itu mungkin melemparNullPointerException

Ada dua cara untuk mengatasi ini,

  • Entah Anda menimpa onViewCreated()seperti yang disebutkan
  • Atau Jika Anda ingin mengikat tampilan di beberapa kelas lain (katakanlah anonim), Anda cukup membuat fungsi ekstensi seperti ini,

    fun View.bindViews(){...}

Pendekatan kedua sangat membantu, ketika Anda memiliki satu fragmen dengan beberapa perilaku.


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

}

** Di sini Anda menggunakan btn_K.setOnClickListener sebelum menemukan -Anda harus menemukan bentuk elemen xml ke kode java / kotlin Anda dengan menggunakan findViewById lalu dan kemudian hanya Anda yang dapat melakukan operasi pada tampilan atau elemen tersebut.

-Jadi itu sebabnya eksekusi null pointer Anda dapatkan

**

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.