如何将Kotlin Android Extensions与Fragment
一起使用?
如果我在onCreateView()
中使用它们,我会收到NullPointerException
例外:
引起:java.lang.NullPointerException:尝试调用虚拟 方法' android.view.View android.view.View.findViewById(int)'在...上 null对象引用
这是片段代码:
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
}
}
`
答案 0 :(得分:343)
Kotlin合成属性不是神奇的,并且以非常简单的方式工作。当您访问btn_K
时,它会调用getView().findViewById(R.id.btn_K)
。
问题是您过早访问它。 getView()
会在null
中返回onCreateView
。尝试使用onViewCreated
方法:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
btn_K.setOnClickListener { Log.d(TAG, "onViewCreated(): hello world"); }
}
答案 1 :(得分:6)
你过早地调用这个btn_K
,因为那时它返回一个null并且给你Null Pointer Exception。
您可以在onActivityCreated()
方法中使用此合成插件来使用这些视图,该方法在Fragment生命周期的onCreateView()
之后调用。
onActivityCreated()
{
super.onActivityCreated(savedInstanceState)
btn_K.setOnClickListener{}
}
答案 2 :(得分:5)
Kotlin Android Extensions plugin生成的合成属性需要view
才能Fragment/Activity
预先设置。
对于您的情况,对于Fragment
,您需要在view.btn_K
中使用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
}
或者更好的是,您应该只在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.*.
答案 3 :(得分:3)
您唯一需要做的是:
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
}
答案 4 :(得分:3)
无需定义伴侣对象,只需通过一个视图调用每个id
changeLanguage = (language) => {
window.localStorage.setItem("siteLanguage", language);
this.setState({})
window.location.reload(1);
}
readTextFile(`/app/localization/localization.en.json`,
(localizationContent) => {
let localization = JSON.parse(localizationContent);
this.props.setLocalizationMessages(localization.messages, 'en');
});
if (localStorage.getItem("siteLanguage") == "th") {
readTextFile(`/app/localization/localization.th.json`,
(localizationContent) => {
let localization = JSON.parse(localizationContent);
this.props.setLocalizationMessages(localization.messages,
'th');
});
}
答案 5 :(得分:1)
在片段中,请在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()
}
答案 6 :(得分:0)
在我的情况下,直到我听取了Otziii的评论意见后,该方法才起作用。清理,重建(无需重新启动),重新运行该应用程序。我也不需要去onActivityCreated
,只需要onCreateView
就可以了。
有一次我也犯了夸大错误布局的错误,因此显然没有得到预期的控件。
答案 7 :(得分:0)
科特林的合成特性不是魔术,而是以非常简单的方式起作用的。当您访问btn_K时,它会调用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
}
如果您使用的是接口回调,那么您将得到NPE cuz,此时视图将不可用->您应该覆盖getView()
方法
override fun getView(): View? {
return mRootView
}
并始终在onViewCreated()
if (mCreatedView == null) {
mCreatedView = view
btn_K.setOnClickListener{
//------------do something
}
}
答案 8 :(得分:0)
将其添加到@Egor Neliuba的答案中,是的,每当调用不带引用的视图时,kotlinex都会寻找rootView,并且由于您位于片段内,并且片段没有getView()
方法。因此,它可能会抛出NullPointerException
有两种方法可以克服这个问题,
onViewCreated()
或者,如果您想将视图绑定到其他类(例如匿名)中,则只需创建一个扩展函数即可,
fun View.bindViews(){...}
当单个片段具有多种行为时,第二种方法会很有帮助。
答案 9 :(得分:-2)
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代码的元素,然后才能对该视图或元素执行操作。
**