I have a view that I'm creating multiple child views to create a dynamic form. Some will act like a dropdown and some are EditText controls for data entry. However, when the user enters some data, then goes to the next fragment and hits the back button...all of the EditText controls get the same values. It's whatever was entered on the last one.
I've been racking my brain for over an hour trying to figure out where my bug is. Is it because all of the programmatically created textboxes have the same id?
Here's my onCreateView:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentNewReceiptInboundCustomAttributesBinding.inflate(layoutInflater)
val layoutManager: LinearLayout = LinearLayout(context)
for (i in receipt.InboundCustomAttributes) {
// val x = newbinding.root
if (i.CustomControlType in 1..3) {
val newbindingTB = CustomControlTextboxBinding.inflate(inflater)
newbindingTB.textView.text = i.LabelCaption
newbindingTB.textboxvalue.setText(i.DefaultValue)
binding.layoutItems.addView(newbindingTB.root)
} else if (i.CustomControlType==4) {
val newbindingDD = CustomControlDropdownBinding.inflate(inflater)
newbindingDD.label.text = i.LabelCaption
newbindingDD.value2.text = i.Value
newbindingDD.rlCustom.setOnClickListener {
val fragment = NewReceiptSelectOptions()
val args = Bundle()
val receiptblank = Receipt()
args.putSerializable("receipt", receiptblank)
args.putString("entity", "customattr")
args.putSerializable("customattribute", i)
fragment.arguments = args
activity?.getSupportFragmentManager()?.beginTransaction()
?.replace(R.id.nav_newreceipt_fragment, fragment)
?.addToBackStack("receiptOptions")
?.commit();
}
binding.layoutItems.addView(newbindingDD.root)
}
}
binding.nextButton.setOnClickListener {
var errorcnt: Int =0
for (i in receipt.InboundCustomAttributes) {
if (i.Required && i.Value.length==0) {
Toast.makeText(
this@NewReceiptInboundCustomAttributes.context,
i.ErrorMessage,
Toast.LENGTH_SHORT
).show()
errorcnt=1
}
}
if (errorcnt==0) {
// addReceiptHeader()
}
}
val view = binding.root
return view
}
Here's a screenshot after hitting the back button.
UPDATE:
Now I have converted to use RecyclerView, but the same thing is happening. Here's my adapter...I'm binding to a specific class depending on ViewType and it works well. However, all of my EditText controls still have the same id, so when the user goes to the next fragment and hits the back button, Android is attempting to remember the inputted values. How can i prevent this?
class NewReceiptInboundCustomAttributesAdapter (
var optionList: MutableList<InboundCustomAttribute>,
private val listener: NewReceiptInboundCustomAttributes
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
// inner class ViewHolder(val binding: QuestionItemBinding) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
when (viewType) {
1 -> {
bindingTB = CustomControlTextboxBinding.inflate(LayoutInflater.from(parent.context), parent, false)
CustomControlTB(bindingTB)
}
4 -> {
bindingDD = CustomControlDropdownBinding.inflate(LayoutInflater.from(parent.context), parent, false)
CustomControlDD(bindingDD)
}
6 -> {
bindingCB = CustomControlCheckboxBinding.inflate(LayoutInflater.from(parent.context), parent, false)
CustomControlCB(bindingCB)
}
else -> {
bindingTB = CustomControlTextboxBinding.inflate(LayoutInflater.from(parent.context), parent, false)
CustomControlTB(bindingTB)
}
}
override fun getItemViewType(position: Int) = optionList[position].CustomControlType
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder.getItemViewType()) {
1 -> {
(holder as CustomControlTB).bind(optionList[position])
bindingTB.textboxvalue.addTextChangedListener (object : TextWatcher {
override fun afterTextChanged(s: Editable) {}
override fun beforeTextChanged(s: CharSequence, start: Int,
count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence, start: Int,
before: Int, count: Int) {
listener.textboxChanged(position, bindingTB.textboxvalue.text.toString())
}
})
}
4 -> {
(holder as CustomControlDD).bind(optionList[position])
}
6 -> {
(holder as CustomControlCB).bind(optionList[position])
}
}
holder.itemView.setOnClickListener { v ->
if (position != RecyclerView.NO_POSITION) {
listener.optionSelected(position)
}
}
}
// return the size of languageList
override fun getItemCount(): Int {
return optionList.size
}
}