尝试访问 Kotlin 片段中的视图时出现 NullPointerException
Posted
技术标签:
【中文标题】尝试访问 Kotlin 片段中的视图时出现 NullPointerException【英文标题】:NullPointerException when trying to access views in a Kotlin fragment 【发布时间】:2016-04-05 03:27:03 【问题描述】:如何通过Fragment
s 使用 Kotlin android 扩展?
如果我在onCreateView()
中使用它们,我会得到这个NullPointerException
异常:
原因:java.lang.NullPointerException:尝试调用虚拟 方法'android.view.View android.view.View.findViewById(int)' 空对象引用
这里是片段代码:
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
`
【问题讨论】:
如果你想在 onCreateView 中做,btn_K 也将是 rootView 上的一个属性。你可以做rootView.btn_K.setOnClickListener
感谢@Makotosan,您的回答对我有用。
清理、重建和重启 Android Studio 对我有用
@Otziii 这个帖子最初是在 2015 年写的。第一个答案有 259 票并被接受。我认为没有必要添加更多答案。
@Solidak 我最近遇到了这个问题,尝试了所有答案,唯一使它起作用的是我现在评论的内容。我在这个线程上有一个答案,但它只是被否决了,所以我把它改成了评论。似乎人们仍然有这个问题,没有人提到要清理并重新启动。
【参考方案1】:
Kotlin 合成属性并不神奇,而且工作方式非常简单。当您访问btn_K
时,它会调用getView().findViewById(R.id.btn_K)
。
问题是您访问它太快了。 getView()
在 onCreateView
中返回 null
。尝试在onViewCreated
方法中执行此操作:
override fun onViewCreated(view: View, savedInstanceState: Bundle?)
btn_K.setOnClickListener Log.d(TAG, "onViewCreated(): hello world");
【讨论】:
成功了!!谢谢。只是一个快速的提示以供将来参考。我有另一个异常,我挖得更深一点,结果发现空引用异常来自对 UI 线程的异步回调,它会尝试访问合成属性,但当时它已经为空。确保使用 Safe Call 运算符 (?.) 或其他一些空安全运算符。它还有助于保持视图的类引用,而不是依赖于onViewCreated()
之外的合成属性
一个问题 - 它为 Activity 和 Fragment 生成不同的代码?如果我们使用另一个不包含getView()
的结构或者它不能调用findViewById()
,有没有办法解决它?例如,教它哪个函数会返回我的布局?
如果您有视图,也可以像rootView.btn_K
一样访问它(而不仅仅是在片段中,这可以在任何地方完成)
有效!然而,它应该从 Kotlin 文档中得到更多的强调。直到这篇文章我才注意到这种方法。无论如何谢谢!
我总是在 onViewCreated 中使用它,但仍然在某些设备上(我从 Crashlytics 得到报告)它得到“不得为空”异常。景色就在那里。我充气正确的布局,它适用于我的设备。奇怪的是不能在随机设备上工作。【参考方案2】:
你调用这个btn_K
太快了,因为它返回一个空值并且给你空指针异常。
您可以通过这个合成插件在onActivityCreated()
方法中使用这些视图,该方法在片段生命周期的onCreateView()
之后调用。
onActivityCreated()
super.onActivityCreated(savedInstanceState)
btn_K.setOnClickListener
【讨论】:
我只想指出,由于某些原因,这个答案对我有用,而接受的答案却没有。我的观点在onViewCreated
中为空,但随后在onActivityCreated
中定义。不知道为什么。【参考方案3】:
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
导入特定布局的所有小部件属性很方便 一口气:
import kotlinx.android.synthetic.main.<layout>.*
因此,如果布局文件名为 activity_main.xml,我们将导入
kotlinx.android.synthetic.main.activity_main.*.
如果我们想在 View 上调用合成属性,我们还应该 导入
kotlinx.android.synthetic.main.activity_main.view.*.
【讨论】:
【参考方案4】:您唯一需要做的就是:
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
【讨论】:
是的,只需使用val view = inflater.inflate() view.button.text = "caption"
。
这是最好的答案 - 肯定是最简洁的解决方案!
@CacheMeOutside 不,因为它仍然是样板代码rootView.subView.doSomething
。最好使用从onViewCreated
开始的视图【参考方案5】:
无需定义伴生对象,只需通过视图调用每个 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
【讨论】:
【参考方案6】:在 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()
【讨论】:
为什么?哪里有这方面的知识?为什么不改为onViewCreated
?【参考方案7】:
在我遵循 cmets 中 Otziii 的建议之前,没有任何效果。清理、重建(无需重新启动)、重新运行应用程序。我也不需要使用onActivityCreated
,只需onCreateView
就可以了。
有一次我也犯了膨胀错误布局的错误,因此显然没有得到预期的控件。
【讨论】:
我在onActivityCreated
也看到了这种情况【参考方案8】:
将其添加到@Egor Neliuba 的答案中,是的,每当您调用没有引用的视图时,kotlinex 都会查找 rootView,并且由于您在片段中,并且片段没有 getView()
方法。因此它可能会抛出NullPointerException
有两种方法可以解决这个问题,
如前所述,要么覆盖onViewCreated()
或者如果你想在其他类中绑定视图(比如匿名),你可以简单地创建一个这样的扩展函数,
fun View.bindViews()...
当您有一个具有多种行为的片段时,第二种方法很有帮助。
【讨论】:
【参考方案9】: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 将元素形式的 xml 查找到您的 java/kotlin 代码,然后只有您可以对该视图或元素执行操作。
-这就是你得到空指针执行的原因
**
【讨论】:
以上是关于尝试访问 Kotlin 片段中的视图时出现 NullPointerException的主要内容,如果未能解决你的问题,请参考以下文章
尝试从 Kotlin 中的另一个活动访问 EditText 时出现空指针异常
从自定义视图访问 RelativeLayout 时出现 NullPointerException
尝试创建 OkHttpClient 对象时出现 kotlin/TypeCastException