ArrayList<HashMap<String,String>> Overwrite the items in list [duplicate] - android

I'm adding three different objects to an ArrayList, but the list contains three copies of the last object I added.
For example:
for (Foo f : list) {
System.out.println(f.getValue());
}
Expected:
0
1
2
Actual:
2
2
2
What mistake have I made?
Note: this is designed to be a canonical Q&A for the numerous similar issues that arise on this site.

This problem has two typical causes:
Static fields used by the objects you stored in the list
Accidentally adding the same object to the list
Static Fields
If the objects in your list store data in static fields, each object in your list will appear to be the same because they hold the same values. Consider the class below:
public class Foo {
private static int value;
// ^^^^^^------------ - Here's the problem!
public Foo(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
In that example, there is only one int value which is shared between all instances of Foo because it is declared static. (See "Understanding Class Members" tutorial.)
If you add multiple Foo objects to a list using the code below, each instance will return 3 from a call to getValue():
for (int i = 0; i < 4; i++) {
list.add(new Foo(i));
}
The solution is simple - don't use the static keywords for fields in your class unless you actually want the values shared between every instance of that class.
Adding the Same Object
If you add a temporary variable to a list, you must create a new instance of the object you are adding, each time you loop. Consider the following erroneous code snippet:
List<Foo> list = new ArrayList<Foo>();
Foo tmp = new Foo();
for (int i = 0; i < 3; i++) {
tmp.setValue(i);
list.add(tmp);
}
Here, the tmp object was constructed outside the loop. As a result, the same object instance is being added to the list three times. The instance will hold the value 2, because that was the value passed during the last call to setValue().
To fix this, just move the object construction inside the loop:
List<Foo> list = new ArrayList<Foo>();
for (int i = 0; i < 3; i++) {
Foo tmp = new Foo(); // <-- fresh instance!
tmp.setValue(i);
list.add(tmp);
}

Your problem is with the type static which requires a new initialization every time a loop is iterated. If you are in a loop it is better to keep the concrete initialization inside the loop.
List<Object> objects = new ArrayList<>();
for (int i = 0; i < length_you_want; i++) {
SomeStaticClass myStaticObject = new SomeStaticClass();
myStaticObject.tag = i;
// Do stuff with myStaticObject
objects.add(myStaticClass);
}
Instead of:
List<Object> objects = new ArrayList<>();
SomeStaticClass myStaticObject = new SomeStaticClass();
for (int i = 0; i < length; i++) {
myStaticObject.tag = i;
// Do stuff with myStaticObject
objects.add(myStaticClass);
// This will duplicate the last item "length" times
}
Here tag is a variable in SomeStaticClass to check the validity of the above snippet; you can have some other implementation based on your use case.

Had the same trouble with the calendar instance.
Wrong code:
Calendar myCalendar = Calendar.getInstance();
for (int days = 0; days < daysPerWeek; days++) {
myCalendar.add(Calendar.DAY_OF_YEAR, 1);
// In the next line lies the error
Calendar newCal = myCalendar;
calendarList.add(newCal);
}
You have to create a NEW object of the calendar, which can be done with calendar.clone();
Calendar myCalendar = Calendar.getInstance();
for (int days = 0; days < daysPerWeek; days++) {
myCalendar.add(Calendar.DAY_OF_YEAR, 1);
// RIGHT WAY
Calendar newCal = (Calendar) myCalendar.clone();
calendarList.add(newCal);
}

Every time you add an object to an ArrayList, make sure you add a new object and not already used object. What is happening is that when you add the same 1 copy of object, that same object is added to different positions in an ArrayList. And when you make change to one, because the same copy is added over and over again, all the copies get affected.
For example,
Say you have an ArrayList like this:
ArrayList<Card> list = new ArrayList<Card>();
Card c = new Card();
Now if you add this Card c to list, it will be added no problem. It will be saved at location 0. But, when you save the same Card c in the list, it will be saved at location 1. So remember that you added same 1 object to two different locations in a list. Now if you make a change that Card object c, the objects in a list at location 0 and 1 will also reflect that change, because they are the same object.
One solution would be to make a constructor in Card class, that accepts another Card object. Then in that constructor, you can set the properties like this:
public Card(Card c){
this.property1 = c.getProperty1();
this.property2 = c.getProperty2();
... //add all the properties that you have in this class Card this way
}
And lets say you have the same 1 copy of Card, so at the time of adding a new object, you can do this:
list.add(new Card(nameOfTheCardObjectThatYouWantADifferentCopyOf));

It can also consequence of using the same reference instead of using a new one.
List<Foo> list = new ArrayList<Foo>();
setdata();
......
public void setdata(int i) {
Foo temp = new Foo();
tmp.setValue(i);
list.add(tmp);
}
Instead of:
List<Foo> list = new ArrayList<Foo>();
Foo temp = new Foo();
setdata();
......
public void setdata(int i) {
tmp.setValue(i);
list.add(tmp);
}

Related

Add variable number of sources to MediatorLiveData

I have to return a list of lists with LiveData.
The background is, that I load some data out of my Room database.
The database call depends on a counter. So I tried the following approach:
MediatorLiveData<List<List<Foo>> forView = new MediatorLiveData<>();
forView.addSource(counter, (trigger) -> {
List<List<Foo>> output = new LinkedList<>();
for(int i = 0; i < counter; i++) {
output.add(new ArrayList<>());
forView.addSource(repository.getDataForCounter(i), (data) -> {
//With some workaround I thought I've access to the position
output.remove("i");
output.add("i", data);
});
}
return output;
});
I think the workaround for the index didn't work, because the variables in lambdas have to be implicit final.
Is there any other approach to "merge" a variable number of lists got out of a database in one list of such lists?

Array, with if statement

So i am busy with a program where i have this array called names and in the array i have the following data:
public static String [] name = {"Products", "Customers","Calculators","Logout"};
public static String [] subName = {"140 wide Plain", "140 wide Pattern", "280 wide Running width", "280 wide plain drops","280 wide pattern drops"};
now the following code i am trying to implement an if statement:
private List<TitleMenu> getList() {
List<TitleMenu> list = new ArrayList<>();
for (int i = 0; i < names.length; i++) {
List<SubTitle> subTitles = new ArrayList<>();
if (names.equals("Calculators")){
for (int j = 0; j < subNames.length; j++) {
SubTitle subTitle = new SubTitle(subNames[j]);
subTitles.add(subTitle);
}}
TitleMenu model = new TitleMenu(names[i], subTitles, null);
list.add(model);
}
return list;
}
so i only want the second portion of my code to implement if the if statement is correct but i cant seem to get the if statement correct. I am coding in android studio so i dont know how my if statement needs to be
You need to reference the indices of the array. Each index in an array is represented by a number that starts at base zero. This is an important and fundamental concept across many programming languages.
It also looks like your array's name is not names and is name.
So you could check to see if the name is "Calculators" by doing something like this:
if (name[i].equals("Calculators")) { ... }

Why does my SparseArray return an ArrayList with zero elements?

I'm iterating through a cursor and populating a SparseArray with ArrayList's containing bundles of information from the cursor:
// An ArrayList to hold all of our components per section
ArrayList<ObjectKanjiLookupChar> al = new ArrayList<ObjectKanjiLookupChar>();
// We'll hold on to all of the above ArrayLists and process them at once
SparseArray<ArrayList<ObjectKanjiLookupChar>> compArray = new SparseArray<ArrayList<ObjectKanjiLookupChar>>();
do
{
// Read values from the cursor
int id = cursor.getInt(cursor.getColumnIndex("_id"));
String component = cursor.getString(cursor.getColumnIndex("component"));
int compStrokes = cursor.getInt(cursor.getColumnIndex("strokes"));
// Create a new object for this component so we can display it in the GridView via an adapter
ObjectKanjiLookupChar oklc = new ObjectKanjiLookupChar();
oklc.setCharacterID(id);
oklc.setCharacter(component);
oklc.setStrokeCount(compStrokes);
al.add(oklc);
// Add headers whenever we change stroke groups
if(compStrokes != strokesSection)
{
compArray.put(strokesSection, al);
al.clear();
strokesSection = compStrokes;
}
}
while(cursor.moveToNext());
// Add the final group of components to the array
compArray.put(strokesSection, al);
Immediately afterwards, I iterate through the SparseArray:
for(int i = 0; i < compArray.size(); i++)
{
Integer strokes = compArray.keyAt(i);
ArrayList<ObjectKanjiLookupChar> alComp = compArray.get(strokes);
// DEBUG
Log.i("DialogKanjiLookup", "Components in Section " + strokes + ": " + alComp.size());
ll.addView(createNewSection(String.valueOf(strokes), alComp));
}
For some unknown reason, the Log() call above reports that alComp has zero entries. I verified that ArrayList.size() was returning numbers greater than 0 when I put() them into the SparseArray, so I must be doing something incorrect when iterating through the SparseArray. What is going on?
I suspect that the problem comes from this piece of code:
if(compStrokes != strokesSection)
{
compArray.put(strokesSection, al);
al.clear(); // Here
strokesSection = compStrokes;
}
You cleared the array list after you added to the SparseArray. You might think that after you have added the list to the SparseArray, SparseArray would keep a copy of the ArrayList. However, they actually share the same reference. Since you cleared the ArrayList, you cleared out the one inside SparseArray too.
The following code should fix the problem.
// We'll hold on to all of the above ArrayLists and process them at once
SparseArray<ArrayList<ObjectKanjiLookupChar>> compArray = new SparseArray<ArrayList<ObjectKanjiLookupChar>>();
do
{
// Read values from the cursor
int id = cursor.getInt(cursor.getColumnIndex("_id"));
String component = cursor.getString(cursor.getColumnIndex("component"));
int compStrokes = cursor.getInt(cursor.getColumnIndex("strokes"));
// Create a new object for this component so we can display it in the GridView via an adapter
ObjectKanjiLookupChar oklc = new ObjectKanjiLookupChar();
oklc.setCharacterID(id);
oklc.setCharacter(component);
oklc.setStrokeCount(compStrokes);
ArrayList<ObjectKanjiLookupChar> al = compArray.get(comStrokes);
if(al == null) {
al = new ArrayList<ObjectKanjiLookupChar>();
compArray.put(comStrokes, al);
}
al.add(oklc);
}
while(cursor.moveToNext());

AndEngine - can't iterate through array items inside handler calls

I am having a problem working inside a handler call. The problem is something as follows:
Sprite sprite = new Sprite[spriteArrayLength];
IUpdateHandler mm[i] = new ........// you know what
for(int i = 0; i < spriteArrayLength; i++){
//many other actions
mm[i] = new IUpdateHandler() {
//do somthing with sprite array items
float anyVar = sprite[i].getX();//problem rises here
};
sprite[i].registerUpdateHandler(mm[i]);
}
Every time it shows an error saying i reaches out of array bound. That means the handler call executes after for loop ends and so i already crosses its limit. How can I do something like above in a proper way?
Edit:
Sorry for my previous mistake. The First line of the code will be:
Sprite sprite[] = new Sprite[spriteArrayLength];
IUpdateHandler mm[] = new ........// you know what
not this:
Sprite sprite = new Sprite[spriteArrayLength];
IUpdateHandler mm[i] = new ........// you know what
I just thought these line are not very important to mention that's why made the mistake. But still the problem remains same.
Edit-2:
I get "array out of bound" type run time error. Let's say, array size is 6. So, last element is 5. But inside UpdateHandler "i" begins with 6 and throws an error. And I tried making "i" final, even made it global by declaring as a class field. I am trying to write short code examples here because it contains many codes. Better version is as follows:
public int i;//global declaration
//inside some method:
Sprite sprite[] = new Sprite[spriteArrayLength];
IUpdateHandler mm[] = new IUpdateHandler[spriteArrayLength];
for(i = 0; i < spriteArrayLength; i++){
//many other actions
mm[i] = new IUpdateHandler() {
//do somthing with sprite array items
float anyVar = sprite[i].getX();//problem rises here
};
sprite[i].registerUpdateHandler(mm[i]);
}
Based on the code in your Edit-2, my suggestion is:
Sprite sprite[] = new Sprite[spriteArrayLength];
IUpdateHandler mm[] = new IUpdateHandler[spriteArrayLength];
for(i = 0; i < spriteArrayLength; i++){
//many other actions
mm[i] = new IUpdateHandler() {
private final int id = i; /* add this line */
// call Log.i() here is compiling error
#Override
public void onUpdate(float pSecondElapsed) {
//do somthing with sprite array items
/* And access id, instead of i in below code.
Here, I assume this statement is located
within onUpdate() or reset().
*/
float anyVar = sprite[id].getX();
}
#Override
public void reset() {
}
};
sprite[i].registerUpdateHandler(mm[i]);
}
You are using the index variable i in 2 different contexts.
In your code you do this before the loop using i as an array index:
IUpdateHandler mm[i] = new ........// you know what
then inside the loop, you are changing the value of i and referencing mm[i] and sprite[i].
I assume that you haven't correctly initialized the mm array to the correct size (spriteArrayLength)
The problem is that your update handler holds a reference to variable i but isn't evaluated until after the loop finishes. Instead of holding a reference to i, give it a reference to the specific sprite, and for readability make it final to avoid any doubt that it could change:
for(i = 0; i < spriteArrayLength; i++){
final Sprite currentSprite = sprite[i];
//many other actions
mm[i] = new IUpdateHandler() {
//do somthing with sprite array items
float anyVar = currentSprite.getX();
};
currentSprite.registerUpdateHandler(mm[i]);
}

How to add elements to multidimensional arrayList

If I create a class such as
public class record{
int index;
String name;
}
and then an ArrayList
ArrayList<.record> members = new ArrayList<.record>();
How do I add individual elements?
I thought there would be something like
members[x].index.add(someintegervalue);
members[x].name.add(somestringvalue);
and then a similar command to set new values if I wanted to change existing values.
Is there a simple way to do this?
Edit: This question has been answered, however it led to another problem. How to pass an ArrayList pointer to a function().
ArrayList<record> members = new ArrayList<record>();
//to add a member
member obMember = new member();
obMember.index = 0;
obMember.name="name";
members.add(obMember);
//to update get child of position cast it and update
member newMember = (menber)members.get(position);
newMember.name="newName";
member.set(location, newMember);
try like this
public class Record{
public int index;
public String name;
}
Record myRecord = new Record();
myRecord.index = someintegervalue;
myRecord.name = somestringvalue;
then add it to arraylist by
members.add(myRecord); or members.add(x , myRecord );
add adding it to x potion the you can get
Record record = members.get(x);

Categories

Resources