IndexOutOfBoundsException при удалении определенных элементов из пользовательского ItemizedOverlay - PullRequest
1 голос
/ 24 января 2012

Я боролся со следующей проблемой уже несколько дней. Я нашел много тем по этой теме, но все немного по-другому или не было решения.

Для своего проекта я создал пользовательский ItemizedOverlay и добавил его в свой MapView. Если я сейчас удаляю последний элемент списка элементов, я получаю IndexOutOfBoundsException, утверждая, что запрошенный индекс равен размеру ArrayList. То есть index 2 size 2 или index 0 size 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;

    }
}

Ответы [ 3 ]

3 голосов
/ 28 апреля 2012

Мне понадобилось время, чтобы понять проблему. Я думаю, что ответ на этот вопрос заключается в том, что ItemizedOverlay - это , а не , предназначенное для управления (добавления и удаления) OverlayItem s. Вы можете только добавить OverlayItem s к ItemizedOverlay, и если вы хотите изменить какой-либо элемент, вам нужно воссоздать ItemizedOverlay (не эффективно). Чтобы решить эту проблему, вам нужно управлять ItemizedOverlay с (с одним OverlayItem) в списке Overlay с вместо OverlayItem с в ItemizedOverlay. Примерно так:

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);
    }
}
1 голос
/ 23 февраля 2013

У меня была такая же проблема. В моем случае я расширил ItemizedOverlay, а внутри - сохранил массив OverlayItems. Каждый раз, когда я панорамировал или увеличивал масштаб карты, я очищал внутренний список элементов, добавлял новые и затем вызывал заполнение. (По какому-то примеру я где-то нашел). Проблема заключалась в том, что базовый класс - ItemizedOverlay, хранит внутреннюю переменную «lastFocusedIndex». После повторного заполнения списка, если он не был сброшен - в следующий раз, когда вы решите щелкнуть где-нибудь на карте, - он сначала решил удалить фокус из lastSelectedItem .... А теперь - если ваш новый список содержит меньше элементов, чем значение of lastSelectedItem - тогда это терпит неудачу с этим исключением.

Решение в моем случае было - после очистки внутреннего списка OverlayItems, также вызвать setLastFocusedIndex (-1) - это гарантирует, что все сбрасывается.

Несколько замечаний о том, что для меня было полезно отладить: 1. Декомпилированный ItemizedOverlay из maps.jar из android-sdk - не помогает, так как это всего лишь jar API / заглушки, который не содержит реальных классов, используемых @ runtime 2. Используя DDMS скачанную систему / framwork / com.google.android.maps.jar 3. преобразовал его с помощью dex2jar, а затем распаковал правильный файл класса для декомпиляции

1 голос
/ 03 июля 2012

Получил такую ​​же проблему и обходной путь. Кажется, что код Google вверх (или вниз) цепочки вызовов становится ужасно запутанным, когда вы сокращаете список OverlayItem в методе onTap. Очевидно, есть какой-то индекс, который не обновляется (или обновляется слишком рано) - отсюда и IOOBE.

Мое решение основано на том факте, что у меня также есть GestureDetector в моем подклассе ItemizedOverlay (я использую onSingleTapConfirmed() для добавления элементов на мою карту).

  • в функции ItemizedOverlay.onTap(int) сохранить индекс только что затронутого элемента OverlayItem, но не изменять список (пока)
  • in onSingleTapConfirmed() проверить, установлена ​​ли переменная justTapped.
    • Если это так, удалить его из списка
    • вызовите setLastFocusedIndex(-1) и populate() для внутреннего обновления наложения
    • invalidate() MapView для перекраски.
  • (опционально) немного потанцевать, чтобы отметить ваш рабочий код.

Надеюсь, это кому-нибудь поможет!

...