问题
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
}
}
`
回答1:
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"); }
}
回答2:
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{}
}
回答3:
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.*.
回答4:
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
}
回答5:
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
}
回答6:
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()
}
回答7:
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.
回答8:
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)
.
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
if (mRootView == null) {
mRootView = inflater.inflate(R.layout.fragment_profile, container, false)
}
return mRootView
}
soo if your are using interfaces callbacks you will get NPE cuz the view won't be available at this time -> you shoud override getView()
method
override fun getView(): View? {
return mRootView
}
and always use your views in onViewCreated()
if (mCreatedView == null) {
mCreatedView = view
btn_K.setOnClickListener{
//------------do something
}
}
回答9:
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.
回答10:
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
**
来源:https://stackoverflow.com/questions/34541650/nullpointerexception-when-trying-to-access-views-in-a-kotlin-fragment