I have created a fragment and inside that fragment I have a recyclerview but when my fragment is loaded nothing shows and it give me this error "E/RecyclerView: No adapter attached; skipping layout". Below is the code for the adapter and fragment class, any help would be appreciated
Adapter Class:
class ViewAllRecipeAdapter(private val newList: ArrayList<Recipes>) :
RecyclerView.Adapter<ViewAllRecipeAdapter.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.view_all_recipe_item, parent, false)
return MyViewHolder(itemView)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = newList[position]
holder.recipeName.text = currentItem.recipeName
holder.recipeDesc.text = currentItem.recipeDescription
}
override fun getItemCount(): Int {
return newList.size
}
class MyViewHolder(itemview: View) : RecyclerView.ViewHolder(itemview) {
val recipeName: TextView
val recipeDesc: TextView
init {
recipeName = itemView.findViewById<View>(R.id.recipe_name) as TextView
recipeDesc = itemView.findViewById<View>(R.id.recipe_description) as TextView
}
}
}
Fragment Class:
class ViewAllMyRecipesFragment : Fragment() {
private lateinit var recyclerview: RecyclerView
private lateinit var recipeData: ArrayList<Recipes>
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view: View = inflater.inflate(R.layout.fragment_view_all_my_recipes, container, false)
recipeData = dummygenerator(10)
recyclerview = view.findViewById<RecyclerView>(R.id.recycler_view_all_recipes)
recyclerview.adapter = ViewAllRecipeAdapter(recipeData)
recyclerview.layoutManager = LinearLayoutManager(view.context)
recyclerview.setHasFixedSize(true)
// Inflate the layout for this fragment
return view
}
private fun dummygenerator(size: Int) : ArrayList<Recipes>{
val list = ArrayList<Recipes>()
for(i in 0 until size) {
val drawable = when (i % 3) {
0 -> "recipeName " +i
1 -> "recipeDescription " + i
else -> "Else " +i
}
val item = Recipes("title $i", "body")
list += item
}
return list
}
}
fragment_view_all_my_recipes.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ui.recipe.ViewAllMyRecipesFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view_all_recipes"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="#layout/view_all_recipe_item" />
</androidx.constraintlayout.widget.ConstraintLayout>
view_all_recipe_item.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/recipe_image"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginEnd="331dp"
android:layout_marginBottom="651dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="#tools:sample/avatars" />
<TextView
android:id="#+id/recipe_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="25dp"
android:text="TextView"
android:textStyle="bold"
android:textSize="18sp"
app:layout_constraintStart_toEndOf="#+id/recipe_image"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/recipe_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="10dp"
android:text="TextView"
app:layout_constraintStart_toEndOf="#+id/recipe_image"
app:layout_constraintTop_toBottomOf="#+id/recipe_name" />
</androidx.constraintlayout.widget.ConstraintLayout>
Try moving all onCreateView logic to onViewCreated and
recyclerview.layoutManager = LinearLayoutManager(requireActivity())
recyclerview.adapter = ViewAllRecipeAdapter(recipeData)
because sometimes it causes problem when layoutManager is after adapter.
Related
[enter image description here][1]
[enter image description here][2]VHFV.png
strong text
[2]: https://i.stack.imgur.com/YJOpm.png
activity_main
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#170628"
android:orientation="vertical"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_images"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
image_layout.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.cardview.widget.CardView
android:layout_width="100dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_margin="5dp"
app:cardCornerRadius="10dp"
android:layout_height="100dp">
<ImageView
android:id="#+id/big_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="#drawable/zone_images" />
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var zoneBinding: ActivityMainBinding
var image = ArrayList<String>()
lateinit var zoneAdapter:ZoneImagesAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
zoneBinding= DataBindingUtil.setContentView(this,R.layout.activity_main)
buildData()
setRecyclerView()
}
private fun buildData() {
image.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQzx__blVU5FWJAUCU4d9-E095_n3Fgy1tuxA&usqp=CAU")
image.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQh90iDDn5BoUnZqANXUszd17_Q-RhfRo8V6Q&usqp=CAU")
image.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQzx__blVU5FWJAUCU4d9-E095_n3Fgy1tuxA&usqp=CAU")
image.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQh90iDDn5BoUnZqANXUszd17_Q-RhfRo8V6Q&usqp=CAU")
image.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQzx__blVU5FWJAUCU4d9-E095_n3Fgy1tuxA&usqp=CAU")
image.add("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQh90iDDn5BoUnZqANXUszd17_Q-RhfRo8V6Q&usqp=CAU")
}
private fun setRecyclerView() {
zoneAdapter = ZoneImagesAdapter(image)
val flexboxLayoutManager = FlexboxLayoutManager(this)
flexboxLayoutManager.flexDirection =FlexDirection.ROW
flexboxLayoutManager.flexWrap = FlexWrap.WRAP
flexboxLayoutManager.justifyContent = JustifyContent.CENTER
flexboxLayoutManager.alignItems = AlignItems.STRETCH
zoneBinding.rvImages.apply {
adapter=zoneAdapter
layoutManager=flexboxLayoutManager
}
}
Adapter
class ZoneImagesAdapter (var listOfImageUrl:ArrayList<String>):
RecyclerView.Adapter<ZoneImagesAdapter.ImageViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageViewHolder {
val view: View = LayoutInflater.from(parent.context)
.inflate(R.layout.big_image_layout, parent, false)
return ImageViewHolder(view)
}
override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
val image = listOfImageUrl[position]
holder.setImages(image)
}
override fun getItemCount(): Int {
return listOfImageUrl.size
}
class ImageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var zoneImage:ImageView=itemView.findViewById(R.id.big_image)
fun setImages(images: String) {
Glide.with(zoneImage).load(images).into(zoneImage)
val layoutParams:ViewGroup.LayoutParams = zoneImage.layoutParams
if (layoutParams is FlexboxLayoutManager.LayoutParams){
val flexboxLp:FlexboxLayoutManager.LayoutParams= layoutParams as FlexboxLayoutManager.LayoutParams
flexboxLp.flexGrow= 1.0f
}
}
}
}
How can I achieve this layout that is showing inside image using recyclerView, ?? I use flexboxLayoutManager for this but I do not know how can I used, Can anyone help me to make this layout that is showing inside image
I'm using MVVC pattern and I'm populating a recyclerView with data from database using Room. At the Logcat, data return correctly and is looped correctly, but recyclerview display seven elements and in the eighth starts to overwrite it with the nineth and tenth elements e after that create 2 more elements with the first 2 elements from list.
I'm coudn't find what is wrong with my code.
So, I'm asking for some help.
AvaliacaoFragment.kt:
class AvaliacaoFragment : Fragment() {
private lateinit var ctx: Context
private var _binding: FragmentAvaliacaoBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
private lateinit var textoSemSecoes: TextView
private lateinit var nomeAvaliacao: TextView
private lateinit var dataAvaliacao: TextView
private val args by navArgs<AvaliacaoFragmentArgs>()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
_binding = FragmentAvaliacaoBinding.inflate(inflater, container, false)
return binding.root
// return inflater.inflate(R.layout.fragment_avaliacoes, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
ctx = view.context
// dialogNovaAvaliacao = MaterialAlertDialogBuilder(ctx, android.R.style.Theme_DeviceDefault_Light_NoActionBar_Fullscreen)
// dialogNovaAvaliacao = MaterialAlertDialogBuilder(ctx,R.style.AlertDialogTheme)
// val builder = MaterialDatePicker.Builder.datePicker()
textoSemSecoes = view.findViewById(R.id.texto_sem_secoes)
nomeAvaliacao = view.findViewById(R.id.nome_avaliacao)
dataAvaliacao = view.findViewById(R.id.data_avaliacao)
nomeAvaliacao.text = args.currentAvaliacao.nome
dataAvaliacao.text = args.currentAvaliacao.dataCriacao
/*
btnAddAvaliacao = view.findViewById(R.id.btn_add_avaliacao)
btnAddAvaliacao.setOnClickListener {
findNavController().navigate(R.id.action_navigation_avaliacoes_to_addAvaliacaoFragment)
}
*/
// Recycler
val recyclerAdapter = SecaoAdapter()
val recyclerView = binding.secaoRecyclerView
recyclerView.adapter = recyclerAdapter
recyclerView.layoutManager = LinearLayoutManager(requireContext())
// ViewModelFactory para passar argumentos para a ViewModel
val factory = object : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return SecaoViewModel(Application(), args.currentAvaliacao.id) as T
}
}
// ViewModel
mSecaoViewModel = ViewModelProvider(this, factory).get(SecaoViewModel::class.java)
mSecaoViewModel.readAllData.observe(viewLifecycleOwner, Observer { secaoList ->
if(secaoList.isNotEmpty()){
Log.d(TAG, "secaoList: ${secaoList.toString()}")
Log.d(TAG, "secaoList.size: ${secaoList.size}")
textoSemSecoes.visibility = View.GONE
recyclerView.visibility = View.VISIBLE
recyclerAdapter.setData(secaoList.sortedBy { it.codigo.toInt() })
} else {
textoSemSecoes.visibility = View.VISIBLE
recyclerView.visibility = View.GONE
}
})
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
companion object {
private val TAG: String = AvaliacaoFragment::class.java.name
lateinit var mSecaoViewModel: SecaoViewModel
private lateinit var btnAddSecao: FloatingActionButton
private lateinit var dialogNovaSecao: MaterialAlertDialogBuilder
}
}
SecaoAdapter.kt:
class SecaoAdapter: RecyclerView.Adapter<SecaoAdapter.SecaoViewHolder>() {
private val TAG: String = SecaoAdapter::class.java.name
private var secaoList = emptyList<Secao>()
private lateinit var binding: ItemSecaoBinding
class SecaoViewHolder(itemBinding: ItemSecaoBinding): RecyclerView.ViewHolder(itemBinding.root) {
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SecaoViewHolder {
binding = ItemSecaoBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return SecaoViewHolder(binding)
}
override fun getItemCount(): Int {
return secaoList.size
}
override fun onBindViewHolder(holder: SecaoViewHolder, position: Int) {
Log.d(TAG, "position: $position")
val currentItem = secaoList[position]
Log.d(TAG, "currentItem: ${currentItem.toString()}")
binding.secaoCodigo.text = currentItem.codigo
binding.secaoNome.text = currentItem.nome
binding.secaoMediaTotal.text = currentItem.mediaPositivo.toString()
binding.secaoPerguntasNaoAplicaveis.text = currentItem.qdePerguntasNaoAplicaveis.toString()
binding.secaoPerguntasRespondidas.text = currentItem.qdePerguntasRespondidas.toString()
binding.secaoPerguntasTotais.text = currentItem.qdePerguntas.toString()
binding.cardSecao.setOnClickListener {
val action = AvaliacaoFragmentDirections.actionAvaliacaoFragmentToSecaoFragment(currentItem)
holder.itemView.findNavController().navigate(action)
}
}
fun setData(secao: List<Secao>){
this.secaoList = secao
notifyDataSetChanged()
}
}
fragment_avaliacao.xml:
<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorPrimaryDark"
tools:context=".ui.secoes.AvaliacaoFragment">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/container_titulo_avaliacao"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
>
<TextView
android:id="#+id/nome_avaliacao"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="#string/padrao_avaliacao_sem_nome"
android:textSize="24sp"
android:textColor="#color/colorIcons"
android:textAlignment="center"
/>
<TextView
android:id="#+id/data_avaliacao"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="#string/padrao_formato_data_hora"
android:textSize="14sp"
android:textColor="#color/colorPrimaryLight"
android:textAlignment="center"
/>
</LinearLayout>
<TextView
android:id="#+id/texto_sem_secoes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#+id/container_titulo_avaliacao"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:textAlignment="center"
android:textSize="16sp"
android:text="#string/nenhuma_secao_criada"
android:textColor="#color/colorPrimaryLight"
/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/secaoRecyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="#+id/container_titulo_avaliacao"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout></androidx.constraintlayout.widget.ConstraintLayout>
Logcat loop from secaoList at the SecaoAdapter (is looping correctly to all elements):
I create a gif to show what is happening with the elements on recyclerView:
Here you can see that it displays seventh element then eighth is replaced by nineth and subsequently replaced by tenth. And final two elements (that should be ninth and tenth) is constructed with first and second list elements.
Thanks for the help in advance.
So the mistake here is that you are referencing only one binding in your adapter which is getting overwritten. Every time you call onCreateViewHolder you are changing the binding reference. The reason this looks okay to start with is that the onCreateViewHolder calls are followed by the onBindViewHolder calls for items visible on the screen. However as you scroll, just onBindViewHolder is called in order to rebind the recycled views.
What you should be doing is using your ViewHolder to store the individual bindings and then obtaining a reference in onBindViewHolder with something like holder.binding.
I would recommend you have a read into the view holder pattern and how to implement it!
I am brand new in Android/kotlin development. I created my very first app with a recyclerView to display the folders and files of the phone. I put the recyclerView into a segment, created my data structure and adapter. Assembled together. It works - or seems to work. But the problem is that when I try to scroll the list, the initial state remains "ther" and the list content starts to scroll. Like it was two different layers. I have no clue where to find the problem. Never heard about such a bug like this. Please give me advice, some keywords where to dig and find the solution. Thanks!
class BrowseFileFragment : Fragment() {
private lateinit var attachedCtx : Context
override fun onAttach(context: Context) {
super.onAttach(context)
this.attachedCtx = context
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View?
{
var view : View = inflater.inflate(R.layout.fragment_browse_file, container, false)
val modelFactory = FileBrowseModelFactory()
val data = modelFactory.create()
bindModelToView(data, view)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
private fun bindModelToView(data: BrowseSettings, view: View)
{
var adapter = MyFileAdapter(data.FoldersAndFiles, this.attachedCtx)
var recyclerView = view.findViewById<RecyclerView>(R.id.fileItemView)
var linearLayoutManager = LinearLayoutManager(this.attachedCtx)
recyclerView.layoutManager = linearLayoutManager
recyclerView.adapter = adapter
var folderLabel = view.findViewById<TextView>(R.id.folderName)
folderLabel.text = data.CurrentFolder
}
}
The segment layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".BrowseFileFragment">
<TextView
android:id="#+id/folderName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="#string/hello_first_fragment"
android:textAlignment="viewStart"
android:textAppearance="#style/TextAppearance.AppCompat.Display1"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/fileItemView"
android:layout_width="match_parent"
app:layout_constrainedHeight="true"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="#+id/folderName"
app:layout_constraintStart_toStartOf="#+id/folderName"
app:layout_constraintTop_toBottomOf="#+id/folderName" />
</androidx.constraintlayout.widget.ConstraintLayout>
The list line layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:background="#color/cardview_shadow_start_color"
android:id="#+id/itemName"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toTopOf="parent"
android:padding="5dp"
android:textSize="30dp"
android:textStyle="bold" />
</androidx.constraintlayout.widget.ConstraintLayout>
And finally my adapter:
class MyFileAdapter(private val items: List<FileItem>, private val context: Context)
: RecyclerView.Adapter<MyFileAdapter.MyViewHolder>()
{
class MyViewHolder (itemView: View) :RecyclerView.ViewHolder(itemView), View.OnClickListener {
init {
itemView.setOnClickListener(this)
}
fun bindItem(f: FileItem) {
var name: TextView = itemView.findViewById(R.id.itemName) as TextView
name.text = f.Name
}
}
override fun getItemCount() = items.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = LayoutInflater
.from(context)
.inflate(R.layout.recyclerview_filteitem_row, parent, false)
return MyViewHolder(view)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
var item = items\[position\]
holder!!.bindItem( item )
}
}
It found out that as the whole list view is saved as a segment, this segment loads "automatically" and was loaded programatically also, and the two "loads" causes this thing. :( Thanks for your time guys.
I want to achieve a layout as shown in the Android Studio preview (left). However if executed in the emulator, only the button is visible and the RecyclerView is not visible/populated (right).
The XML code:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
style="#style/AppTheme">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/list"
android:name="com.example.app.ItemFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"
tools:context=".ItemFragment"
tools:listitem="#layout/fragment_item"
android:scrollbars="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/floatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_margin="#dimen/fab_margin"
android:clickable="true"
android:focusable="true"
android:src="#android:drawable/ic_input_add"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
However if the RecyclerView is alone in the fragment the list is populated (but of course the action button is not showing). Code see below. And yes, my list which should be shown is not empty.
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/list"
android:name="com.example.app.ItemFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"
tools:context=".ItemFragment"
tools:listitem="#layout/fragment_item" >
</androidx.recyclerview.widget.RecyclerView>
I have already tried using RelativeLayout and FrameLayout, but I still get the same result. The same behavior occurs if I use e.g. a TextView instead of the action button.
--- Requested additional info ---
Adapter class (automatically generated by Android Studio, template):
class MyItemRecyclerViewAdapter(
private val mValues: List<DummyItem>,
private val mListener: OnListFragmentInteractionListener?
) : RecyclerView.Adapter<MyItemRecyclerViewAdapter.ViewHolder>() {
private val mOnClickListener: View.OnClickListener
init {
mOnClickListener = View.OnClickListener { v ->
val item = v.tag as DummyItem
// Notify the active callbacks interface (the activity, if the fragment is attached to
// one) that an item has been selected.
mListener?.onListFragmentInteraction(item)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.fragment_item, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = mValues[position]
holder.mIdView.text = item.id
holder.mContentView.text = item.content
with(holder.mView) {
tag = item
setOnClickListener(mOnClickListener)
}
}
override fun getItemCount(): Int = mValues.size
inner class ViewHolder(val mView: View) : RecyclerView.ViewHolder(mView) {
val mIdView: TextView = mView.item_number
val mContentView: TextView = mView.content
override fun toString(): String {
return super.toString() + " '" + mContentView.text + "'"
}
}
}
List fragment (automatically generated by Android Studio, template):
class ItemFragment : Fragment() {
// TODO: Customize parameters
private var columnCount = 1
private var listener: OnListFragmentInteractionListener? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
columnCount = it.getInt(ARG_COLUMN_COUNT)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_item_list, container, false)
// Set the adapter
if (view is RecyclerView) {
with(view) {
layoutManager = when {
columnCount <= 1 -> LinearLayoutManager(context)
else -> GridLayoutManager(context, columnCount)
}
adapter = MyItemRecyclerViewAdapter(DummyContent.ITEMS, listener)
}
}
return view
}
override fun onAttach(context: Context) {
super.onAttach(context)
if (context is OnListFragmentInteractionListener) {
listener = context
} else {
throw RuntimeException(context.toString() + " must implement OnListFragmentInteractionListener")
}
}
override fun onDetach() {
super.onDetach()
listener = null
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
*
*
* See the Android Training lesson
* [Communicating with Other Fragments](http://developer.android.com/training/basics/fragments/communicating.html)
* for more information.
*/
interface OnListFragmentInteractionListener {
// TODO: Update argument type and name
fun onListFragmentInteraction(item: DummyItem?)
}
companion object {
// TODO: Customize parameter argument names
const val ARG_COLUMN_COUNT = "column-count"
// TODO: Customize parameter initialization
#JvmStatic
fun newInstance(columnCount: Int) =
ItemFragment().apply {
arguments = Bundle().apply {
putInt(ARG_COLUMN_COUNT, columnCount)
}
}
}
}
Try this for your layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="#style/AppTheme"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/list"
android:name="com.example.app.ItemFragment"
android:layout_width="0dp"
android:layout_height="0dp"
android:scrollbars="vertical"
app:layoutManager="LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:context=".ItemFragment"
tools:listitem="#layout/fragment_item" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/floatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_margin="#dimen/fab_margin"
android:clickable="true"
android:focusable="true"
android:src="#android:drawable/ic_input_add"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Inside ItemFragment.kt replace onCreateView with
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_item_list, container, false)
}
After that go ahead and implement onViewCreated as such
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
with(list) {
layoutManager = when {
columnCount <= 1 -> LinearLayoutManager(requireContext())
else -> GridLayoutManager(requireContext(), columnCount)
}
adapter = MyItemRecyclerViewAdapter(DummyContent.ITEMS)
}
}
This should fix your problem because the AS template is assuming that the rootview will be a RecyclerView and is treating the whole layout as such.
I am trying to develop social networking app which uses Android Jetpack Libraries but while using Navigation Component to use bottom navigation to navigate through fragments inside an activity , This Adapter throws an error at LayoutInflator() which causes app to crash
Can anyone help me through this:
My Adapter Class:
class FeedAdapter : PagedListAdapter<feed,FeedAdapter.ViewHolder>(FeedDiffCallBack()){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val userPost = LayoutInflater.from(parent.context)
.inflate(R.layout.feedrow,parent,false)
return ViewHolder(userPost)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val feedItem = getItem(position)
if(feedItem != null){
holder.bind(feedItem)
}
}
class ViewHolder(itemView:View):RecyclerView.ViewHolder(itemView) {
//Retrieve data
private val username:TextView = itemView.post_name
private val userPic:ImageView = itemView.feedImage1
private val location:TextView = itemView.postLocation
private val time:TextView = itemView.postTime
private val post:ImageView = itemView.postImage
fun bind(feed: feed) = with(itemView){
//TODO:Bind Data with View
showFeedData(feed)
}
private fun showFeedData(feed: feed) {
username.text = feed.username
userPic.setImageURI(null)
userPic.visibility = View.GONE
location.text = feed.location
time.text = feed.timeStamp.toString()
post.setImageURI(Uri.parse(feed.mUrl))
}
}
}
class FeedDiffCallBack : DiffUtil.ItemCallback<feed>() {
override fun areItemsTheSame(oldItem:feed, newItem: feed): Boolean {
return oldItem?.id == newItem?.id
}
override fun areContentsTheSame(oldItem: feed, newItem: feed): Boolean {
return oldItem == newItem
}
}
Fragment Class:
class FeedFragment : Fragment() {
companion object {
fun newInstance() = FeedFragment()
}
private lateinit var viewModel: FeedViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.feed_fragment, container, false)
val context = getContext() ?: return view
val factory = InjectorUtils.provideViewModelFactory(context)
viewModel =
ViewModelProviders.of(this,factory).get(FeedViewModel::class.java)
val adapter = FeedAdapter()
view.findViewById<RecyclerView>(R.id.feedView).adapter = adapter
view.findViewById<RecyclerView>(R.id.feedView).layoutManager =
LinearLayoutManager(MyApplication.getContext())
subscribeUI(adapter)
return view
}
private fun subscribeUI(adapter: FeedAdapter) {
viewModel.showFeed().observe(this, object:Observer<PagedList<feed>>{
override fun onChanged(t: PagedList<feed>?) {
adapter.submitList(t)
adapter.notifyDataSetChanged()
}
})
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
}
}
feed_row.xml
Individual item for recycler view -->
<RelativeLayout
android:id="#+id/postContainer"
android:layout_margin="10dp"
android:elevation="2dp"
android:background="#drawable/bg_parent_rounded_corner"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--TODO:Change to Circle Image View-->
<ImageView
android:id="#+id/profileImage"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginTop="5dp"
android:layout_marginLeft="5dp"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
/>
<LinearLayout
android:id="#+id/postDetail_1"
android:orientation="vertical"
android:layout_marginTop="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="20dp"
android:layout_alignParentRight="true">
<TextView
android:id="#+id/post_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="#style/LabelStyle"
android:textSize="15sp"
android:fontFamily="#font/sf_pro_display_semibold" />
<LinearLayout
android:id="#+id/postDetail_2"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/postLocation"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/postTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="120dp" />
</LinearLayout>
</LinearLayout>
<ImageView
android:id="#+id/postImage"
android:layout_height="200dp"
android:layout_width="match_parent"
android:layout_below="#+id/postDetail_1"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:layout_marginTop="6dp"
/>
</RelativeLayout>
Your issue might be in this method,
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val feedItem = getItem(position)
if(feedItem != null){
holder.bind(feedItem)
}
}
Your ViewHolder is using poisition from method parameter which might be inconsistent
See from here,
So, you should change line to this:
val feedItem = getItem(holder.adapterPosition)
instead of
val feedItem = getItem(position)
I hope it resolves the issue.
This might help some one looking for the same Exception to be cleared :
What I did is that my feed_row.xml above is included inside < layout > tags and I changed it in this way , So the exception got cleared:
Before Exception:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
After changing to this Exception cleared:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
I don't know how it works but it did work!!! So Anyone who knows what happens there can explain please!