I want to make dynamic recyclerview, so when i click button "add", data will be increase one data. But when i click at the second time, the preview data will show again and after data will be show twice. Like thiserror data
but when i minimize or back, and then look again, the list data show normally
for the nomor log, i'm using generate number with some cetegory and MVVM pattern
This is my code
---Activity---
class ProductListActivity : AppCompatActivity(), CoroutineScope {
companion object {
const val paramTreeId = "param_tree_id"
const val paramTreeNumber = "param_tree_number"
const val paramOrderId = "param_order_id"
const val paramOrderNum = "param_order_num"
const val paramSpeciesId = "param_species_id"
}
private lateinit var addNewLog: ImageView
private lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
private val vm: ProductListViewModel by lazy {
ViewModelProviders.of(this, viewModelFactory).get(ProductListViewModel::class.java)
}
private var treeId = -1
private var treeNumber = ""
private var orderId = -1
private var orderNum = ""
private var speciesId = 1
private var logNumber: String? = null
private val products = mutableListOf<WoodProduct>()
private val productAdapter = object : RecyclerView.Adapter<ProductItemViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, itemType: Int): ProductItemViewHolder {
val ui = EditViewProductUi()
val itemView = ui.createView(AnkoContext.create(parent.context, parent))
return ProductItemViewHolder(ui, itemView)
}
override fun getItemCount(): Int = products.size
override fun onBindViewHolder(holder: ProductItemViewHolder, position: Int) {
val product = products[position]
return holder.bind(product) { product ->
alert {
title = "Hapus Data Kayu"
message = "Hapus data kayu dari daftar?"
okButton {
launch {
it.dismiss()
products.removeAt(position)
vm.deleteProduct(product.copy(deleted = 1))
Log.d("data", "delete= $product")
}
}
cancelButton {
it.dismiss()
}
}.show()
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
job = Job()
AndroidInjection.inject(this)
treeId = intent.getIntExtra(paramTreeId, -1)
orderId = intent.getIntExtra(paramOrderId, -1)
treeNumber = intent.getStringExtra(paramTreeNumber)
orderNum = intent.getStringExtra(paramOrderNum)
speciesId = intent.getIntExtra(paramSpeciesId, 1)
coordinatorLayout {
relativeLayout {
verticalLayout {
relativeLayout {
backgroundColor = Color.WHITE
toolbar {
id = R.id.toolbar
backgroundColor =
ContextCompat.getColor(context, R.color.colorPrimaryDark)
setTitleTextColor(Color.WHITE)
menu.apply {
add("0").setActionView(linearLayout {
addNewLog = imageView(R.drawable.ic_plus) {
scaleType = ImageView.ScaleType.FIT_XY
}.lparams(dip(38), dip(38)) {
rightMargin = dip(10)
}
addNewLog.setOnClickListener {
vm.productData.observe(
this@ProductListActivity,
Observer(::onProductUpdate)
)
launch {
vm.loadProduct(orderId, orderNum, treeId, logNumber)
}
}
}).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
}
}.lparams {
alignParentTop()
width = matchParent
height = wrapContent
}
linearLayout {
id = R.id.header_log
textView("") {
typeface = regularFace
textSize = regularText
textColor = Color.BLACK
}.lparams(dip(15), dip(40)) {
verticalGravity = Gravity.CENTER
horizontalGravity = Gravity.CENTER
}
textView("") {
}.lparams(dip(30), dip(20)) {
verticalGravity = Gravity.CENTER
}
textView("Nomor Log") {
isEnabled = false
padding = dip(4)
typeface = regularFace
textSize = regularText
textColor = Color.BLACK
gravity = Gravity.CENTER
textAlignment = View.TEXT_ALIGNMENT_CENTER
}.lparams(matchParent, dip(50)) {
weight = 2f
}
textView("Diameter
(cm)") {
padding = dip(4)
textSize = regularText
typeface = regularFace
textColor = Color.BLACK
textAlignment = View.TEXT_ALIGNMENT_CENTER
}.lparams(matchParent, dip(50)) {
weight = 3f
}
textView("Panjang
(cm)") {
padding = dip(4)
textSize = regularText
typeface = regularFace
textColor = Color.BLACK
textAlignment = View.TEXT_ALIGNMENT_CENTER
}.lparams(matchParent, dip(50)) {
weight = 3f
}
}.lparams(matchParent, wrapContent) {
below(R.id.toolbar)
rightMargin = dip(5)
leftMargin = dip(5)
}
linearLayout {
id = R.id.line_log
backgroundColor = Color.BLACK
}.lparams(matchParent, dip(1)) {
topMargin = dip(5)
bottomMargin = dip(5)
below(R.id.header_log)
}
verticalLayout {
recyclerView {
adapter = productAdapter
layoutManager = LinearLayoutManager(context)
}.lparams(matchParent, matchParent)
}.lparams(matchParent, matchParent) {
below(R.id.line_log)
}
}.lparams(matchParent, dip(0)) {
weight = 1f
}
linearLayout {
backgroundColor = Color.WHITE
val saveButton = button {
text = "Ok"
textColor = Color.WHITE
allCaps = false
background =
ResourcesCompat.getDrawable(resources, R.drawable.save_button, null)
}.lparams(wrapContent, wrapContent) {
padding = dip(10)
}
val cancelButton = button {
text = "Batal"
allCaps = false
textColor = BUTTON_YELLOW
background = ResourcesCompat.getDrawable(
resources,
R.drawable.cancel_button,
null
)
}.lparams(wrapContent, wrapContent) {
padding = dip(10)
leftMargin = dip(10)
}
}.lparams(matchParent, dip(80)) {
gravity = Gravity.RIGHT
rightMargin = dip(10)
}
}.lparams(matchParent, matchParent)
}.lparams(matchParent, matchParent)
}
val toolbar = findViewById<Toolbar>(R.id.toolbar)
toolbar.title = "No. Pohon: $treeNumber"
toolbar.setNavigationIcon(R.drawable.ic_arrow_back_black_24dp)
toolbar.setNavigationOnClickListener {
onBackPressed()
}
vm.productsData.observe(this, Observer(::updateProducts))
}
private fun onProductUpdate(product: WoodProduct?) {
product ?: return
products.add(product)
launch {
vm.saveProduct(
logNumber == null,
product.diameter,
product.length,
product.rejectStatusPetani,
product.isTaken
)
}
Log.d("size", "product = ${products.size - 1}")
productAdapter.notifyItemInserted(products.size - 1)
productAdapter.notifyDataSetChanged()
}
private fun updateProducts(newProducts: List<WoodProduct>?) {
newProducts ?: return
products.clear()
products.addAll(newProducts)
productAdapter.notifyDataSetChanged()
}
override fun onResume() {
super.onResume()
launch {
vm.loadProducts(treeId)
}
}}
class ProductItemViewHolder(private val ui: EditViewProductUi, itemView: View) :
RecyclerView.ViewHolder(itemView) {
@SuppressLint("SetTextI18n")
fun bind(product: WoodProduct, onDelete: (WoodProduct) -> Unit) {
ui.numberPosition.text =
String.format(itemView.context.getString(R.string.no), adapterPosition + 1)
ui.logNumberView.setText(product.logNumber)
ui.diameterView.setText(product.diameter)
ui.longView.setText(product.length)
ui.rejectStatusView.setSelection(product.rejectStatusPetani)
ui.isTakenView.setSelection(product.isTaken)
ui.deleteButton.setOnClickListener {
onDelete(product)
}
}}
----ViewModel----
class ProductListViewModel @Inject constructor(val productInteractor: WoodProductInteractor) : ViewModel() {
val productsData = MutableLiveData<List<WoodProduct>>()
val productData = MutableLiveData<WoodProduct>()
private val numberFormat = DecimalFormat("###.##")
suspend fun loadProducts(treeId: Int) {
val products = GlobalScope.async(Dispatchers.IO) { productInteractor.getWoodProducts(treeId) }.await()
GlobalScope.launch(Dispatchers.Main) { productsData.value = products }
Log.d("Data","Log Product = $productsData")
}