Search code examples
androidlistkotlinadapter

kotlin.Unit cannot be cast to java.util.List. for Custom Adapter on getFilter


I am using a custom adapter to display a list of contacts on AutoTextComplete but when I try to run it I get the error "kotlin.Unit cannot be cast to java.util.List" for

mContact = filterResults.values **as List<Contact>**

Contact is a Serializable object and is how i am retrieving contact names as objects in the List - code is below... I have tried looking for a solution elsewhere, but have not been able to resolve... if you can redirect or solution or guide will be amazing thanks

private var invoice: Invoice? = null
private lateinit var contact: Contact
private var invoiceItems: List<InvoiceItems>? = null
private lateinit var contactSelect: ArrayList<Contact>
private lateinit var dueDate: Calendar
private val calendar = Calendar.getInstance()
private var total = 0
private var subTotal = 0
private var taxrate = 0
private var invoiceType: String = ""
private var invoiceUpdt: InvoiceItems? = null
private var j: String? = null
private var clientLkey: String? = ""

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_edit_invoice)

    val toolbar: Toolbar = findViewById(R.id.toolbar_editinv)
    setSupportActionBar(toolbar)
    supportActionBar?.setDisplayShowHomeEnabled(true)

    val invoiceClient = findViewById<AutoCompleteTextView>(R.id.invoiceClient)
    val invoiceDueDt = findViewById<TextView>(R.id.invoiceDueDt)
    dueDate = Calendar.getInstance()

    //getting values from intent
   invoice = intent.getSerializableExtra("invoice") as? Invoice
   invoiceItems = intent.getSerializableExtra("invoiceItem") as? List<InvoiceItems>
   invoiceUpdt = intent.getSerializableExtra("invoiceItemUpdt") as? InvoiceItems
   j = intent.getStringExtra("i")

    if (invoice == null){
        invoiceType = "new"
        supportActionBar?.title = "Add Invoice"
        addinvoiceItem()
    } else {
        editInvoice()
    }

    //Setup Due date for the invoice
    invoiceDueDt.setOnClickListener {
        showCalendar()
    }

    //Auto complete based on database for selecting the client
    val clientContact: List<Contact> = ArrayList<Contact>()
    val adapter = ClientSelectAdapter(this, R.layout.userlatomcontacts, clientContact)
    invoiceClient.setAdapter(adapter)
    invoiceClient.threshold = 2

    invoiceClient.setOnItemClickListener { parent, _, position, id ->
        val selectedClient = parent.adapter.getItem(position) as Contact?
        invoiceClient.setText(selectedClient?.name)
        clientLkey = selectedClient?.lookupKey
    }
}

inner class ClientSelectAdapter(
    context: Context,
    @LayoutRes private val layoutResource: Int,
    private var allContacts: List<Contact>
):
    ArrayAdapter<Contact>(context, layoutResource, allContacts),
    Filterable {private var mContact: List<Contact> = allContacts

    override fun getCount(): Int {
        return mContact.size
    }

    override fun getItem(p0: Int): Contact {
        return mContact[p0]

    }
    override fun getItemId(p0: Int): Long {
        // Or just return p0
        return mContact[p0].id.toLong()
    }

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {

        var view = convertView
        if (view == null) {
            view = LayoutInflater.from(parent.context)
                .inflate(layoutResource, parent, false)
        }
        val invoiceClient = view!!.findViewById<View>(R.id.invoiceClient) as TextView
        invoiceClient.text = mContact[position].name
        val clientProfile = view.findViewById<View>(R.id.profile_image) as ShapeableImageView

        Picasso.get().load(mContact[position].photoUri)
            .placeholder(R.drawable.ic_baseline_whatshot_24).fit().centerCrop()
            .into(clientProfile)

        return view
    }

    override fun getFilter(): Filter {
        return object : Filter() {
            override fun publishResults(
                charSequence: CharSequence?,
                filterResults: FilterResults
            ) {
                **mContact = filterResults.values as List<Contact>**
                notifyDataSetChanged()
            }

            override fun performFiltering(charSequence: CharSequence?): FilterResults {
                val queryString = charSequence?.toString()?.toLowerCase(Locale.ROOT)

                val results = FilterResults()
                results.values = if (queryString == null || queryString.isEmpty())
                    allContacts
                else {
                    val db = AppDatabase.getDatabase(context)
                    allContacts = db.contactsDao().getBySearch(queryString)
                }
                return results
            }


        }
    }
}

Solution

  • According to kotlin documentations Branches of if branches can be blocks. In this case, the last expression is the value of a block

    So, in your case, when code enters the else block, the last expression is assignment, and assignments return Unit in kotlin. You may check this situation with this simple example:

    var temp = 0
    var result: Int = if (temp > 0) {
        5
    } else {
        temp = 5
    }
    

    You would see the ide error at temp = 5 since it returns Unit whereas result expects Int.

    To sum up, you just need to change your else block as follows:

    else {
       val db = AppDatabase.getDatabase(context)
       allContacts = db.contactsDao().getBySearch(queryString)
       allContacts
    }