web-dev-qa-db-ja.com

Kotlinフラグメント内のビューにアクセスしようとするとNullPointerExceptionが発生する

Fragmentsで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
    }
}
`
181
Solidak

Kotlinの合成特性は魔法ではなく、非常に単純な方法で機能します。 btn_Kにアクセスすると、getView().findViewById(R.id.btn_K)を呼び出します。

問題は、アクセスが早すぎることです。 getView()nullonCreateViewを返します。 onViewCreatedメソッドでやってみてください。

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    btn_K.setOnClickListener { Log.d(TAG, "onViewCreated(): hello world"); }
}
352
Egor Neliuba

このbtn_Kを呼び出した時点で、その時点でnullが返され、Null Pointer Exceptionが発生しています。

FragmentライフサイクルのonActivityCreated()の直後に呼び出されるonCreateView()メソッドでこの合成プラグインによってこれらのビューを使うことができます。

onActivityCreated()
{
        super.onActivityCreated(savedInstanceState)
        btn_K.setOnClickListener{}
}
6
Kashish luthra

Kotlin Android Extensionsプラグイン によって生成された合成プロパティは、Fragment/Activityを事前に設定するためにviewが必要です。

あなたの場合、Fragmentには、onViewCreatedview.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.*.もインポートする必要があります。

5
onmyway133

あなたがする必要がある唯一のことは:

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
}
3
Rhusfer

コンパニオンオブジェクトを定義する必要はありません。

 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
}
3
Rahul ShaRma

フラグメントであなたのコードを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()

  }
1
abhilasha Yadav

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
   }
 }
0
ilyas ipek

私の場合、コメントの中で Otziii のアドバイスに従うまでは何もうまくいきませんでした。クリーン、再構築(再起動は不要)、アプリを再実行してください。私もonActivityCreatedを使う必要はなく、onCreateViewだけでうまくいきました。

あるとき、私は間違ったレイアウトを膨らませるという誤りをしました、それで、明らかに期待されたコントロールを得ませんでした。

0
ZzZombo

@Egor Neliubaの答えに追加します。参照なしでビューを呼び出すたびに、はい、kotlinexはrootViewを検索します。また、フラグメント内にあり、フラグメントにはgetView()メソッドがありません。したがって、NullPointerExceptionをスローする可能性があります

これを克服するには2つの方法があります。

  • 前述のようにonViewCreated()をオーバーライドするか、
  • または、他のクラス(匿名など)のビューをバインドする場合は、このような拡張関数を作成するだけです。

    fun View.bindViews(){...}

2番目のアプローチは、複数の動作を持つ単一のフラグメントがある場合に役立ちます。

0
Aziz