Dav*_* T. 1 java multithreading android list arraylist
我有一个Minion对象的ArrayList,当一个盾与一个minion碰撞时,我想从ArrayList中删除那个minion.但是,我只能让它以单向工作,而不是另一种方式.任何人都可以解释为什么?
在所有3个案例中,我使用Android的Renderer的onDrawFrame()方法...所以我无法控制何时调用它.但这里是所有3种方式的代码:
方法1 :(不起作用)
public void onDrawFrame(GL10 gl) {
List<Integer> indexesToRemove = new ArrayList<Integer>();
int len = minions.size();
for(int i=0; i<len; i++){
if( OverlapTester.overlapCircleRectangle( (Circle)shield1.bounds, (Rectangle)minions.get(i).bounds) ){ //this tests out to work just fine
indexesToRemove.add(i);
}
}
for(int i=indexesToRemove.size()-1; i>=0; i--){
minions.remove(indexesToRemove.get(i)); //<------ why doesn't this work?
}
}
Run Code Online (Sandbox Code Playgroud)
问题是最后一行minions.remove(indexesToRemove.get(i));不能实际删除小兵.它会被适当的索引调用.我已经通过调试器,直接向上运行,并且根本没有修改arraylist.为什么是这样?实际上,在调试器中,该行"minions.remove(indexesToRemove.get(i));" 被称为数十亿次.
方法2 :(仍然不起作用)
public void onDrawFrame(GL10 gl) {
synchronized(minions){
List<Integer> indexesToRemove = new ArrayList<Integer>();
int len = minions.size();
for(int i=0; i<len; i++){
if( OverlapTester.overlapCircleRectangle( (Circle)shield1.bounds, (Rectangle)minions.get(i).bounds) ){ //this tests out to work just fine
indexesToRemove.add(i);
}
}
for(int i=indexesToRemove.size()-1; i>=0; i--){
minions.remove(indexesToRemove.get(i)); //<------ why doesn't this work?
}
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,我想......"哦,也许因为它没有完全同步,drawFrame有时被调用太多次并且在错误的时间访问arraylist并且我需要锁定它.但它仍然无效. ,minions.remove(indexesToRemove.get(i));用正确的索引正确调用该行,但实际上并没有删除该对象.我正在看着屏幕上的盾牌直接撞到了小兵身上,没有任何事情发生在小兵身上(它没有从arraylist中删除)
方法#3(这实际上有效)
public void onDrawFrame(GL10 gl) {
ArrayList<Minion> colliders = new ArrayList<Minion>(minions);
int len = colliders.size();
for(int i=0; i<len; i++){
GameObject collider = colliders.get(i);
if(OverlapTester.overlapCircleRectangle((Circle)shield1.bounds, (Rectangle)collider.bounds)){
minions.remove(collider); // <---- why does THIS work instead?
}
}
}
Run Code Online (Sandbox Code Playgroud)
这段代码完美无缺.盾牌击碎了仆从,仆从掉落了.正如你在这里看到的,唯一的区别是我正在使用重载ArrayList.remove(object)方法而不是通过索引删除.就像在线minions.remove(collider);.为什么这个有用?
有人可以解释一下吗?
另外,除了存储arraylist的另一个实例变量副本之外,还有更好的方法来管理ArrayList<Minion> colliders = new ArrayList<Minion>(minions);吗?
注意:Shield和Minion都是常规Java对象,具有矩形形状作为边界.所有数学检查都很好.我在调试器中对它进行了测试,并且碰撞检测是准确的.我也在更新onDrawFrame()方法中准确的边界/位置.
Jac*_*ack 10
因为ArrayList提供了两种方法:
public E remove(int index)
public boolean remove(Object o)
Run Code Online (Sandbox Code Playgroud)
当你调用时minions.remove(indexesToRemove.get(i)),因为indexesToRemove是a List<Integer>,调用被绑定到第二个签名,你通过直接指定对象来删除元素,自动取消装箱不会把你Integer变成一个,int所以找不到元素,没有任何反应.
尝试使用:minions.remove((int)indexesToRemove.get(i))以便正确应用方法的静态绑定.
@杰克的回答是对的.对于后代,你应该在Iterator这里使用你可以在你的循环内删除:
// synchronization wrapper here
Iterator<Minion> iterator = minions.iterator();
while (iterator.hasNext()) {
Minion minion = iterator.next();
if( OverlapTester.overlapCircleRectangle(..., minion.bounds)) {
iterator.remove();
}
}
Run Code Online (Sandbox Code Playgroud)