kotlinfragmentandroid-arrayadapterlifecycleautocompletetextview

AutoCompleteTextView & ArrayAdapter with back to Fragment


(sorry for my english)

I have fragment where I have an AutocompleteTextView and ArrayAdapter for it. ArrayAdapter get values from resource strings.

When fragment creating first time — everything is ok, but when I go to fragment back (with backstack or replace with saved fragment) my AutocompleteTextView show only 1 item but ArrayAdapter size is 6. I really don't know why is that...

I was thinking if I save ArrayAdapter at viewmodel it will work, but no. I want to see my items after I back to fragment

SomeFragment.kt (all names changed):

class SomeFragment : Fragment() {
    private val mSomeViewModel = SomeViewModel()

    private lateinit var mSomeAutoCompleteTextView: AutoCompleteTextView
    private lateinit var mSomeStrings: Array<String>
    private lateinit var mSomeArrayAdapter: ArrayAdapter<String>

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
    ): View? {
        mSomeStrings = resources.getStringArray(R.array.strings_array)
        mSomeArrayAdapter = ArrayAdapter(requireContext(), R.layout.dropdown_item, mSomeStrings)

        return inflater.inflate(R.layout.fragment_order_server, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        view.apply {
            mSomeAutoCompleteTextView = findViewById(R.id.someAutoCompleteTextView)
        }

        mSomeAutoCompleteTextView.apply {
            setText(mSomeStrings[mSomeViewModel.positionId])
            /* when breakpoint here and check mSomeArrayAdapter.count there are 6 items, but app show only one */
            setAdapter(mSomeArrayAdapter)
            setOnItemClickListener { _, _, position, _ ->
                mSomeViewModel.someFunction(position)
            }
        }
    }
}

SomeViewModel.kt (all names changed):

class SomeViewModel : ViewModel() {
    val positionId: Int
        get() = mPositionId

    fun someFunction(position: Int) {
        mPositionId = position

        /* some other code */
    }
}

Solution

  • Okay, I just found a solution. My mistake was that I use standard ArrayAdapter instead of my own (or it's because ArrayAdapter has something bad). I created custom BaseAdapter with Filterable and it's work.

    Code if someone needed:

    class OrderArrayAdapter<T : Any>(
        private val context: Context,
        list: Array<T>
    ) : BaseAdapter(), Filterable {
        private val mObjects = list
    
        override fun getCount(): Int {
            return mObjects.size
        }
    
        override fun getItem(position: Int): Any {
            return mObjects[position]
        }
    
        override fun getItemId(position: Int): Long {
            return position.toLong()
        }
    
        override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
            val item = getItem(position)
            val view = convertView ?: LayoutInflater.from(context)
                .inflate(R.layout.dropdown_item, parent, false)
    
            view.apply {
                findViewById<TextView>(R.id.dropdownTextView).text = item.toString()
            }
    
            return view
        }
    
        override fun getFilter(): Filter {
            return customFilter
        }
    
        private val customFilter = object : Filter() {
            override fun performFiltering(constraint: CharSequence?): FilterResults {
                val filterResults = FilterResults()
                filterResults.values = mObjects
                return filterResults
            }
    
            override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
                notifyDataSetChanged()
            }
        }
    }