I have a ListView that has an adapter for each cell. This adapter extends ArrayAdapter (my object class).
The app also has 2 tabs so far. Tab 1 has the list, Tab 2 has a map.
Each cell in the adapter has a check box, which by default is unchecked.
The issue I have is that when I switch tabs the checked boxes return to be unchecked, and if I iterate an array of checked boxes, I get a ConcurrentModificationException when I try to mark a box as checked.
Here's my code of what I'm doing:
value_checkBox.setTag(route.getRouteShortName());
value_checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
{
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
if (isChecked == true)
{
RouteListLV.arrayOfRoutesEnabled.add(route);
}
else
{
RouteListLV.arrayOfRoutesEnabled.remove(route);
}
}
});
This part (the sample code above) works, and here's where I am adding the checked routes into a static array that can be used by multiple views.
for (Route routeFromArray : RouteListLV.arrayOfRoutesEnabled)
{
if (routeFromArray.getRouteShortName().equals(route.getRouteShortName() ) )
{
System.out.println("Match!");
value_checkBox.setChecked(true); <--- causes the ConcurrentModificationException
}
}
This loop (the for loop above) doesn't work and the exception happens when I set the checkBox to be checked.
I have tried an iterator as well, but I get the same result:
Iterator<Route> iterator = RouteListLV.arrayOfRoutesEnabled.iterator();
while (iterator.hasNext())
{
Route routeFromArray = iterator.next();
if (routeFromArray.getRouteShortName().equals(route.getRouteShortName() ) )
{
System.out.println("Match!");
value_checkBox.setChecked(true); <--- causes the ConcurrentModificationException
}
}
Any suggestions on this issue?
Just to be clear, I have 2 arrayLists. One is the one with the entire list of "routes" which is being passed to the ArrayAdapter to form the list, and I have a second arrayList for just the selected routes.
You're iterating through an ArrayList (RouteListLV.arrayOfRoutesEnabled) and modifying it as you go along. That causes a ConcurrentModificationException, so don't do it. Find a way to first find the element or elements you're going to modify and then modify the list (and never use the iterator after that). Or build a "shadow" copy of the list that has everything you want it to have at the end, then call removeAll() and then addAll(newList) on the original list, which is just that same idea in a slightly different form.
Related
I am working on a game project. So far so good, but i just stuck on ome basic thing and i cant find a solution and make it work properly. I decided to come here and ask you ppl of suggestions.
PROBLEM:
When the player comes to contact with a diamond, i suppose to remove the diamond from the level and from the arraylist containing all the objects in the world. What always happens i get an exception error message after remove() method called.
CODES:
1.Class with the list: EDIT_1
private ArrayList<AbstractObject> objects = new ArrayList<AbstractObject>();
public void removeObject(String name){
ArrayList<AbstractObject> newest = new ArrayList<AbstractObject>();
ListIterator<AbstractObject> delete=objects.listIterator();
while(delete.hasNext()){
if(name.equals(delete.next().getName())){
delete.remove();
}
else{
delete.previous();
newest.add(delete.next());
}
}
objects=newest;
}
2.Player class calling the removeObject method: EDIT_1
public void playerLogic(){
fallingDown();
for(AbstractObject object : this.getWorld().getListOfObjects()){ <--------ERROR HERE
if(this.intersects(object)){
if(object instanceof FinishZone && points>=getWorld().getDiamondCount()){
if(!(getWorld().getManager().isMoreLevels())){
getWorld().getMenu().openMenu(true);
}
else{
this.getWorld().getManager().nextLevel();
}
}
if(object instanceof Diamond){
points++;
this.getWorld().removeObject(object.getName());
}
}
}
}
ERROR:
Exception in thread "Thread-2" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at project.objects.characters.Player.playerLogic(Player.java:77)
at project.objects.characters.Player.update(Player.java:70)
at project.world.World.update(World.java:110)
at project.Main.update(Main.java:122)
at project.Main.run(Main.java:65)
at java.lang.Thread.run(Thread.java:745)
I checked up some examples of removing items from arraylist but i havent find the difference.
EDIT_1:
So i figured out how to do it but i always get the error. I edited the removeobject code block. This worked good with a neutral list that i created for testing. I put all the items which i dont want to delete into a new list than ovewritten the old arraylist with the newest one. It worked with no exception error. When i made the same with the game list i want to edit it thrown the same error.
Ill put there the render code too if maybe there is the problem...
public void render(Graphics g) {
if(menu.getChoice()==-1){
menu.render(g);
}
else if(menu.getChoice()==0){
g.setColor(Color.white);
for(AbstractObject tempObj : objects){
tempObj.render(g);
}
}
}
FIXED:
Ill changed the starting list is ListIterator instead of putting items in arrayList before adding it to ListIterator. All methods changed to iterate. Working fine :)
You can't remove object while iterating over a list.
One option - use iterator.remove() - if you iterate with iterator, not the "enhanced for loop". You'll need to slightly modify your loop code, but the functionality will be the same.
Another: Store all objects to remove in an auxiliary list, and remove them all at the end of the loop.
I have a comboBox cb and an ObservableList<StringProperty> data
I have bound the cb's Items to data as follows:
Bindings.bindContent(cb.getItems(), data);
Suppose data has the following items: str1, str2, str3, str4
When I change data, the combobox gets the new list without any problem.
But if str3 is selected in cb and I change the value of str3 to NewStr3 in data, that change is not getting displayed in cb. And sometimes the list displayed is also wrong (it shows str3 instead of NewStr3) eventhough underlying data it refers is correct.
How can I force combobox to display new values when the underlying model is changed?
The selected item in a combo box is not required to be an element of the combo box's items list. (For example, in an editable combo box, you can type in an item which is not in the list.) If you think about your example from this perspective, it's no surprise that it behaves as you describe.
If you want to force the selected value to be an element of the underlying list when that list may change, you need to define how the selected item should change if the list changes in a way in which it no longer contains the selected item (it is not obvious how you will do this, and probably depends on your application logic). Once you know what you want to do, you can implement it with a ListChangeListener:
cb.getItems().addListener((ListChangeListener.Change change) -> {
String newSelectedItem = ... ; // figure item that should be selected instead
cb.setValue(newSelectedItem);
});
The simplest implementation would be just cb.setValue(null);, which would mean no item was selected if the list changed so that it no longer contained the currently selected item.
Oops ... mis-read the comboBox for a choiceBox - while the basics of this answer apply to both combo- and choiceBox, I don't have a custom ComboBoxX - yet :-)
Basically, it's the responsibility of the SelectionModel to update itself on changes to the items. The intended behaviour implemented in core is to completely clear the selection - that is, null the selectedItem and set selectedIndex to -1 - if the old item was the selectedItem and is replaced or removed. The typical solution for custom behaviour is to implement a custom selection model and set it:
/**
* A SelectionModel that updates the selectedItem if it is contained in
* the data list and was replaced/updated.
*
* #author Jeanette Winzenburg, Berlin
*/
public static class MySelectionModel<T> extends ChoiceBoxSelectionModel<T> {
public MySelectionModel(ChoiceBoxX<T> cb) {
super(cb);
}
#Override
protected void itemsChanged(Change<? extends T> c) {
// selection is in list
if (getSelectedIndex() != -1) {
while (c.next()) {
if (c.wasReplaced() || c.wasUpdated()) {
if (getSelectedIndex() >= c.getFrom()
&& getSelectedIndex() < c.getTo()) {
setSelectedItem(getModelItem(getSelectedIndex()));
return;
}
}
}
}
// super expects a clean change
c.reset();
super.itemsChanged(c);
}
}
// usage
myChoiceBox.setSelectionModel(new MySelectionModel(myChoiceBox));
Unfortunately, core choiceBox doesn't play by the rule - it severely interferes with model's responsibilities (probably because the model implementation doesn't stand up to its duties) which requires a complete re-write of the whole collaborator-stack (choiceBox, -skin, copied -behaviour) such as ChoiceBoxX - which I did just to learn a bit, try remove some of its smells and fix some bugs.
Hi I have a listview showing an arraylist, when an item is clicked it is added to another arraylist and displayed in another activity. What is my problem? I want that if an item (eg a dog) I touch once, is added to the second activity, and it shows. But if I were to touch the item (dog) is not added again.
We would say that I want to check if it exists, not add.
I've tried so, but without success.
if (page2 == null)
{
page2 = (ListView) LayoutInflater.from(Local_mostrar_bebidaActivity.this).inflate(R.layout.page_two_viewpager_listview, null);
page2.setAdapter(adapterlistvMenuVINOSespumosos);
page2.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
if (MiPedidoActivity.itemsListVMiPedido.contains( position)){}
else
MiPedidoActivity.itemsListVMiPedido.add(itemsListVMenuVINOSespumosos.get(position));
}});
}
page = page2;
break;
Any ideas?
You have:
if (MiPedidoActivity.itemsListVMiPedido.contains( position)){}
else
MiPedidoActivity.itemsListVMiPedido.add(itemsListVMenuVINOSespumosos.get(position));
You are checking if itemsListVMiPedido contains the integer, position, but you are adding itemsListVMenuVINOSespumosos.get(position) to the list. You need to check if the list contains them item, not the index (think of it exactly like what you are trying to do: "do not add item to list if list already contains item). You probably mean something like this (I just made up Item for example, use whatever class your objects are):
Item item = itemsListVMenuVINOSespumosos.get(position);
if (MiPedidoActivity.itemsListVMiPedido.contains(item)) { // <- look for item!
// ... item already in list
} else {
MiPedidoActivity.itemsListVMiPedido.add(item);
}
By the way, as a suggestion, if your item classes have equals() and hashCode() properly implemented, consider a LinkedHashSet (which will preserve insertion order but will not allow duplicates). There are other Set implementations that may be useful too (e.g. TreeSet if your items implement Comparable), depending on your ordering/sorting requirements.
I have a zul wich has two dependent combos. When an item of the first combo (cb_empresa_detalle) is checked then the second combo (cb_agente_detalle) loads its items.
In my controller I have this code:
#EventHandler("cb_empresa_detalle.onSelect")
public void loadAgentes(Event evt) throws WrongValueException,
InterruptedException {
if (cb_empresa_detalle.getSelectedItem() != null) {
idEmpresa = (String) cb_empresa_detalle.getSelectedItem()
.getValue();
// cb_agente_detalle.getChildren().clear();
cb_agente_detalle.getItems().clear();
(...)
This code throws a ConcurrenModificationException in lines (I tried the following two options), when I check in diferent items in first combo:
cb_agente_detalle.getChildren().clear(); // is now comented
cb_agente_detalle.getItems().clear();
Also, I tried this:
while (cb_agente_detalle.getItemCount() > 0) {
cb_agente_detalle.removeChild(cb_agente_detalle.getFirstChild());
}
Any idea?
A ConcurrentModificationException is thrown when you try to delete items from a collection when you're iterating over it using an iterator.
Just make sure it is not the case.
I have a SortedSet holding my ordered data.
I use the .first() method to return the first record, and pass it to another window.
When the other window finishes I get an event called, and I want to pass the next from the SortedSet to the window, so how to move to the next element?
launchWindow(this.set.first());
Then I have this:
onActivityResult(...) {
if (this.set.hasNext()) launchWindow(this.set.next());//hasNext/next doesn't exists in the current context for SortedSet
}
What options I have?
Instead of the Set you should pass the Iterator, then next consumer would just call next()
Don't you want to use an Iterator on the SortedSet?
The iterator solution:
You should probably have something like this:
class WindowLauncherClass {
SortedSet set = null;
Iterator setIterator = null;
public WindowLauncherClass(SortedSet set) {
this.set = set; // or you can copy it if that's what you need.
}
protected void launchWindow(Object item) {
// impl
}
public void onActivityResult() {
if ( setIterator != null && setIterator.hasNext() )
{
launchWindow(setIterator.next());
}
}
public void start() {
setIterator = set.iterator();
onActivityResult();
}
}
In the comments appeared the question about updates to the set. Will the iterator see it ?.
The normal answer is depends on the application requirements. In this case i don't have all the information and i'll try to guess.
until jdk 1.5 there was only one SortedSet implementstion ( TreeSet ). this had a fail fast iterator.
in jdk 6 appeared a new implementation: ConcurrentSkipListSet. The iterator for this sorted set is not a fail fast one.
If you are adding an element into the set that is "smaller" than the currently displayed element then you will not be able to see it anyway by a "good" (not fail fast) iterator. If you are adding an element "bigger" that the currently displayed element you will see it by a proper iterator.
The final solution is to actually reset the set and the iterator when a proper change is created. By using a ConcurrentSkipListSet initially you will see only the "bigger" changes and by using a TreeSet you will fail at every update.
If you afford to miss updates "smaller" than the current one then go for the jdk 6.0 and ConcurrentSkipListSet. If not than you'll have to keep track of what you displayed and rebuild a proper set with new items and undisplayed items.
Unless you're using some SortedSet from a third-party library, your set is also a NavigableSet (every SortedSet in java.util also implements NavigableSet). If you can make the event pass back the element it just finished working on, NavigableSet has a method higher which will get the next element higher than the one you pass in:
public void onActivityResult(Event event) {
Element element = event.processedElement;
Element next = set.higher(element);
if(next != null)
launchWindow(next);
}