NullPointerException when trying to access views in a Kotlin fragment
AndroidKotlinKotlin Android-ExtensionsAndroid Problem Overview
How to use Kotlin Android Extensions with Fragment
s?
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
**