【问题标题】:IndexOutOfBoundsException when removing certain items from custom ItemizedOverlay从自定义 ItemizedOverlay 中删除某些项目时出现 IndexOutOfBoundsException
【发布时间】:2012-01-24 15:27:13
【问题描述】:

几天来,我一直在努力解决以下问题。我找到了很多关于这个主题的线程,但都有些不同或没有解决方案。

对于我的项目,我创建了一个自定义 ItemizedOverlay 并将其添加到我的 MapView。如果我现在删除项目列表的最后一项,我会得到一个IndexOutOfBoundsException,声称请求的索引等于ArrayList 的大小。 IE。索引 2 大小 2 或索引 0 大小 0。从其他主题告诉我的内容来看,我已经尝试过 populate()setLastFocusedIndex(-1) 方法。这些解决了我遇到的其他问题,但没有解决这个问题。从列表中删除其他项目时它工作正常,问题似乎只发生在最后一项。

我得到以下 Logcat 输出:

01-24 16:11:08.091: E/AndroidRuntime(916): Uncaught handler: thread main exiting due to uncaught exception
01-24 16:11:08.101: E/AndroidRuntime(916): java.lang.IndexOutOfBoundsException: Invalid location 0, size is 0
01-24 16:11:08.101: E/AndroidRuntime(916):  at java.util.ArrayList.get(ArrayList.java:341)
01-24 16:11:08.101: E/AndroidRuntime(916):  at com.google.android.maps.ItemizedOverlay.getItem(ItemizedOverlay.java:419)
01-24 16:11:08.101: E/AndroidRuntime(916):  at com.google.android.maps.ItemizedOverlay.focus(ItemizedOverlay.java:538)
01-24 16:11:08.101: E/AndroidRuntime(916):  at com.google.android.maps.ItemizedOverlay.onTap(ItemizedOverlay.java:455)
01-24 16:11:08.101: E/AndroidRuntime(916):  at com.google.android.maps.OverlayBundle.onTap(OverlayBundle.java:83)
01-24 16:11:08.101: E/AndroidRuntime(916):  at com.google.android.maps.MapView$1.onSingleTapUp(MapView.java:346)
01-24 16:11:08.101: E/AndroidRuntime(916):  at android.view.GestureDetector.onTouchEvent(GestureDetector.java:506)
01-24 16:11:08.101: E/AndroidRuntime(916):  at com.google.android.maps.MapView.onTouchEvent(MapView.java:628)
01-24 16:11:08.101: E/AndroidRuntime(916):  at android.view.View.dispatchTouchEvent(View.java:3709)
01-24 16:11:08.101: E/AndroidRuntime(916):  at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:852)
01-24 16:11:08.101: E/AndroidRuntime(916):  at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
01-24 16:11:08.101: E/AndroidRuntime(916):  at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
01-24 16:11:08.101: E/AndroidRuntime(916):  at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
01-24 16:11:08.101: E/AndroidRuntime(916):  at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
01-24 16:11:08.101: E/AndroidRuntime(916):  at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1659)
01-24 16:11:08.101: E/AndroidRuntime(916):  at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1107)
01-24 16:11:08.101: E/AndroidRuntime(916):  at android.app.Activity.dispatchTouchEvent(Activity.java:2061)
01-24 16:11:08.101: E/AndroidRuntime(916):  at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1643)
01-24 16:11:08.101: E/AndroidRuntime(916):  at android.view.ViewRoot.handleMessage(ViewRoot.java:1691)
01-24 16:11:08.101: E/AndroidRuntime(916):  at android.os.Handler.dispatchMessage(Handler.java:99)
01-24 16:11:08.101: E/AndroidRuntime(916):  at android.os.Looper.loop(Looper.java:123)
01-24 16:11:08.101: E/AndroidRuntime(916):  at android.app.ActivityThread.main(ActivityThread.java:4363)
01-24 16:11:08.101: E/AndroidRuntime(916):  at java.lang.reflect.Method.invokeNative(Native Method)
01-24 16:11:08.101: E/AndroidRuntime(916):  at java.lang.reflect.Method.invoke(Method.java:521)
01-24 16:11:08.101: E/AndroidRuntime(916):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
01-24 16:11:08.101: E/AndroidRuntime(916):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
01-24 16:11:08.101: E/AndroidRuntime(916):  at dalvik.system.NativeStart.main(Native Method)

对此困扰我的是,它似乎是从标准ItemizedOverlay 调用方法。我没有添加普通的ItemizedOverlay,并且除了在构造函数中之外,我不会在我的itemizedOverlay 中调用超级方法。错误似乎仍然发生在正常的ItemizedOverlay 中,因此ArrayList 为空是有道理的。

我希望有人能指出我正确的方向,因为我真的觉得被困在这里。提前致谢!

这是我的代码:

public class GameItemOverlay extends ItemizedOverlay<Item> {

    private ArrayList<Item> mOverlays = new ArrayList<Item>();


    public GameItemOverlay(Drawable defaultMarker) {
        super(boundCenterBottom(defaultMarker));
        setLastFocusedIndex(-1);
        populate(); 
    }

    public void itemDataReady(){
        mOverlays = GameSession.items;
        setLastFocusedIndex(-1);
        populate();
    }

    @Override
    protected Item createItem(int i) {
      return mOverlays.get(i);
    }

    @Override
    public int size() {
      return mOverlays.size();
    }

    @Override
    protected boolean onTap(int i){
        GameSession.remove(mOverlays.get(i).getID()); //Removes the item according to it's position

        setLastFocusedIndex(-1);
        populate();   
        return true;

    }
}

【问题讨论】:

  • 删除前检查:if (index
  • 发布您的自定义 itemizedOverlay 代码
  • @Adrian 我确实逐步完成,并且在删除项目期间不会发生错误。一切顺利,直到删除方法完成后才会发生错误。这就是为什么我认为检查列表实际上没有用。但我会再看看它。感谢您的意见。

标签: android android-mapview itemizedoverlay indexoutofboundsexception


【解决方案1】:

我花了一段时间才弄清楚问题所在。我认为这个问题的答案是ItemizedOverlay不打算用于管理(添加和删除)OverlayItems。您几乎只能将OverlayItems 添加到ItemizedOverlay,如果您想更改任何项目,则需要重新创建ItemizedOverlay(效率不高)。要解决此问题,您需要管理Overlays 列表中的ItemizedOverlays(只有一个OverlayItem),而不是ItemizedOverlay 中的OverlayItems。类似的东西:

public class SomeActivity extends MapActivity {

    private SomeMapView mView;

    // Rest of the code ...

    private void sendRequest(GeoPoint point)
    {
        List<Overlay> mOverlays = mView.getOverlays();
        // Show red marker
        OverlayItem item    = new OverlayItem(point, "Hello", "world");   
        MarkerItemizedOverlay itemOverlay   = new MarkerItemizedOverlay(drawable, mView);
        itemOverlay.addOverlay(item);
        mOverlays.add(itemOverlay);
    }
}

public class MarkerItemizedOverlay extends ItemizedOverlay<OverlayItem> {

    private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
    MapView mView;

    // Rest of the code ...

    @Override
    protected boolean onTap(int index) {
        List<Overlay> mOverlays = mView.getOverlays();
        mOverlays.remove(this);
    }
}

【讨论】:

  • 感谢您的回复。听起来不错,虽然听起来也有点慢;)但我不想在不尝试的情况下得出任何结论。最后我使用了不同的“解决方案”。它并不优雅,但效果很好。您必须在列表末尾添加一个空项目。这将防止错误发生。您只需要在添加/删除项目时多加注意。
【解决方案2】:

遇到了同样的问题,并找到了解决方法。 当您缩小 onTap 方法中的 OverlayItem 列表时,似乎 Google 的代码向上(或向下)调用链变得非常混乱。显然有一些索引没有更新(或更新太早) - 因此是 IOOBE。

我的解决方案基于我的 ItemizedOverlay 子类中还有一个 GestureDetector(我使用 onSingleTapConfirmed() 将项目添加到我的地图)。

  • ItemizedOverlay.onTap(int)函数中保存刚刚点击的OverlayItem的索引,但不要修改列表(暂时)
  • onSingleTapConfirmed() 中检查是否设置了“justTapped”变量。
    • 如果有,请将其从列表中删除
    • 调用 setLastFocusedIndex(-1)populate() 在内部更新 Overlay
    • invalidate()要重绘的 MapView。
  • (可选)跳一段快乐的舞蹈来庆祝您的工作代码。

希望这对任何人都有帮助!

【讨论】:

    【解决方案3】:

    我遇到了同样的问题。在我的情况下,我扩展了 ItemizedOverlay,并且在里面 - 保留了一个 OverlayItems 数组。每次我平移或缩放地图时,我都会清除内部项目列表,添加新项目,然后调用填充。 (通过我在某处找到的一些例子)。问题是基类——ItemizedOverlay,保留了一个内部变量“lastFocusedIndex”。重新填充列表后,如果未重置 - 下次您决定单击地图中的某个位置时 - 它首先决定从 lastSelectedItem 移除焦点....现在 - 如果您的新列表包含的项目少于值lastSelectedItem - 然后它失败并出现此异常。

    在我的情况下,解决方案是 - 在清除 OverlayItems 的内部列表之后,还调用 setLastFocusedIndex(-1) - 这可以确保一切都被重置。

    一些对我调试有用的注释: 1. 从 android-sdk 的 maps.jar 反编译 ItemizedOverlay - 没有帮助,因为这只是一个 API/Stub jar,不包含 @runtime 使用的真实类 2.使用DDMS下载system/framwork/com.google.android.maps.jar 3.使用dex2jar进行转换,然后解压出正确的class文件进行反编译

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多