264

如何将 Kotlin Android Extensions 与Fragments 一起使用?如果我在里面使用它们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
    }
}
`
4

9 回答 9

486

Kotlin 合成属性并不神奇,而且工作方式非常简单。当你访问btn_K时,它要求getView().findViewById(R.id.btn_K)

问题是您访问它太快了。中getView()返回。尝试在方法中这样做:nullonCreateViewonViewCreated

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    btn_K.setOnClickListener { Log.d(TAG, "onViewCreated(): hello world"); }
}
于 2015-12-31T08:01:55.567 回答
10

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

您可以通过这个合成插件在Fragment 生命周期onActivityCreated()之后调用的方法中使用这些视图。onCreateView()

onActivityCreated()
{
        super.onActivityCreated(savedInstanceState)
        btn_K.setOnClickListener{}
}
于 2017-11-20T11:57:08.543 回答
8

Kotlin Android Extensions 插件生成的综合属性需要预先设置一个viewfor 。Fragment/Activity

在您的情况下,对于Fragment,您需要使用view.btn_KinonViewCreated

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.*.

如果我们想在 View 上调用合成属性,我们还应该导入kotlinx.android.synthetic.main.activity_main.view.*.

于 2018-08-03T14:03:17.440 回答
5

你唯一需要做的是:

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
}
于 2018-07-16T05:19:35.243 回答
3

无需定义伴生对象,只需通过类似的视图调用每个 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
}
于 2019-06-26T08:15:02.643 回答
1

在 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()

  }
于 2018-05-23T07:17:13.073 回答
0

就我而言,在我遵循评论中Otziii的建议之前,没有任何效果。清理、重建(无需重新启动)、重新运行应用程序。我也不需要一起去,onActivityCreated只是onCreateView做了这个把戏。

有一次我也犯了错误布局的错误,因此显然没有得到预期的控件。

于 2018-11-16T07:07:04.700 回答
0

将其添加到@Egor Neliuba 的答案中,是的,每当您调用没有引用的视图时,kotlinex 都会查找 rootView,并且由于您在片段中并且片段没有getView()方法。因此它可能会抛出NullPointerException

有两种方法可以克服,

  • onViewCreated()如前所述,您可以覆盖
  • 或者如果你想在其他类中绑定视图(比如匿名),你可以简单地创建一个这样的扩展函数,

    fun View.bindViews(){...}

当您有一个具有多种行为的片段时,第二种方法很有帮助。

于 2019-08-16T07:24:06.167 回答
-3
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 代码,然后只有您可以对该视图或元素执行操作。

- 所以这就是你得到空指针执行的原因

**

于 2018-04-10T12:01:29.257 回答