Fragment
sでKotlin Android拡張機能を使用する方法これらをonCreateView()
内で使用すると、NullPointerException
例外が発生します。
原因:Java.lang.NullPointerException:nullオブジェクト参照に対して仮想メソッド '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
}
}
`
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"); }
}
このbtn_K
を呼び出した時点で、その時点でnullが返され、Null Pointer Exceptionが発生しています。
FragmentライフサイクルのonActivityCreated()
の直後に呼び出されるonCreateView()
メソッドでこの合成プラグインによってこれらのビューを使うことができます。
onActivityCreated()
{
super.onActivityCreated(savedInstanceState)
btn_K.setOnClickListener{}
}
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
パラメーターはNULL可能なBundle?
でなければならないことに注意してください。また、 合成プロパティのインポート も確認してください。
特定のレイアウトのすべてのウィジェットプロパティを一度にインポートすると便利です。
import kotlinx.Android.synthetic.main.<layout>.*
したがって、レイアウトのファイル名がactivity_main.xmlの場合、
kotlinx.Android.synthetic.main.activity_main.*.
をインポートします。Viewの合成プロパティを呼び出したい場合は、
kotlinx.Android.synthetic.main.activity_main.view.*.
もインポートする必要があります。
あなたがする必要がある唯一のことは:
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
}
コンパニオンオブジェクトを定義する必要はありません。
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
}
フラグメントであなたのコードを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()
}
Kotlin合成プロパティは魔法ではなく、非常に簡単な方法で機能します。 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を取得します。現時点ではビューを利用できません-> getView()
メソッドをオーバーライドする必要があります
override fun getView(): View? {
return mRootView
}
常にonViewCreated()
でビューを使用します
if (mCreatedView == null) {
mCreatedView = view
btn_K.setOnClickListener{
//------------do something
}
}
私の場合、コメントの中で Otziii のアドバイスに従うまでは何もうまくいきませんでした。クリーン、再構築(再起動は不要)、アプリを再実行してください。私もonActivityCreated
を使う必要はなく、onCreateView
だけでうまくいきました。
あるとき、私は間違ったレイアウトを膨らませるという誤りをしました、それで、明らかに期待されたコントロールを得ませんでした。
@Egor Neliubaの答えに追加します。参照なしでビューを呼び出すたびに、はい、kotlinexはrootViewを検索します。また、フラグメント内にあり、フラグメントにはgetView()
メソッドがありません。したがって、NullPointerException
をスローする可能性があります
これを克服するには2つの方法があります。
onViewCreated()
をオーバーライドするか、または、他のクラス(匿名など)のビューをバインドする場合は、このような拡張関数を作成するだけです。
fun View.bindViews(){...}
2番目のアプローチは、複数の動作を持つ単一のフラグメントがある場合に役立ちます。