AutoCompeleteTextView is not show ArrayList in dropDown kotlin using ViewBinding - kotlin

AutoCompleteTextView is Replace with Spinner. AutoCompleteTextview inside TextInputLayout in Xml.
Data Fill using Custom ArrayAdapter in AutoCompeleteTextView but Data is not Show in AutoComplete TextView dropdowm.
MainActivity.kt
val numberList = ArrayList<Serve>()
numberList.add(Serve("101"))
numberList.add(Serve("101/2"))
numberList.add(Serve("201"))
numberList.add(Serve("202/3"))
numberList.add(Serve("205/1"))
val adapterSeveNo = CustomArrayAdapter(this,serveNo)
binding.autoCTVServeNo.setAdapter(adapterSeveNo)
binding.autoCTVServeNo.setOnItemClickListener { adapterView, view, i, l ->
val selectedItem = adapterView.getItemAtPosition(i).toString()
Toast.makeText(this,selectedItem,Toast.LENGTH_LONG).show()
}
activity.main.xml
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/tilListNumber"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
app:boxBackgroundMode="outline"
app:endIconMode="clear_text"
android:hint="Select Number.*"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/btnProductNext">
<AutoCompleteTextView
android:id="#+id/autoCTVServeNo"
android:layout_width="match_parent"
android:layout_height="60dp"
android:paddingStart="10dp"
android:paddingLeft="10dp"
android:inputType="none"/>
</com.google.android.material.textfield.TextInputLayout>
CustomArrayAdapter.kt
class CustomArrayAdapter( context: Context, val serveNo : ArrayList<Serve>) : ArrayAdapter<Serve>(context,0,serveNo) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val binding = DropDownItemBinding.inflate(inflater)
val ser = serveNo.get(position)
binding.tvDropDown.text = ser.serveNo
return binding.root
}
}
drop_down_item.xml
<TextView
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/tvDropDown"
android:padding="16dp"
android:maxLines="1"
android:ellipsize="end"
android:textAppearance="#style/TextAppearance.MaterialComponents.Subtitle1">
</TextView>
AutoCompleteTextview drop down is not data fill from ArrayList using ArrayAdapter in Viewbinding.

Related

Artefacts when implementing expandable items in RecyclerView

I'm trying to make a simple RecyclerView with expandable items using Kotlin. Basically a list of bins which expand out to show descriptions of what should go in them. I tried to follow the Android Studio Recycler View example as closely as possible. The problem is when I expand each item, some artefacts would show.
Unexpanded view
Expanded view
Note: The expanded view is the result of pressing on "Recycling Bin", the artefact is made up of the bin's description text and also "Garden Waste Bin" somehow being duplicated.
Below is my implementation
Adapter class
class BinAdapter(private val dataSet: List<Bin>) : RecyclerView.Adapter<BinViewHolder>() {
var expandedPosition = -1
var previousExpandedPosition = -1
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BinViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.bin_row_item, parent, false)
return BinViewHolder(view)
}
override fun onBindViewHolder(viewHolder: BinViewHolder, position: Int) {
viewHolder.itemView.isActivated
viewHolder.titleView.text = dataSet[position].name
viewHolder.descriptionView.text = dataSet[position].description
val isExpanded = position == expandedPosition
viewHolder.descriptionView.visibility = if (isExpanded) View.VISIBLE else View.GONE
viewHolder.itemView.isActivated = isExpanded
if (isExpanded) {
previousExpandedPosition = position
}
viewHolder.itemView.setOnClickListener {
expandedPosition = if (isExpanded) -1 else position
notifyItemChanged(previousExpandedPosition)
notifyItemChanged(position)
}
}
override fun getItemCount() = dataSet.size
Fragment class
class BinLookupFragment : Fragment() {
private var _binding: FragmentBinLookupBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentBinLookupBinding.inflate(inflater, container, false)
binding.binRecyclerView.adapter = BinAdapter(BinList(resources))
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
ViewHolder class
class BinViewHolder(itemView: View) : ViewHolder(itemView) {
val titleView: TextView
val descriptionView: TextView
init {
titleView = itemView.findViewById(R.id.titleView)
descriptionView = itemView.findViewById(R.id.descriptionView)
}
}
Row item layout
<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="wrap_content">
<TextView
android:id="#+id/titleView"
android:layout_width="#dimen/bin_list_width"
android:layout_height="#dimen/bin_list_item_title_height"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="#+id/descriptionView"
android:layout_width="#dimen/bin_list_width"
android:layout_height="#dimen/bin_list_item_description_height"
app:layout_constraintTop_toBottomOf="#id/titleView"
app:layout_constraintStart_toStartOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
fragment layout
<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/bin_recycler_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="200dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Has anyone come across this before or have some debugging tips?

Recycler View not displaying inside a Fragment

I'm using Recycler view to show items in my Fragment named Recent History. I want to display user data from firebase to my recent history Fragment. But the recycler view is not showing on the fragment. Please Help me out in this. What did I do wrong here? or what's the solution so that my fragment shows the recycler view.
Recent History Fragment Code:
`
class recent_history : Fragment(R.layout.fragment_recent_history) {
private var binding: FragmentRecentHistoryBinding? = null
private lateinit var auth: FirebaseAuth
var database: FirebaseDatabase? = null
var databaseReference: DatabaseReference? = null
private lateinit var userArrayList: ArrayList<User>
private lateinit var myAdapter: AdapterClass
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentRecentHistoryBinding.inflate(inflater, container, false)
return binding!!.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
auth = FirebaseAuth.getInstance()
database = FirebaseDatabase.getInstance()
databaseReference = database?.reference!!.child("Users").child("result")
userArrayList= arrayListOf()
myAdapter=AdapterClass(userArrayList)
binding?.recyclerview.apply {
binding?.recyclerview?.adapter = myAdapter
var linearLayoutManager = LinearLayoutManager(activity)
binding?.recyclerview?.layoutManager = linearLayoutManager
binding?.recyclerview?.setHasFixedSize(true)
}
getData()
}
override fun onDestroy() {
super.onDestroy()
binding = null
}
private fun getData() {
val user = auth.currentUser
databaseReference?.child(user?.uid!!)
databaseReference!!.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
for (data in snapshot.children) {
var model = data.getValue(User::class.java)
userArrayList.add(model!!)
}
}
}
override fun onCancelled(error: DatabaseError) {
Log.e("cancel", error.toString())
}
})
}
}
`
Fragment Recent History 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"
android:background="#color/white"
tools:context=".recent_history">
<TextView
android:id="#+id/profiletitle"
android:layout_width="389dp"
android:layout_height="46dp"
android:layout_marginStart="4dp"
android:layout_marginTop="28dp"
android:fontFamily="monospace"
android:text="Recent Search History"
android:textAlignment="center"
android:textColor="#color/Twit"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</TextView>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerview"
android:layout_width="220dp"
android:layout_height="664dp"
android:layout_marginBottom="100dp"
android:orientation="vertical"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/profiletitle"
tools:listitem="#layout/adapterview">
</androidx.recyclerview.widget.RecyclerView>
</androidx.constraintlayout.widget.ConstraintLayout>
I'm sending data to firebase from another Fragment named keyword Fragment.
Code of keyword fragment:
class keywordfrag : Fragment() {
private var binding: FragmentKeywordfragBinding? = null
private lateinit var auth: FirebaseAuth
var database: FirebaseDatabase? = null
var databaseReference: DatabaseReference? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentKeywordfragBinding.inflate(inflater, container, false)
return binding!!.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
auth = FirebaseAuth.getInstance()
database = FirebaseDatabase.getInstance()
val user = auth.currentUser
databaseReference?.child(user?.uid!!)
databaseReference = database?.getReference("Users")?.child("result")
binding?.analyzebtn?.setOnClickListener {
sendData()
}
}
override fun onDestroy() {
super.onDestroy()
binding = null
}
private fun sendData() {
val keywordtext = binding?.userenteredkeyword?.text.toString().trim()
val timestamp = Timestamp(System.currentTimeMillis())
val timendate = timestamp.toString().trim()
// val username=auth.currentUser?.uid.toString().trim()
// val email=auth.currentUser?.email.toString().trim()
if (TextUtils.isEmpty(keywordtext)) {
binding?.userenteredkeyword?.error = "keyword can not be Empty"
} else {
val model = User(keywordtext, timendate)
val user = auth.currentUser
databaseReference?.child(user?.uid!!)?.setValue(model)
binding?.userenteredkeyword?.setText("")
val currentUser = auth.currentUser
val currentUserdb = databaseReference?.child((currentUser?.uid!!))
currentUserdb?.child("keywordtext")?.setValue(keywordtext)
currentUserdb?.child("timendate")?.setValue(timendate)
}
}
}
Adapter Class:
package com.example.emotela_finalyearproject
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.emotela_finalyearproject.databinding.AdapterviewBinding
import kotlin.collections.ArrayList
class AdapterClass(var list:ArrayList<User>) :RecyclerView.Adapter<AdapterClass.ViewHolder>() {
class ViewHolder(val binding: AdapterviewBinding) : RecyclerView.ViewHolder(binding.root) {
var keyword = binding.keywordtv
var timenddate=binding.timendatetv
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = AdapterviewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
with(holder) {
with(list[position]) {
keyword.text = this.keywordtext
timenddate.text= this.timendate
}
}
}
}
Adapter view Layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:cardElevation="8dp"
app:cardCornerRadius="8dp"
android:layout_margin="16dp">
<LinearLayout
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginVertical="6dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="336dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="#+id/keywordtitle"
android:layout_width="141dp"
android:layout_height="35dp"
android:fontFamily="monospace"
android:text="searched word: "
android:textSize="10sp"
android:textStyle="bold">
</TextView>
<TextView
android:id="#+id/keywordtv"
android:layout_width="143dp"
android:layout_height="36dp"
android:fontFamily="monospace"
android:textSize="10sp">
</TextView>
<TextView
android:id="#+id/timeanddatetitle"
android:layout_width="160dp"
android:layout_height="36dp"
android:fontFamily="monospace"
android:text="Time and Date: "
android:textSize="10sp"
android:textStyle="bold">
</TextView>
<TextView
android:id="#+id/timendatetv"
android:layout_width="171dp"
android:layout_height="48dp"
android:fontFamily="monospace"
android:textSize="10sp">
</TextView>
<LinearLayout
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginVertical="6dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="336dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:orientation="vertical">
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
Result in Emulator:
You need to calll
imageAdapter.notifyDataSetChanged()
after you fetch the data from firebase.

How to display a TextView when Recycler View is empty?

I would like to display a textView when my RecyclerView is empty.
I prepared this function but it doesn't work. I believe I should get the list from RecyclerView but I don't really know how.
I am in a fragment.
XML:
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="#layout/item_list" />
<TextView
android:id="#+id/tv_no_records"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="#string/nothing_to_display"
android:textSize="16sp"
android:visibility="gone" />
Fragment:
private fun displayList() {
val list = listOf<Shoe>()
if (list.isEmpty()) {
binding.recyclerViewList.visibility = View.VISIBLE
binding.tvNoRecords.visibility = View.GONE
} else {
binding.recyclerViewList.visibility = View.GONE
binding.tvNoRecords.visibility = View.VISIBLE
}
}
Adding the shoe (in ViewModel):
fun addShoe(shoe: Shoe) {
viewModelScope.launch(Dispatchers.IO) {
repository.addShoes(shoe)
}
}
Many thanks,
Anna
The conditions are inverted. When list is empty you are showing recyclerView and vice versa. Simply use a not check.
Consider below:
private fun displayList() {
val list = listOf<Shoe>()
if (list.isNotEmpty()) {
binding.recyclerViewList.visibility = View.VISIBLE
binding.tvNoRecords.visibility = View.GONE
} else {
binding.recyclerViewList.visibility = View.GONE
binding.tvNoRecords.visibility = View.VISIBLE
}
}

Kotlin doesnt get the data from the binding viewModel

I'm trying to get the data that the user is enter in the autocompleteview but i doesnt receive it in the viewModel.
There's the xml file,
<layout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="connectionViewModel"
type="com.example.soccerinfo.connection.ConnectionViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<AutoCompleteTextView
android:id="#+id/mail"
style="#style/textStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/enter_your_mail"
android:inputType="textEmailAddress"
android:text="#{connectionViewModel._connectionMailId}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.23000002" />
<Button
android:id="#+id/connectionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/sign_in"
android:onClick="#{() -> connectionViewModel.onConnection()}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/mail" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
There is the viewModel, in the insertUpdate function I'm trying to display the connectionMailId. The connectionMailId display an empty string when I want to display ion the logs
class ConnectionViewModel(
val database: ConnectionDataBaseDao,
private val app : Application) : AndroidViewModel(app){
private val _eventConnectionMade = MutableLiveData<Boolean>()
val eventConnectionMade : LiveData<Boolean>
get() = _eventConnectionMade
val _mails : MutableLiveData<List<Connection>> = MutableLiveData()
var _connectionMailId = String()
init {
viewModelScope.launch(Dispatchers.IO) {
_mails.postValue(database.getAllConnections())
}
_connectionMailId = ""
}
fun insertUpdateConnection(mail: String){
viewModelScope.launch(Dispatchers.IO){
Timber.i("Email binding : $_connectionMailId")
var connection = Connection(mail)
if (requireNotNull(_mails.value?.any { connection -> connection.mailId.equals(mail) })){
update(connection)
}else{
insert(connection)
}
}
}
I hope you will help thanks a lot.
Try making _connectionMailId a live data of type String:
var _connectionMailId = MutableLiveData<String>()
also, use two way data binding:
android:text="#={connectionViewModel._connectionMailId}"

Root casue for NoSuchElementException: Collection is empty

I am facing Crash in Firebase Crashlytics on bind method but unable to find the root cause. I have added a Null check but still, the issue not fixed.
Firebase Crash Report
Fatal Exception: java.util.NoSuchElementException: Collection is empty.
at kotlin.collections.CollectionsKt___CollectionsKt.first(_Collections.kt:184)
at com.transferhome.contacts.ContactsAdapter.bind(ContactsAdapter.kt:25)
at com.transferhome.contacts.ContactsBaseAdapter.onBindViewHolder(ContactsBaseAdapter.kt:38)
at com.transferhome.contacts.ContactsBaseAdapter.onBindViewHolder(ContactsBaseAdapter.kt:19)
at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:6781)
at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:6823)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:5752)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6019)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5858)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5854)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2230)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1557)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1517)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:612)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3924)
at androidx.recyclerview.widget.RecyclerView.onMeasure(RecyclerView.java:3336)
at android.view.View.measure(View.java:22216)
at androidx.constraintlayout.widget.ConstraintLayout.internalMeasureChildren(ConstraintLayout.java:1227)
at androidx.constraintlayout.widget.ConstraintLayout.onMeasure(ConstraintLayout.java:1572)
at android.view.View.measure(View.java:22216)
at androidx.viewpager.widget.ViewPager.onMeasure(ViewPager.java:1638)
at android.view.View.measure(View.java:22216)
at androidx.constraintlayout.widget.ConstraintLayout.onMeasure(ConstraintLayout.java:1676)
at android.view.View.measure(View.java:22216)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6671)
at androidx.coordinatorlayout.widget.CoordinatorLayout.onMeasureChild(CoordinatorLayout.java:733)
at com.google.android.material.appbar.HeaderScrollingViewBehavior.onMeasureChild(HeaderScrollingViewBehavior.java:95)
at com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior.onMeasureChild(AppBarLayout.java:1556)
at androidx.coordinatorlayout.widget.CoordinatorLayout.onMeasure(CoordinatorLayout.java:803)
at android.view.View.measure(View.java:22216)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6671)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at androidx.appcompat.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:143)
at android.view.View.measure(View.java:22216)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6671)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1539)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:823)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:702)
at android.view.View.measure(View.java:22216)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6671)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at android.view.View.measure(View.java:22216)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6671)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1539)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:823)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:702)
at android.view.View.measure(View.java:22216)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6671)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at com.android.internal.policy.DecorView.onMeasure(DecorView.java:831)
at android.view.View.measure(View.java:22216)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2589)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1631)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1885)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1515)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7266)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:981)
at android.view.Choreographer.doCallbacks(Choreographer.java:790)
at android.view.Choreographer.doFrame(Choreographer.java:721)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:967)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:101)
at android.os.Looper.loop(Looper.java:166)
at android.app.ActivityThread.main(ActivityThread.java:7529)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)
ContactsAdapter.kt
class ContactsAdapter ( private val onItemSelect: (contact: Contact) -> Unit )
: ContactsBaseAdapter<ItemContactFavListBinding>() {
var contactFavSignal = MutableLiveData<Contact>().apply { }
override fun bind(contact: Contact, holder: ContactVH<ItemContactFavListBinding>) {
val binding = holder.binding
binding.contactName.text = contact.name
binding.contactNumber.text = contact.numbers.first().phone
binding.imgContactHeart.setOnClickListener(View.OnClickListener {
val backgroundImageName = (binding.imgContactHeart.getTag()).toString()
if(backgroundImageName.equals("2")) {
binding.imgContactHeart.setImageResource(R.drawable.heart_selected_yellow)
EventBus.getDefault().post(CustomEvent(contact,true));
binding.imgContactHeart.setTag("1")
binding.imgContactHeart.setImageResource(R.drawable.heart_selected_yellow)
}else if(backgroundImageName.equals("1")) {
binding.imgContactHeart.setImageResource(R.drawable.heart_selected_yellow)
EventBus.getDefault().post(CustomEvent(contact,false));
binding.imgContactHeart.setTag("2")
binding.imgContactHeart.setImageResource(R.drawable.heart)
}
})
var num = contact.numbers.first().phone
if(num.contains(" "))
num = num.replace(" ","")
if(num.startsWith("0"))
num = num.removePrefix("0")
if(num.startsWith("+"))
num = num.removePrefix("+")
var isFav:Boolean=false
for (x in 0..FavoritesFragment.listFavNumbers.size-1)
{
var num2 = FavoritesFragment.listFavNumbers[x]
if(num2.endsWith(num))
isFav=true
}
if(isFav)
{
binding.imgContactHeart.setTag("1")
binding.imgContactHeart.setImageResource(R.drawable.heart_selected_yellow)
}
else
{
binding.imgContactHeart.setTag("2")
binding.imgContactHeart.setImageResource(R.drawable.heart)
}
showContactProfileImage(contact, binding.contactImage)
holder.binding.root.setOnClickListener {
onItemSelect.invoke(contact)
}
}
override fun provideBinding(inflater: LayoutInflater, parent: ViewGroup): ItemContactFavListBinding {
return ItemContactFavListBinding.inflate(inflater, parent, false)
}
}
ContactBaseAdater.kt
abstract class ContactsBaseAdapter<T : ViewDataBinding> :
PagedListAdapter<Contact, ContactsBaseAdapter.ContactVH<T>>(object : DiffUtil.ItemCallback<Contact>() {
override fun areItemsTheSame(oldItem: Contact, newItem: Contact): Boolean {
return oldItem.name == newItem.name || oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Contact, newItem: Contact): Boolean {
return oldItem.name == newItem.name
}
} ) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ContactVH<T> {
return ContactVH(provideBinding(LayoutInflater.from(parent.context), parent))
}
override fun onBindViewHolder(holder: ContactVH<T>, position: Int) {
val contact = getItem(position)
if (contact != null) {
bind(contact, holder)
}
}
abstract fun bind(contact: Contact, holder: ContactVH<T>)
abstract fun provideBinding(inflater: LayoutInflater, parent: ViewGroup): T
class ContactVH<T : ViewDataBinding>(val binding: T) : RecyclerView.ViewHolder(binding.root)
fun showContactProfileImage(contact: Contact, imageHolder: ImageView?) {
UiUtils.showContactProfileImage(contact, imageHolder)
}
}
item_contact_fav_list.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<RelativeLayout android:layout_width="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="#+id/contact_image"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_alignParentLeft="true"
android:contentDescription="#null"/>
<LinearLayout android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="vertical"
android:weightSum="2"
android:layout_toLeftOf="#+id/img_contact_heart"
android:layout_toRightOf="#+id/contact_image"
android:layout_marginLeft="5dp">
<TextView
android:id="#+id/contact_name"
android:textSize="16sp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="middle"
android:focusable="false"
android:textColor="#color/colorBlack"
android:layout_marginTop="3dp"
tools:text="Contact Name"/>
<TextView
android:id="#+id/contact_number"
android:textSize="15sp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_weight="1"
android:singleLine="true"
android:textColor="#android:color/darker_gray"
tools:text="Contact Name"
android:layout_marginLeft="5dp"
/>
</LinearLayout>
<ImageView
android:layout_alignParentRight="true"
android:id="#+id/img_contact_heart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/heart"
android:layout_centerVertical="true"
/>
</RelativeLayout>
</layout>
Let's take a look at the stacktrace:
Fatal Exception: java.util.NoSuchElementException: Collection is empty.
at kotlin.collections.CollectionsKt___CollectionsKt.first(_Collections.kt:184)
at com.transferhome.contacts.ContactsAdapter.bind(ContactsAdapter.kt:25)
Most probably, the line referred to is this one:
binding.contactNumber.text = contact.numbers.first().phone
the call to first() in particular. If contact.numbers is empty, first() will throw a NoSuchElementException. Your code does not handle this case.
The easiest solution would be to set the text to null if there are no numbers:
binding.contactNumber.text = contact.numbers.firstOrNull()?.phone
Why would you add a nullcheck if the exception was not a NullPointerException?