尝试访问 Kotlin 片段中的视图时出现 NullPointerException
NullPointerException when trying to access views in a Kotlin fragment
如何将 Kotlin Android 扩展与 Fragment
一起使用?
如果我在 onCreateView()
中使用它们,我会得到这个 NullPointerException
异常:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual
method 'android.view.View android.view.View.findViewById(int)' on a
null object reference
这是片段代码:
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
}
}
`
Kotlin 合成属性并不神奇,并且以非常简单的方式工作。当您访问 btn_K
时,它会调用 getView().findViewById(R.id.btn_K)
.
问题是您访问它的速度太快了。 getView()
returns null
onCreateView
。尝试在 onViewCreated
方法中进行:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
btn_K.setOnClickListener { Log.d(TAG, "onViewCreated(): hello world"); }
}
您调用此 btn_K
太早了,因为当时它 returns 为 null 并给您 Null Pointer Exception。
您可以通过此合成插件在 onActivityCreated()
方法中使用这些视图,该方法在 Fragment 生命周期 onCreateView()
之后调用。
onActivityCreated()
{
super.onActivityCreated(savedInstanceState)
btn_K.setOnClickListener{}
}
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
}
}
**在这里你在查找之前使用btn_K.setOnClickListener
- 你必须使用 findViewById 找到你的 java/kotlin 代码的元素形式 xml 然后只有你可以对该视图或元素执行操作。
-这就是你得到空指针异常的原因
**
在 Fragments 中,请在 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()
}
您唯一需要做的是:
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
}
由 Kotlin Android Extensions plugin 生成的综合属性需要 view
用于 Fragment/Activity
以预先设置。
在您的情况下,对于 Fragment
,您需要在 onViewCreated
中使用 view.btn_K
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
}
或者更好的是,您应该只访问 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`
}
请注意 savedInstanceState
参数应该可以为空 Bundle?
,并检查 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.*.
在我的情况下,在我遵循评论中 Otziii 的建议之前,没有任何效果。清理、重建(无需重启)、重新 运行 应用程序。我也不需要使用 onActivityCreated
,只需 onCreateView
就可以了。
有一次我也犯了错误的布局错误,显然没有得到预期的控制。
无需定义伴生对象只需通过类似
的视图调用每个 id
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
}
将其添加到@Egor Neliuba 的回答中,是的,每当您在没有引用的情况下调用视图时,kotlinex 都会查找 rootView,并且由于您在片段中并且片段没有 getView()
方法。因此它可能会抛出 NullPointerException
有两种方法可以解决这个问题,
- 要么你重写
onViewCreated()
如前所述
或者如果你想在其他class(比如匿名)中绑定视图,你可以简单地创建一个像这样的扩展函数,
fun View.bindViews(){...}
当您有一个具有多种行为的片段时,第二种方法很有用。
如何将 Kotlin Android 扩展与 Fragment
一起使用?
如果我在 onCreateView()
中使用它们,我会得到这个 NullPointerException
异常:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.View.findViewById(int)' on a null object reference
这是片段代码:
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
}
}
`
Kotlin 合成属性并不神奇,并且以非常简单的方式工作。当您访问 btn_K
时,它会调用 getView().findViewById(R.id.btn_K)
.
问题是您访问它的速度太快了。 getView()
returns null
onCreateView
。尝试在 onViewCreated
方法中进行:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
btn_K.setOnClickListener { Log.d(TAG, "onViewCreated(): hello world"); }
}
您调用此 btn_K
太早了,因为当时它 returns 为 null 并给您 Null Pointer Exception。
您可以通过此合成插件在 onActivityCreated()
方法中使用这些视图,该方法在 Fragment 生命周期 onCreateView()
之后调用。
onActivityCreated()
{
super.onActivityCreated(savedInstanceState)
btn_K.setOnClickListener{}
}
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
}
}
**在这里你在查找之前使用btn_K.setOnClickListener - 你必须使用 findViewById 找到你的 java/kotlin 代码的元素形式 xml 然后只有你可以对该视图或元素执行操作。
-这就是你得到空指针异常的原因
**
在 Fragments 中,请在 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()
}
您唯一需要做的是:
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
}
由 Kotlin Android Extensions plugin 生成的综合属性需要 view
用于 Fragment/Activity
以预先设置。
在您的情况下,对于 Fragment
,您需要在 onViewCreated
view.btn_K
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
}
或者更好的是,您应该只访问 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`
}
请注意 savedInstanceState
参数应该可以为空 Bundle?
,并检查 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.*.
在我的情况下,在我遵循评论中 Otziii 的建议之前,没有任何效果。清理、重建(无需重启)、重新 运行 应用程序。我也不需要使用 onActivityCreated
,只需 onCreateView
就可以了。
有一次我也犯了错误的布局错误,显然没有得到预期的控制。
无需定义伴生对象只需通过类似
的视图调用每个 id 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
}
将其添加到@Egor Neliuba 的回答中,是的,每当您在没有引用的情况下调用视图时,kotlinex 都会查找 rootView,并且由于您在片段中并且片段没有 getView()
方法。因此它可能会抛出 NullPointerException
有两种方法可以解决这个问题,
- 要么你重写
onViewCreated()
如前所述 或者如果你想在其他class(比如匿名)中绑定视图,你可以简单地创建一个像这样的扩展函数,
fun View.bindViews(){...}
当您有一个具有多种行为的片段时,第二种方法很有用。