试图访问Kotlin片段中的视图时出现NullPointerException

如何使用Kotlin Android扩展Fragments? 如果我在onCreateView()中使用它们,我会得到这个NullPointerException异常:

原因:java.lang.NullPointerException:试图调用virtual .lang. nullpointerexception android.view.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
}
}
`
64075 次浏览

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"); }
}

你调用这个btn_K太快了,因为在那个时候它会返回一个空值,并给你一个空指针异常。

你可以通过这个合成插件在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找到xml到你的java/kotlin代码中的元素,然后只有你可以对该视图或元素执行操作

-这就是为什么你得到空指针执行

**

在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插件生成的合成属性需要预先为Fragment/Activity设置view

在你的例子中,对于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?,并检查导入合成属性

导入特定布局的所有小部件属性非常方便

import kotlinx.android.synthetic.main.<layout>.*

因此,如果布局文件名是activity_main.xml,我们将导入 kotlinx.android.synthetic.main.activity_main.*. < / p > 如果我们想在View上调用合成属性,我们也应该 进口kotlinx.android.synthetic.main.activity_main.view.*. < / p >

在我的情况下,直到我遵循评论中的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()
  • 如果你想在其他类中绑定视图(比如匿名),你可以简单地创建一个像这样的扩展函数,

    fun View.bindViews(){...} < / p >

第二种方法是有用的,当你有一个具有多种行为的片段时。