javaandroidandroid-listviewandroid-arrayadapterlistview-adapter

How to add items to listview dynamically


I am trying create an android app in Android studio that allows me to add items to my listView during runtime. I had a code used to add predefined items which worked when but when I modified it to add one item everytime I press the add button, I manage to add the first but when I try to add more after that, all the other items become the same as the first one.

Every item has a product id and a amount, in which the idText is set when my apps barcodescanner, scans a product, then I set the amountText by specifying a value in a editText widget and then create a item with these values by pressing the Add button. When I use it the first one ends up as it should like this:

778216562   12

but when I add another one, all previous items turns into the new one:

589095564   15
589095564   15

This is the code used to add items to my listView. The addItem() method is called when I press the add button on the app, also listItem is declared like this List<HashMap<String, String>> listItems = new ArrayList<>();:

 public void addItem(){
        if(amountText.getText().toString().matches("[0-9]+")) {
            productList.put(idText.getText().toString(), amountText.getText().toString());


            SimpleAdapter adapter = new SimpleAdapter(this, listItems, R.layout.list_item,
                    new String[]{"idForID", "idForAmount"},
                    new int[]{R.id.productId, R.id.amount});

            resultsMap.put("idForID", idText.getText().toString());
            resultsMap.put("idForAmount", productList.get(idText.getText().toString()));
            listItems.add(resultsMap);

            productsView.setAdapter(adapter);

        }
    }

Does anyone know how to change this code so I can keep adding items without the previous one changing and while at it I am not able to add an item with the same product id as a previous one, but with a different amount and wonder if anyone knows how to resolve that as well?


Solution

  • Your first issue is because of the way Java handles mutable data types. Since the resultsMap is a global variable, when you call put() with the same key value (i.e. "idForID" and "idForAmount") you are overriding the last input for those keys. The reference listItems has still points to the resultsMap object that now contains the overridden data, leaving you with multiple copies of the same object.

    A simple solution to this problem would be to move the declaration of the resultsMap object inside of your addItem() function (making it a local variable). Though I would also advise against this solution, considering the unnecessary added complexity of a Map nested inside of a List.

    Instead, a solution that would also solve your second issue would be to create a class to contain the data.

    final class Product(String id, String amount) {
    
        public final String id;
        public final String amount;
    
        public Product(String id, String amount) {
            this.id = id;
            this.amount = amount;
        }
    
        /**
         * Override equals() and hashCode() as well.
         * These can be generated in Android Studio by selecting 
         * Code > Generate… > equals() and hashCode().
         */
    
    }
    

    Then use this object as the type for your list and adapter, instead of Map<String, String>, and make sure you create a new object each time you add an item to the list. This will allow you to create a List containing any amount of items, even if they have the same id.


    As @Raza suggested, I would also recommend switching from a ListView to a RecyclerView. As stated in the ArrayAdapter documentation.

    Note: If you are considering using array adapter with a ListView, consider using RecyclerView instead. RecyclerView offers similar features with better performance and more flexibility than ListView provides. See the Recycler View guide.