NullPointerException when trying to access views in a Kotlin fragment

AndroidKotlinKotlin Android-Extensions

Android Problem Overview


How to use Kotlin Android Extensions with Fragments? If I use them inside onCreateView(), I get this NullPointerException exception:

> Caused by: java.lang.NullPointerException: Attempt to invoke virtual > method 'android.view.View android.view.View.findViewById(int)' on a > null object reference

Here is the fragment code:

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

Android Solutions


Solution 1 - Android

Kotlin synthetic properties are not magic and work in a very simple way. When you access btn_K, it calls for getView().findViewById(R.id.btn_K).

The problem is that you are accessing it too soon. getView() returns null in onCreateView. Try doing it in the onViewCreated method:

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

Solution 2 - Android

You are calling this btn_K too soon as at that time it returns a null and is giving you Null Pointer Exception.

You can use these views by this synthetic plugin in onActivityCreated() method which is called just after onCreateView() of Fragment lifecycle.

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

Solution 3 - Android

Synthetic properties generated by Kotlin Android Extensions plugin needs a view for Fragment/Activity to be set before hand.

In your case, for Fragment, you need to use view.btn_K in 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
}

Or better, you should only access synthetic properties in 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`
}

Please notice that savedInstanceState parameter should be nullable Bundle?, and also check Importing synthetic properties

> It is convenient to import all widget properties for a specific layout > in one go: > > > import kotlinx.android.synthetic.main.<layout>.* > > Thus if the layout filename is activity_main.xml, we'd import > kotlinx.android.synthetic.main.activity_main.*. > > If we want to call the synthetic properties on View, we should also > import kotlinx.android.synthetic.main.activity_main.view.*.

Solution 4 - Android

the only thing you need to do is:

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
}

Solution 5 - Android

In Fragments please write your 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()
  
  }

Solution 6 - Android

In my case nothing worked until I followed the advice from Otziii in the comments. Clean, rebuild (no restart needed), re-run the app. I also didn't need to go with onActivityCreated and just onCreateView did the trick.

One time I also made the error of inflating wrong layout, thus not getting the expected controls obviously.

Solution 7 - Android

no need to define companion object just call every id by a view like

 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
}

Solution 8 - Android

Adding it to @Egor Neliuba's answer, Yes whenever you call a view without reference, kotlinex looks for a rootView, and since you are inside a fragment and fragment doesn't have getView() method. Therefore it might throw NullPointerException

There are two ways to overcome this,

  • Either you override onViewCreated() as mentioned

  • Or If you want to bind views in some other class(say anonymous), you can simply create an extension function like this,

    fun View.bindViews(){...}

The second approach is helpful, when you have a single fragment with multiple behaviour.

Solution 9 - Android

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
}

}

**Here you are using btn_K.setOnClickListener before finding -You have to find the element form xml to your java/kotlin code by using findViewById then and then only you can perform operation on that view or element. -So that's why null pointer execption you got

**

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsolidakView Question on Stackoverflow
Solution 1 - AndroidEgor NeliubaView Answer on Stackoverflow
Solution 2 - AndroidKashish luthraView Answer on Stackoverflow
Solution 3 - Androidonmyway133View Answer on Stackoverflow
Solution 4 - AndroidRhusferView Answer on Stackoverflow
Solution 5 - Androidabhilasha YadavView Answer on Stackoverflow
Solution 6 - AndroidZzZomboView Answer on Stackoverflow
Solution 7 - AndroidRahul ShaRmaView Answer on Stackoverflow
Solution 8 - AndroidAzizView Answer on Stackoverflow
Solution 9 - AndroidAmit WalkeView Answer on Stackoverflow