I am working with Android Studio and Kotlin. I am trying to create an RecyclerView and a Adapter.
I obtain the following error when I try to use the RecyclerView. It says that dog_image is null but I don't undernstand why.
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.dogglers, PID: 26356
java.lang.IllegalStateException: view!!.findViewById(R.id.dog_image) must not be null
at com.example.dogglers.adapter.DogCardAdapter$DogCardViewHolder.<init>(DogCardAdapter.kt:50)
at com.example.dogglers.adapter.DogCardAdapter.onCreateViewHolder(DogCardAdapter.kt:90)
at com.example.dogglers.adapter.DogCardAdapter.onCreateViewHolder(DogCardAdapter.kt:34)
at androidx.recyclerview.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:7078)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6235)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6118)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6114)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2303)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1627)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4134)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3851)
at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4404)
at android.view.View.layout(View.java:20871)
at android.view.ViewGroup.layout(ViewGroup.java:6268)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20871)
at android.view.ViewGroup.layout(ViewGroup.java:6268)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20871)
at android.view.ViewGroup.layout(ViewGroup.java:6268)
at androidx.appcompat.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:530)
at android.view.View.layout(View.java:20871)
at android.view.ViewGroup.layout(ViewGroup.java:6268)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20871)
at android.view.ViewGroup.layout(ViewGroup.java:6268)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)
at android.view.View.layout(View.java:20871)
at android.view.ViewGroup.layout(ViewGroup.java:6268)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at com.android.internal.policy.DecorView.onLayout(DecorView.java:758)
at android.view.View.layout(View.java:20871)
at android.view.ViewGroup.layout(ViewGroup.java:6268)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2972)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2487)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1580)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7634)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:958)
at android.view.Choreographer.doCallbacks(Choreographer.java:770)
at android.view.Choreographer.doFrame(Choreographer.java:702)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:944)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6831)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:927)
The error is here (Adapter):
/*
* Copyright (C) 2021 The Android Open Source Project.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.dogglers.adapter
import android.content.Context
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.dogglers.model.Dog
import com.example.dogglers.data.DataSource.dogs as list_dogs
import com.example.dogglers.R
/**
* Adapter to inflate the appropriate list item layout and populate the view with information
* from the appropriate data source
*/
class DogCardAdapter(
private val context: Context?,
private val layout: Int
): RecyclerView.Adapter<DogCardAdapter.DogCardViewHolder>() {
// TODO: Initialize the data using the List found in data/DataSource
private val dogs: List<Dog> = list_dogs
/**
* Initialize view elements
*/
class DogCardViewHolder(view: View?): RecyclerView.ViewHolder(view!!) {
// TODO: Declare and initialize all of the list item UI components
val imageView: ImageView = view!!.findViewById(R.id.dog_image)
val dogNameTextView: TextView = view!!.findViewById(R.id.dog_name)
val dogAgeTextView: TextView = view!!.findViewById(R.id.dog_age)
val dogHobbiesTextView: TextView = view!!.findViewById(R.id.dog_hobbies)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DogCardViewHolder {
// TODO: Use a conditional to determine the layout type and set it accordingly.
// if the layout variable is Layout.GRID the grid list item should be used. Otherwise the
// the vertical/horizontal list item should be used.
var adapterLayout =LayoutInflater.from(parent.context)
.inflate(R.layout.activity_grid_list, parent, false)
when(layout){
1->{
adapterLayout =LayoutInflater.from(parent.context)
.inflate(R.layout.activity_vertical_list, parent, false)
}
2->{
adapterLayout =LayoutInflater.from(parent.context)
.inflate(R.layout.activity_horizontal_list, parent, false)
}
}
// TODO Inflate the layout
// TODO: Null should not be passed into the view holder. This should be updated to reflect
// the inflated layout.
return DogCardViewHolder(adapterLayout)
}
override fun getItemCount(): Int {
return dogs.size
}// TODO: return the size of the data set instead of 0
override fun onBindViewHolder(holder: DogCardViewHolder, position: Int) {
// TODO: Get the data at the current position
// TODO: Set the image resource for the current dog
// TODO: Set the text for the current dog's name
// TODO: Set the text for the current dog's age
val resources = context?.resources
val dog = dogs[position]
holder.imageView.setImageResource(dog.imageResourceId)
holder.dogNameTextView.text=dog.name
holder.dogAgeTextView.text=dog.age
// TODO: Set the text for the current dog's hobbies by passing the hobbies to the
// R.string.dog_hobbies string constant.
// Passing an argument to the string resource looks like:
// resources?.getString(R.string.dog_hobbies, dog.hobbies)
holder.dogHobbiesTextView.text=resources?.getString(R.string.dog_hobbies, dog.hobbies)
}
}
dog_image id is in the following XML archives. I don't know why is null:
I would like to know how to improve this question
CodePudding user response:
dog_image
should live under each layout that could be inflated in onCreateViewHolder
meaning:
activity_grid_list
activity_vertical_list
activity_horizontal_list
if you will add it to those layout the code will run.
However, I don't think that's what you are looking for, if I understood correctly you want to inflate list's as adapter items, meaning you should have another adapter that will handle those list's item's an that adapter should inflate the dog_image
.
CodePudding user response:
The tutorial clearly states that
In
onCreateViewHolder()
, you want to either inflate thegrid_list_item
orvertical_horizontal_list_item
layout.
In your code, first you're inflating activity_grid_list
, and then overriding it with activity_vertical_list
or activity_horizontal_list
.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DogCardViewHolder {
// TODO: Use a conditional to determine the layout type and set it accordingly.
// if the layout variable is Layout.GRID the grid list item should be used. Otherwise the
// the vertical/horizontal list item should be used.
when(layout){
Layout.GRID->{
adapterLayout = LayoutInflater.from(parent.context)
.inflate(R.layout.grid_list_item, parent, false)
}
// use this, or "else->"
Layout.VERTICAL, Layout.HORIZONTAL->{
adapterLayout = LayoutInflater.from(parent.context)
.inflate(R.layout. vertical_horizontal_list_item, parent, false)
}
}
// TODO Inflate the layout
// TODO: Null should not be passed into the view holder. This should be updated to reflect
// the inflated layout.
return DogCardViewHolder(adapterLayout)
}