Il existe un scénario assez simple qui me donne pas mal de problèmes. Je fais une activité très simple avec un fragment incorporé. Ce fragment est simplement une Gridview qui affiche des images. Le problème vient de la référence à Gridview utilisant des extensions Kotlin pour faire directement référence à un identifiant XML. Quel est le problème ici? Kotlinx ne fonctionne-t-il pas sur les fragments statiques?
Erreur:
Java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.Android.android_me/com.example.Android.android_me.ui.MainActivity}: Java.lang.IllegalStateException: gridview_all_parts must not be null
Caused by: Java.lang.IllegalStateException: gridview_all_parts must not be null at com.example.Android.android_me.ui.MasterListFragment.onActivityCreated(MasterListFragment.kt:22)
Fragment avec une ligne de code offensive
import kotlinx.Android.synthetic.main.fragment_master_list.*
class MasterListFragment: Fragment() {
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val layoutView = inflater?.inflate(R.layout.fragment_master_list, container, false)
return layoutView
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
//If this is removed, code runs
gridview_all_parts.adapter = MasterListAdapter(activity, AndroidImageAssets.getAll())
super.onActivityCreated(savedInstanceState)
}
}
Fragment Layout:
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:id="@+id/gridview_all_parts"
Android:layout_width="match_parent" Android:layout_height="match_parent"/>
Présentation de l'activité des parents
<?xml version="1.0" encoding="utf-8"?>
<!--have tried both class:= and Android:name:=-->
<fragment xmlns:Android="http://schemas.Android.com/apk/res/Android"
class="com.example.Android.android_me.ui.MasterListFragment"
Android:id="@+id/fragment_masterlist"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
/>
Activité des parents
class MainActivity: AppCompatActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
Pour utiliser les extensions dans Fragment, vous devez utiliser votre layoutView
. Cela devrait fonctionner: layoutView.gridview_all_parts.adapter = MasterListAdapter(activity, AndroidImageAssets.getAll())
Vous pouvez rendre votre layoutView global dans ce cas.
EXPLICATION MISE À JOUR Elle a quelque chose à voir avec le gonflage de la vue. Comme dans butterknife, nous devons lier la vue gonflée dans le cas de fragment/recyclerView, de la même manière que dans le cas de kotlin, nous avons besoin de cette vue gonflée pour accéder aux vues dans le fichier XML.
Citant à partir de documentation officielle ,
Importation de propriétés synthétiques Il est pratique d'importer toutes les propriétés de widget pour une mise en page spécifique en une fois:
import kotlinx.Android.synthetic.main.<layout>.*
Ainsi, si le nom du fichier de mise en page est
activity_main.xml
, nous importonskotlinx.Android.synthetic.main.activity_main. *.
Si nous voulons appeler les propriétés synthétiques sur View, nous devrions également importation
kotlinx.Android.synthetic.main.activity_main.view.*.
Une fois que nous avons fait cela, nous pouvons ensuite appeler les extensions correspondantes, qui sont des propriétés nommées d'après les vues du fichier XML.
Pour tous ceux qui ont trouvé ce problème dans l’autre cas.
Les NPE à partir d’extensions Android se produisent également lors de l’écriture de l’adaptateur pour RecyclerView (en particulier: l’écriture de CustomViewHolder).
Voir LayoutContainer pour plus d'informations et pour résoudre ce problème.
apply plugin: 'kotlin-Android-extensions'
Android {
androidExtensions {
experimental = true
}
// your config
defaultConfig {}
}
class MainViewHolder(override val containerView: View) :
RecyclerView.ViewHolder(containerView),
LayoutContainer { // Extends this
fun bind(item: News) = containerView.apply {
tv_item_title.text = item.title
}
}