问题
Here is the scenario of what I am trying to do: I am creating a RecyclerView that can add or remove one or more child item/fragment/view that has EditText(s) but....
Here is my problem: Whenever I scroll down in my RecyclerView, its items' value resets. I think the problem here is that the RecyclerView Adapter cannot bind or hold the values but I don't know where exactly is the problem in my code.
class StocksAdapter() : RecyclerView.Adapter<ViewHolder>() {
class StockFragmentHolder : ViewHolder {
fun Double.format(digits: Int) = java.lang.String.format("%,.${digits}f", this)
lateinit var numberOfShares: EditText;
lateinit var buyPrice: EditText;
lateinit var btnCompute: Button
lateinit var btnRemove: Button
lateinit var stockAveragePrice: TextView
lateinit var stockTotalAmount: TextView
private var savedStock : Stock? = null
constructor(view: View) : super(view) {
numberOfShares = view.findViewById(R.id.stockNumberOfShares)
buyPrice = view.findViewById(R.id.stockBuyPrice)
btnCompute = view.findViewById(R.id.btnCompute)
btnRemove = view.findViewById(R.id.btnRemove)
stockAveragePrice = view.findViewById(R.id.stockAveragePrice)
stockTotalAmount = view.findViewById(R.id.stockTotalAmount)
}
fun populateView(stock: Stock, onStocksAdapterListener: OnStocksAdapterListener, position: Int) {
if(savedStock == null || stock.buyPrice > 0 || stock.numberOfShares > 0) {
savedStock = stock
}
this.buyPrice.setText(if (savedStock!!.buyPrice <= 0.0) "" else savedStock!!.buyPrice.toString())
this.numberOfShares.setText(if (savedStock!!.numberOfShares <= 0.0) "" else savedStock!!.numberOfShares.toString())
this.stockAveragePrice.text = "0"
this.stockTotalAmount.text = "0"
this.btnCompute.setOnClickListener(View.OnClickListener {
var stock = Stock();
stock.numberOfShares = this.numberOfShares.text.toString().toLongOrNull()
stock.buyPrice = this.buyPrice?.text.toString().toDoubleOrNull()
stock.sellPrice = 0.0
if (stock.numberOfShares != null || stock.numberOfShares != 0L) {
var buyTotalAmount: Double = 0.0;
buyTotalAmount = StocksCalculator.calculateTotalSharesPrice(stock, StocksCalculator.TRANSACTION_FEE_BASE_VALUES, Constants.TRANSACTION_TYPE.TRANSACTION_TYPE_BUY)
var averagePricePerShare = (buyTotalAmount / stock.numberOfShares)
this.stockAveragePrice.text = averagePricePerShare.format(2);
this.stockTotalAmount.text = "" + buyTotalAmount.format(2)
onStocksAdapterListener.onStocksComputeButtonClicked(stock.numberOfShares, averagePricePerShare, buyTotalAmount, position)
}
})
this.btnRemove.setOnClickListener(View.OnClickListener {
onStocksAdapterListener.onStocksRemoveButtonClicked(position)
})
}
}
lateinit var onStocksAdapterListener: OnStocksAdapterListener;
lateinit var listStocks: ArrayList<Stock>
public constructor(listStocks: ArrayList<Stock>, onStocksAdapterListener: OnStocksAdapterListener) : this() {
this.listStocks = listStocks
this.onStocksAdapterListener = onStocksAdapterListener
setHasStableIds(true)
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder {
var itemView = LayoutInflater.from(parent?.getContext())
.inflate(R.layout.fragment_stock, parent, false)
}
override fun getItemViewType(position: Int): Int {
return position
}
override fun getItemCount(): Int {
return listStocks.size
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) {
var stock: Stock = listStocks.get(position)
holder.populateView(stock, this.onStocksAdapterListener, position)
}
public interface OnStocksAdapterListener {
public fun onStocksAddButtonClicked()
public fun onStocksComputeButtonClicked(numberOfShares: Long?, averagePricePerShare: Double?, averageTotalAmount: Double?, position: Int)
public fun onStocksRemoveButtonClicked(position: Int)
}
Here is how I create my recyclerView in my Fragment:
val mLayoutManager = LinearLayoutManager(this.context)
var recyclerView: RecyclerView = view.findViewById(R.id.recyclerView)
val itemDecorator = DividerItemDecoration(context, DividerItemDecoration.VERTICAL)
itemDecorator.setDrawable(ContextCompat.getDrawable(context, R.drawable.divider))
recyclerView.addItemDecoration(itemDecorator)
recyclerView.setLayoutManager(mLayoutManager)
recyclerView.setItemAnimator(DefaultItemAnimator())
recyclerView.adapter = stocksAdapter
I have tried disabling the setIsRecyclable of the ViewHolder but the problem still persists.
What is the best approach to prevent the RecyclerView to stop resetting the values? Or should I replace the RecyclerView with ListView?
回答1:
I found a workaround by increasing the cache size of the recyclerview. Just ensure that the cache size is good enough for your application.
code:
recyclerView.setItemViewCacheSize(int);
回答2:
As I have seen in your code you are trying to add an item just after the activity load. So when you scroll your activity then again it calls the onCreate activity and data is again load from the storage or network so load data in specific method or in OnActiviyt Result method.
回答3:
I don't know in your code what is savedStock
or what do you use it for. But your populateView
method doesn't work as intended.
If you only use this savedStock
for rendering, remove it completely, otherwise, don't use it in the populateView
.
In populateView
depend on the stock
passed according to the position you get to draw the values.
Your code should be something like
this.buyPrice.setText(if (stock!!.buyPrice <= 0.0) "" else stock!!.buyPrice.toString())
this.numberOfShares.setText(if (stock!!.numberOfShares <= 0.0) "" else stock!!.numberOfShares.toString())
来源:https://stackoverflow.com/questions/50328655/recyclerview-items-values-reset-when-scrolling-down