Reputation: 5081
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
}
}
`
Upvotes: 269
Views: 65281
Reputation: 2113
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,
onViewCreated()
as mentionedOr 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.
Upvotes: 0
Reputation: 99
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
}
Upvotes: 0
Reputation: 944
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.
Upvotes: 0
Reputation: 48055
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.*.
Upvotes: 8
Reputation: 581
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
}
Upvotes: 5
Reputation: 15054
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"); }
}
Upvotes: 490
Reputation: 213
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()
}
Upvotes: 1
Reputation: 293
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.
**
Upvotes: -3
Reputation: 121
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{}
}
Upvotes: 11