RecyclerView Not showing Text - android

I am new to mobile development with kotlin and I am trying to add a new item to the recyclerview.
The item is added to the recycler view but the text is not visible. I don't get what it's wrong.
I am using Kotlin in Android Studio 4.2
The class AgentAttributes only contains two properties:val Name:String ,val Value:String
**activity_main.xml**
<EditText
android:id="#+id/etSearch"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="No emp"
app:layout_constraintEnd_toStartOf="#+id/btnSearch"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/btnSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#android:string/search_go"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rvAgentAttributes"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/etSearch" />
**MainActivity.kt**
private lateinit var agentAttributesAdapter:AgentAttributesAdapter
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
//setContentView(R.layout.activity_main)
//constructor
agentAttributesAdapter = AgentAttributesAdapter(mutableListOf())
//Definition of Recycler view adapter
binding.rvAgentAttributes.adapter = agentAttributesAdapter
binding.rvAgentAttributes.layoutManager = LinearLayoutManager(this)
//THIS IS THE WAY THAT I AM TRYING TO ADD A NEW ITEM
val agentAttr = AgentAttributes("Nombre","JOEL ROMUALDO LOPEZ SALIDO")
agentAttributesAdapter.addAttributes(agentAttr)
**AgentAttributesAdapter**
class AgentViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AgentViewHolder {
return AgentViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.agent_details,
parent,
false
)
)
override fun onBindViewHolder(holder: AgentViewHolder, position: Int) {
val layoutInflater = LayoutInflater.from(holder.itemView.context)
binding = AgentDetailsBinding.inflate(layoutInflater)
//val view = binding.root
val currentAgent = agent_attributes[position]
holder.itemView.apply {
binding.tvAttribute.text = currentAgent.Name.toString()
}
}
override fun getItemCount(): Int {
return agent_attributes.size
}
fun addAttributes(attr:AgentAttributes){
agent_attributes.add(attr)
notifyItemInserted(agent_attributes.size - 1)
}

There's no need to inflate your layout in the "binding" step:
override fun onBindViewHolder(viewHolder: ChoicesViewHolder, pos: Int) {
AgentDetailsBinding.bind(viewHolder.itemView).apply {
val currentAgent = agent_attributes[position]
tvAttribute.text = currentAgent.Name.toString()
}
}
PS: variables should be lower case, so currentAgent should have a name, no Name

Related

Android Kotlin expanding textview in adapter causes unwanted expanding another textviews

I show a list of items using adapter and recyclerview. Each item shows only 4 lines of biography-textView. In order to see whole biography, user clicks 'expand' textView. My code functions but there is a problem because sometimes (somehow randomly) one 'expand' click (f.e. in item No 1) causes expanding 2-3 biography textView more in another items(f.e. items No 7 and 12). What is wrong with my code? How to check it/identify why items textView are extra expand?
Can anyone help?
class ShowMastersAdapter (
private val masterList: ArrayList<Master>,
private val itemListener: OnItemClickListener
) : RecyclerView.Adapter<ShowMastersAdapter.ShowMasterViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ShowMasterViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_master, parent, false)
return ShowMasterViewHolder(view)
}
override fun onBindViewHolder(holder: ShowMasterViewHolder, position: Int) {
holder.bindData(position)
}
override fun getItemCount(): Int {
return masterList.size
}
inner class ShowMasterViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bindData(position: Int) {
val masterBiography = itemView.findViewById<TextView>(R.id.item_master_biography)
val masterExpandBiography =itemView.findViewById<TextView>(R.id.item_master_expand_text)
masterBiography.text = masterList[position].biography
masterExpandBiography.setOnClickListener {
itemListener.onReadMoreTextClick(masterExpandBiography, masterBiography)
}
}
}
interface OnItemClickListener {
fun onReadMoreTextClick(expandText: TextView, biographyText: TextView)
}
}
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/layout_top_part">
<TextView
android:id="#+id/item_master_biography"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/item_master_margin_start"
android:layout_marginEnd="#dimen/item_master_margin_end"
android:ellipsize="end"
android:maxLines="4"
android:text="unknown"
android:textSize="#dimen/font_main_size_item_master"
app:layout_constraintBottom_toTopOf="#+id/item_master_expand_text"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/item_master_biography_label" />
<TextView
android:id="#+id/item_master_expand_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:text="#string/it_master_expand_text"
android:textColor="#color/text_as_link"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
class FragmentShowMasters() : Fragment(), ShowMastersAdapter.OnItemClickListener{
private var listOfMasters: ArrayList<Master> = ArrayList()
private lateinit var myRecycler: RecyclerView
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState:Bundle?): View {
myView = inflater.inflate(R.layout.fragment_show_masters, container, false)
myRecycler = myView.findViewById(R.id.recycler_show_masters)
myRecycler.setHasFixedSize(true)
myRecycler.adapter = ShowMastersAdapter(listOfMasters, this, highlightSearchText)
myRecycler.adapter?.notifyDataSetChanged()
myRecycler.layoutManager = LinearLayoutManager(this.context)
return myView
}
override fun onReadMoreTextClick(expandText: TextView, biographyText: TextView) {
if (biographyText.maxLines == 4) {
biographyText.maxLines = Int.MAX_VALUE
expandText.text = getString(R.string.it_master_shrink_text)
} else {
biographyText.maxLines = 4
expandText.text = getString(R.string.it_master_expand_text)
}
}
}

nested recycler view not visible

I'm trying to create a nested recycler view with data received from the server(using Retrofit). The outer recyclerview prints fine, but the inner recyclerview doesn't print at all.
No Error, No Warning...I don't know why. please Help.
my recylcerview blueprint here
Layout Code
the layout xml look like this
(1) activity_main
<androidx.coordinatorlayout.widget.CoordinatorLayout
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=".MainActivity">
<com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.appbar.CollapsingToolbarLayout ...>
<androidx.appcompat.widget.Toolbar
android:id="#+id/homeToolbar" ... />
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="#+id/homeLogo" ... />
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/homeBanner" ... />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/outerRecycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="50dp"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:layout_width="match_parent"
android:layout_height="50dp" ... />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
(2) item_outer_recycler
<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/houseImage"
android:contentDescription="main image"
android:layout_width="match_parent"
android:layout_height="150dp".../>
<TextView
android:id="#+id/houseName"
android:layout_width="200dp"
android:layout_height="30dp"
tools:text="some name" ... />
<TextView
android:id="#+id/houseAddress"
android:layout_width="300dp"
android:layout_height="20dp"
android:layout_marginStart="15dp"
tools:text="some address" ... />
<TextView
android:id="#+id/houseHomepage"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginEnd="15dp".../>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/innerRecycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
(3) item_inner_recycler
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tool="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:id="#+id/houseTag"
android:layout_width="50dp"
android:layout_height="20dp"
android:textSize="12sp"
android:textColor="#878d95"
android:background="#e4e7ed"
android:textAlignment="center"
tool:text="roop top"/>
</LinearLayout>
Adapters Code
(1) outer recycler adapter
class MainHouseHolder(val binding: ItemOuterRecyclerBinding): RecyclerView.ViewHolder(binding.root)
class MainHouseAdapter(private val context: Context, private val data: List<House>):
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun getItemCount(): Int = data.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainHouseHolder =
MainHouseHolder(ItemOuterRecyclerBinding.inflate(LayoutInflater.from(parent.context), parent, false))
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val house = data[position]
val binding = (holder as MainHouseHolder).binding
binding.innerRecycler.adapter = MainTagAdapter(house.tags)
binding.innerRecycler.layoutManager =
LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
// process outer recycler view
}
}
(2) inner recycler adapter
class MainTagHolder(val binding: ItemInnerRecyclerBinding) : RecyclerView.ViewHolder(binding.root)
class MainTagAdapter(private val data: String) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
var tagData :MutableList<String> = mutableListOf()
override fun getItemCount(): Int {
tagData = data.split(",") as MutableList<String>
return tagData.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainTagHolder =
MainTagHolder(ItemInnerRecyclerBinding.inflate(LayoutInflater.from(parent.context), parent, false))
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val binding = (holder as MainTagHolder).binding
binding.houseTag.text = tagData[position]
}
}
Activity Code
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var houseList : List<House>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.homeToolbar)
val apiClient = APIClient().connectInterface
val houseCall = apiClient.getHouseList()
houseCall.enqueue(object : Callback<HouseList> {
override fun onResponse(call: Call<HouseList>, response: Response<HouseList>) {
Log.d("CONNECTOR", "ON_RESPONSE")
houseList = response.body()?.list as List<House>
val adapter = MainHouseAdapter(applicationContext, houseList)
binding.houseList.adapter = adapter
binding.houseList.layoutManager = LinearLayoutManager(applicationContext)
adapter.notifyDataSetChanged()
}
override fun onFailure(call: Call<HouseList>, t: Throwable) {
Log.d("CONNECTOR", "FAILURE")
t.printStackTrace()
}
})
}
}
in item_outer_recycler
change
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/innerRecycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="parent" />
to
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/innerRecycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#id/houseAddress" />
I think you should change outer adapter from
class MainHouseHolder(val binding: ItemOuterRecyclerBinding): RecyclerView.ViewHolder(binding.root)
class MainHouseAdapter(private val context: Context, private val data: List<House>):
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun getItemCount(): Int = data.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainHouseHolder =
MainHouseHolder(ItemOuterRecyclerBinding.inflate(LayoutInflater.from(parent.context), parent, false))
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val house = data[position]
val binding = (holder as MainHouseHolder).binding
binding.innerRecycler.adapter = MainTagAdapter(house.tags)
binding.innerRecycler.layoutManager =
LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
// process outer recycler view
}
}
to
class MainHouseAdapter(private val context: Context, private val data: List<House>):
RecyclerView.Adapter<MainHouseAdapter.MainHouseHolder>() {
override fun getItemCount(): Int = data.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainHouseHolder =
MainHouseHolder(ItemOuterRecyclerBinding.inflate(LayoutInflater.from(parent.context), parent, false))
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val house = data[position]
val binding = (holder as MainHouseHolder).binding
binding.innerRecycler.adapter = MainTagAdapter(house.tags)
binding.innerRecycler.layoutManager =
LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
// process outer recycler view
}
inner class MainHouseHolder(val binding: ItemOuterRecyclerBinding): RecyclerView.ViewHolder(binding.root)
}
and make inner adapter like outer too
class MainTagAdapter(private val data: String) : RecyclerView.Adapter<MainTagAdapter.MainTagHolder>() {
var tagData :MutableList<String> = mutableListOf()
override fun getItemCount(): Int {
tagData = data.split(",") as MutableList<String>
return tagData.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainTagHolder =
MainTagHolder(ItemInnerRecyclerBinding.inflate(LayoutInflater.from(parent.context), parent, false))
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val binding = (holder as MainTagHolder).binding
binding.houseTag.text = tagData[position]
}
inner class MainTagHolder(val binding: ItemInnerRecyclerBinding) : RecyclerView.ViewHolder(binding.root)
}
Oh...the problem was that innerRecycler was set to app:layout_constraintTop_toBottomOf="parent" . I made a stupid mistake.
I'm sorry

RecyclerView Overwrite last element a couple times

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!

how to binding correctly recyclerview items in kotlin?

I am developing a news app and I am following MVVM with data binding in recycler view I am trying to bind items but I am just stuck below my recyclerview items xml file
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="article"
type="yodgorbek.komilov.musobaqayangiliklari.model.Article">
</variable>
</data>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp">
<ImageView
android:text="#{article.urlToImage}"
android:id="#+id/imageView"
android:layout_width="100dp"
android:layout_height="85dp"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:contentDescription="bbc"
tools:background="#color/colorPrimary" />
<TextView
android:id="#+id/articleTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_toEndOf="#id/imageView"
android:layout_toRightOf="#id/imageView"
android:ellipsize="end"
android:lines="3"
android:maxLines="3"
android:text="#{article.title}" />
<ImageView
android:id="#+id/imageCategory"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_below="#id/articleTitle"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_toEndOf="#id/imageView"
android:layout_toRightOf="#id/imageView"
android:src="#drawable/ic_espn"
tools:background="#color/colorPrimary" />
<TextView
android:id="#+id/articleSourceName"
android:layout_width="wrap_content"
android:layout_height="32dp"
android:layout_below="#id/articleTitle"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_toEndOf="#id/imageCategory"
android:layout_toRightOf="#id/imageCategory"
android:gravity="center|start"
android:text="#{article.source.name}" />
<TextView
android:id="#+id/articleTime"
android:layout_width="wrap_content"
android:layout_height="32dp"
android:layout_below="#id/articleTitle"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_toEndOf="#id/articleSourceName"
android:layout_toRightOf="#id/articleSourceName"
android:gravity="center|start"
android:text="#{article.publishedAt}"
android:textColor="#android:color/darker_gray"
tools:ignore="NotSibling" />
</RelativeLayout>
</androidx.cardview.widget.CardView>
</layout>
below TopHeadlinesAdapter.kt where I am trying to implement data binding logic
#Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS")
class TopHeadlinesAdapter(val context: Context, private val article: List<Article>) :
RecyclerView.Adapter<TopHeadlinesAdapter.MyViewHolder>() {
private var articleList: List<Article> by Delegates.observable(emptyList()) { _, _, _ ->
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val inflater =
LayoutInflater.from(parent.context)//.inflate(R.layout.news_list, parent, false)
// val binding = Article.inflate(inflater)
return MyViewHolder(article, parent)
}
override fun getItemCount(): Int {
return articleList.size
}
#SuppressLint("NewApi")
override fun onBindViewHolder(holder: MyViewHolder, position: Int) =
holder.bind(articleList[position])
//holder.articleTitle.text = articleList.get(position).title
//holder.articleSourceName.text = articleList.get(position).source.name
//Picasso.get().load(articleList.get(position).urlToImage).into(holder.image)
// val input = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX")
// val output = SimpleDateFormat("dd/MM/yyyy")
// var d = Date()
// try {
// d = input.parse(articleList[5].publishedAt)
// } catch (e: ParseException) {
// try {
// val fallback = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
// fallback.timeZone = TimeZone.getTimeZone("UTC")
// d = fallback.parse(articleList[5].publishedAt)
// } catch (e2: ParseException) {
// // TODO handle error
// val formatted = output.format(d)
// val timelinePoint = LocalDateTime.parse(formatted)
// val now = LocalDateTime.now()
//
// var elapsedTime = Duration.between(timelinePoint, now)
//
// println(timelinePoint)
// println(now)
// elapsedTime.toMinutes()
//
// holder.articleTime.text = "${elapsedTime.toMinutes()}"
//
//
fun updateData(newList: List<Article>) {
articleList = newList
Log.e("articleListSize", articleList?.size.toString())
}
inner class MyViewHolder(private val binding: Article) : RecyclerView.ViewHolder(binding.root) {
fun bind(article: Article) {
binding.article = article
// val image: ImageView = itemView!!.findViewById(R.id.imageView)
// val articleTitle: TextView = itemView!!.findViewById(R.id.articleTitle)
// val articleSourceName: TextView = itemView!!.findViewById(R.id.articleSourceName)
// val imageCategory: ImageView = itemView!!.findViewById(R.id.imageCategory)
// val articleTime: TextView = itemView!!.findViewById(R.id.articleTime)
}
}
}
below my Article.kt data class
data class Article(
val author: String,
val content: String,
val description: String,
val publishedAt: String,
val source: Source,
val title: String,
val url: String,
val urlToImage: String
)
below fragment_top_headlines.xml where I am hosting recyclerview
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:id="#+id/pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
below TopHeadlinesFragment.kt
class TopHeadlinesFragment : Fragment() {
private val viewModel by viewModel<MainViewModel>()
private lateinit var topHeadlinesAdapter: TopHeadlinesAdapter
// private val newsRepository: NewsRepository by inject()
private lateinit var article:List<Article>
//3
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(
R.layout.fragment_top_headlines
, container, false
)
val recyclerView = view.findViewById(R.id.recyclerView) as RecyclerView
val pb = view.findViewById(R.id.pb) as ProgressBar
topHeadlinesAdapter = TopHeadlinesAdapter(recyclerView.context, article)
recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.adapter = topHeadlinesAdapter
initViewModel()
return view
}
private fun initViewModel() {
viewModel?.sportList?.observe(this, Observer { newList ->
topHeadlinesAdapter.updateData(newList)
})
viewModel?.showLoading?.observe(this, Observer { showLoading ->
pb.visibility = if (showLoading) View.VISIBLE else View.GONE
})
viewModel?.showError?.observe(this, Observer { showError ->
(showError)
})
viewModel?.loadNews()
}
}
I want to know what I have to do in order to bind correctly recyclerview items and show correctly in my app?
try this in
class yourAdapterName(val context: Context, var listData:
MutableList<Article>) :
RecyclerView.Adapter<LanguageAdapter.ViewHolder>() {
lateinit var bindind: YourBinding
fun onRefresh(listData: MutableList<Article>) {
this.listData = listData
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
ViewHolder {
bindind = YourBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(bindind)
}
override fun getItemCount(): Int {
return listData.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.setData(listData[position])
}
inner class ViewHolder(private val binding: LangugaeItemBinding) : RecyclerView.ViewHolder(binding.getRoot()) {
fun setData(model: Article) {
with(binding) {
artical = model
executePendingBindings()
}
}
}
}
and call these into onViewCreated in fragment
val recyclerView = view.findViewById(R.id.recyclerView) as
RecyclerView
val pb = view.findViewById(R.id.pb) as ProgressBar
topHeadlinesAdapter = TopHeadlinesAdapter(recyclerView.context,
article)
recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.adapter = topHeadlinesAdapter
initViewModel()

How to update editText for data object in recycle view Kotlin

I am new to android studio and just starter 1 month ago for learning it.
I currently try to written the app that has list of data class with name, price, quantity and unit cost.
I have done the recycle view and i am facing the problem that how to update the editText value whenever the user input the quantity in the data classs
Below are my data class code
data class food (val food: String, val price: Int, var quantity: Int, var cost: Int = price*quantity)
object ABC {
var food_List = listOf<food>(
ABC ("A", 28 ,5) ,
ABC ("B", 28, 0)
)}
Below are my recycle view adaptor
class customAdaptor (val context: Context, val food_List:List<food>):RecyclerView.Adapter<customAdaptor.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(context).inflate(R.layout.list_layout,parent, false)
return ViewHolder(v)
}
override fun getItemCount(): Int {
return food_List.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val listused= food_List[position]
holder.setData(listused,position)
}
inner class ViewHolder (itemView: View): RecyclerView.ViewHolder(itemView) {
fun setData(listused: food?, pos: Int) {
itemView.listFoodName.text = listused!!.food
itemView.listUnitPrice.text =listused.price.toString()
itemView.listUnitTotalPrice.text=listused.cost.toString()
}
}}
Below are my mainactivity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_page_budget)
val layoutManager = LinearLayoutManager(this)
layoutManager.orientation = LinearLayoutManager.VERTICAL
recyclerview.layoutManager = layoutManager
val adapter = customAdaptor(this, ABC.food_List)
recyclerview.adapter = adapter}
Below are my layout for card view.
<androidx.cardview.widget.CardView
android:id="#+id/cardView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="270dp"
android:layout_height="wrap_content"
android:textAlignment="center"
android:id="#+id/listFoodName"/>
<TextView
android:layout_width="50dp"
android:layout_height="wrap_content"
android:textAlignment="center"
android:id="#+id/listUnitPrice"/>
<EditText
android:layout_width="50dp"
android:layout_height="wrap_content"
android:textAlignment="center"
android:inputType="numberDecimal"
android:id="#+id/listQuantity"/>
<TextView
android:layout_width="50dp"
android:layout_height="wrap_content"
android:textAlignment="center"
android:id="#+id/listUnitTotalPrice"/> -->
</LinearLayout>
</androidx.cardview.widget.CardView>
Then i didnt know how to write the editText for the update.
Please help. Thank you very much.
You should use this:
editText.afterTextChanged{doSomethingWithText(it)}
Your code would be something like:
fun setData(listused: food?, pos: Int) {
itemView.listFoodName.text =listused!!.food
itemView.listUnitPrice.text =listused.price.toString()
itemView.listUnitTotalPrice.text=listused.cost.toString()
itemView.listQuantity.afterTextChanged {
listused?.quantity = it.toInt()
itemView.listUnitTotalPrice.text=listused.cost.toString()
}
}

Categories

Resources