yandexmobile / yandexmapkit-android

Yandex Map Kit for Android
161 stars 65 forks source link

Ошибка при открытии карты onSingleTapUp #119

Open drs88 opened 11 years ago

drs88 commented 11 years ago

Изредка при работе программы происходит следующая ошибка во время открытия карты (согласно описанию пользователей). Не могу понять где она может быть, т.к. не представляю как работает данный метод, мб что-то забыл указать или добавить, При загрузке карты добавляются несколько custom объектов наследующих BalloonItem и позиционируется на них. Подскажите хотя бы в какую сторону можно копать.

java.lang.NullPointerException at ru.yandex.yandexmapkit.overlay.OverlayItem.getRectBounds(Unknown Source) at ru.yandex.yandexmapkit.overlay.Overlay.a(Unknown Source) at ru.yandex.yandexmapkit.overlay.Overlay.onSingleTapUp(Unknown Source) at ru.yandex.yandexmapkit.OverlayManager.onSingleTapUp(Unknown Source) at ru.yandex.yandexmapkit.MapController.onSingleTapUp(Unknown Source) at f.onSingleTapUp(Unknown Source) at android.view.GestureDetector.onTouchEvent(GestureDetector.java:557) at f.a(Unknown Source) at ru.yandex.yandexmapkit.MapController.onTouchEvent(Unknown Source) at ru.yandex.yandexmapkit.MapSurfaceView.onTouchEvent(Unknown Source) at android.view.View.dispatchTouchEvent(View.java:3885) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942) at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1808) at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1141) at android.app.Activity.dispatchTouchEvent(Activity.java:2099) at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1792) at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2208) at android.view.ViewRoot.handleMessage(ViewRoot.java:1881) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:130) at android.app.ActivityThread.main(ActivityThread.java:3706) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:507) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599) at dalvik.system.NativeStart.main(Native Method)

ghost commented 11 years ago

скинь код которым производишь отрисовку

drs88 commented 11 years ago

Метод onCreate:

        setContentView(R.layout.map);

        mapView = (MapView)findViewById(R.id.map);
        mapView.showZoomButtons(true);
        mapView.showScaleView(true);

        mapView.showFindMeButton(false);
        mapView.showJamsButton(true);
        mc = mapView.getMapController();
        overlayManager = mc.getOverlayManager();

        //Стандартный слой для отображения объектов
        overlay = new Overlay(mc);
        //Устанавливаем заголовок, если передан
        String title = this.getIntent().getStringExtra("title");
        if (title == null)
            title = "Карта";
        MyLog.d(Program.logTag, "Открываются Яндекс.Карты, устанавливаем заголовок - " + title);
        setTitle(title);

        //В различии от переданных параметров показываем различные режимы
        OrderPos order = (OrderPos)this.getIntent().getParcelableExtra("order");
        Parcelable[] pars = this.getIntent().getParcelableArrayExtra("orders");
        currentParking = this.getIntent().getParcelableExtra("parking");

        type = (OrderType) this.getIntent().getSerializableExtra("orderType");

        //Если задан один заказ - отображаем его
        if (order != null)
        {
            addOrderBulloon(order, false, type, currentParking);
            MyLog.d(Program.logTag, "Задан заказ - " + order);
        }

        //Если задан массив заказов - отображаем их
        if (pars != null)
        {
            MyLog.d(Program.logTag, "Задан список заказов");
            for (int i = 0; i < pars.length; i++)
            {
                order = (OrderPos)pars[i];
                addOrderBulloon(order, true, type, currentParking);
            }
        }

        int count = overlay.getOverlayItems().size();
        if (count > 0)
        {
            overlayManager.addOverlay(overlay);
            if (count == 1)
            {
                OverlayItem item = (OverlayItem) overlay.getOverlayItems().get(0);
                mc.setPositionNoAnimationTo(item.getGeoPoint());
                mc.setZoomCurrent(zoomForOneObject);
            }
            else
            {
                //mc.setZoomCurrent(17);
                //mc.setZoomToSpan(arg0, arg1)
                setZoomSpan(mc, overlay.getOverlayItems());
            }   
        }
        else
        {
            MyLog.d(Program.logTag, "Объектов на карте нет");
        }

        //Создаём список доступных подложек
        mapLayers = mc.getListMapLayer();
        //Пробуем получить сохраненный слой
        String userLayerRequestName = Config.settings.getString(settingsLayerName, "pmap");

        MyLog.d(Program.logTag, "Устанавливаем подложку - " + userLayerRequestName);

        MapLayer userLayer = mc.getMapLayerByLayerRequestName(userLayerRequestName);
        if (userLayer != null)
        {
            mc.setCurrentMapLayer(userLayer);
        }

Метод setZoomSpan

private void setZoomSpan(MapController mc, List<OverlayItem> list)
{
    int count = list.size();
    double maxLat, minLat, maxLon, minLon;
    maxLat = maxLon = Double.MIN_VALUE;
    minLat = minLon = Double.MAX_VALUE;
    for (int i = 0; i < count; i++)
    {
        GeoPoint geoPoint = list.get(i).getGeoPoint();
        double lat = geoPoint.getLat();
        double lon = geoPoint.getLon();

        maxLat = Math.max(lat, maxLat);
        minLat = Math.min(lat, minLat);
        maxLon = Math.max(lon, maxLon);
        minLon = Math.min(lon, minLon);
    }

    double width = maxLon - minLon;
    double heigh = maxLat - minLat;

    double coor = 0.25;

    maxLon += heigh * coor;
    minLat -= width * coor;
    minLon -= heigh * coor;
    maxLat += width * coor;

    mc.setZoomToSpan(maxLat - minLat, maxLon - minLon);
    mc.setPositionAnimationTo(new GeoPoint((maxLat + minLat)/2, (maxLon + minLon)/2));
}
ghost commented 11 years ago

Есть вероятность что вызов setZoomSpan в onCreate это делает попробуй перенеси его в onResume... но не уверен

что за метод addOrderBulloon

drs88 commented 11 years ago

Спасибо за помощь, попробую, правда быстро выяснить вряд ли получится, сложно воспроизводимая, изменю в новой версии.

Метод добавления произвольного балуна на карту

private void addOrderBulloon(OrderPos order, boolean clickable, OrderType type, Parking parking)
{
    //Создаём точку заказа, если у него есть координаты
    if ((order.latitude != 0) && (order.longitude != 0))
    {
        OverlayItem orderItem = new OverlayItem(new GeoPoint(order.latitude, order.longitude), getResources().getDrawable(R.drawable.order_icon));
        OrderBalloonItem balloonOrder = new OrderBalloonItem(this, order, type, parking);
        if (clickable)
            balloonOrder.setOnViewClickListener();
        orderItem.setBalloonItem(balloonOrder);
        overlay.addOverlayItem(orderItem);
    }
    else
        MyLog.w(Program.logTag, "При добавлении на карту:у заказа нет координат order = " + order);
}

Класс для этого

public class OrderBalloonItem extends BalloonItem implements OnBalloonListener { Context context; OrderPos order; OrderType type; //Какой стоянке принадлежит заказ (для свободных) Parking currentParking; public OrderBalloonItem(Context context, OrderPos order, OrderType type, Parking parking) { super(context, new GeoPoint(order.latitude, order.longitude)); this.order = order; this.context = context; this.type = type; this.currentParking = parking; this.setText(order.getOrderDescription(context, type)); }

public void setOnViewClickListener()
{
    setOnBalloonViewClickListener(R.id.ymk_balloon_text_view, this);
}

public void onBalloonViewClick(BalloonItem object, View text)
{
    try
    {
        Intent intent = new Intent(context, OrderActivity.class);
        intent.putExtra("order", order);
        intent.putExtra("orderType", type);
        intent.putExtra("parking", currentParking);
        //Даже если он не часть множества заказов, всё равно отправляем true, чтобы была возможность вернуться на карту
        intent.putExtra("partOfManyOrders", true);
        context.startActivity(intent);
    }
    catch (Exception e) 
    {
        MyLog.e(Program.logTag, "Ошибка при обработке нажатия на OrderBalloonItem", e);
    }
}

public void onBalloonAnimationEnd(BalloonItem arg0) 
{

}

public void onBalloonAnimationStart(BalloonItem arg0) 
{

}

public void onBalloonHide(BalloonItem arg0)
{

}

public void onBalloonShow(BalloonItem arg0) 
{

}

}

osipkat commented 11 years ago

У меня карта падает с таким же логом. Вообще активити с картой запускается с некоторой задержкой после вызова. Так вот если в время этой задержки тапнуть по экрану, приложение падает с этим вот логом. И сама эта задержка (до 2 секунд) сама по себе тоже напрягает.

ghost commented 11 years ago

видимо не успевают прорисоваться все слои... а инет какой wifi или gprs?

osipkat commented 11 years ago

wifi

osipkat commented 11 years ago

Как же с этим бороться?

ghost commented 11 years ago

если идет задержка вызова активити значит что от нагруженно в мтоде onCreate я например саму карту помещал во Fragment в onCreateView делал findViewById а уже в onResume всякие опреации по проиросвке балунов центриорвоания и прочее попрбуйте может поможет ... или как вариант (но это костыль) сделайте задержку сек 2-3 перед происовкой балуна

drs88 commented 11 years ago

Действительно, теперь ошибку смог воспроизвести, может на время загрузки делать MapView не активным, а поверх что-то показывать? но как понять когда карта прогрузилась? У меня проблема была, даже когда балунов не было на карте. UPD: При этом только при первом отображении карта вызывается, при последующем всё быстро работает, мб уже загружено в памяти что-то.

ghost commented 11 years ago

покопайте в сторну addOnGlobalLayoutListener вот пример для гугла http://stackoverflow.com/questions/14456382/why-does-googlemap-animatecamera-crash-after-ongloballayout по идее можно отловить когда карта отрендерилась

или же статично ждите примерн 5 сек и показывйте лоадер поверх карты

mksaint13 commented 11 years ago

Иногда есть такая проблема и мы ее по фиксили, надеемся что скоро выложим.

osipkat commented 11 years ago

А как-то можно эту проблему обойти до выхода этого фикса? Вариант с addOnGlobalLayoutListener мне не помог.

mksaint13 commented 11 years ago

Возможных решений пока не вижу. а так из за чего может падать. Это либо mDrawable в OverlayItem null или не успели сформироваться данные для getScreenPoint(), то есть пытаетесь чтото сделать с OverlayItem когда у него не просетилось значение ScreenPoint,

drs88 commented 11 years ago

Не знаю стоит ли создавать отдельную тему, но возникла проблема с тем же кодом при открытии карты. Судя по стек трейсу во время ручного зума, есть логи, что это произошло параллельно центрированию на карте по таймеру (через runOnUiThread) объектов на карте (метод setZoomSpan). Не сталкивался ли кто-нибудь с подобным? баг в библиотеке или ошибка в коде?

java.lang.ArrayIndexOutOfBoundsException: length=121; index=121 at x.d(Unknown Source) at x.h(Unknown Source) at ru.yandex.yandexmapkit.MapModel.startManualZoom(Unknown Source) at ru.yandex.yandexmapkit.MapController.onScaleBegin(Unknown Source) at f.a(Unknown Source) at ru.yandex.yandexmapkit.MapController.onTouchEvent(Unknown Source) at ru.yandex.yandexmapkit.MapSurfaceView.onTouchEvent(Unknown Source) at android.view.View.dispatchTouchEvent(View.java:5546) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1726) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1726) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1726) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1726) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1726) at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1912) at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1371) at android.app.Activity.dispatchTouchEvent(Activity.java:2364) at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1860) at android.view.View.dispatchPointerEvent(View.java:5726) at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:2890) at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2466) at android.view.ViewRootImpl.processInputEvents(ViewRootImpl.java:845) at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2475) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4424) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) at dalvik.system.NativeStart.main(Native Method)

mksaint13 commented 11 years ago

Очень странно можешь точно описать последовательно шаги попробуем на своей стороне потестировать

drs88 commented 11 years ago

Ошибка произошла у клиента, ко мне дошёл только отчёт, судя по нему в ту же секунду, что закончился метод onCreate, может быть и после onResume() уже, так как там логов нет. Я предполагаю, что он раздвигал пальцами (как и в случае простого прикосновения onTouch) во время загрузки карты. Лично воспроизвести мне не удалось пока.

drs88 commented 11 years ago

Небольшое дополнение, произошла второй раз похожая ошибка, лог немного другой, после поворота карты, для неё использовал статью http://habrahabr.ru/post/167807/, или это недокументированная функция?

java.lang.ArrayIndexOutOfBoundsException at x.d(Unknown Source) at x.h(Unknown Source) at ru.yandex.yandexmapkit.MapModel.startManualZoom(Unknown Source) at ru.yandex.yandexmapkit.MapController.onScaleBegin(Unknown Source) at f.a(Unknown Source) at ru.yandex.yandexmapkit.MapController.onTouchEvent(Unknown Source) at ru.yandex.yandexmapkit.MapSurfaceView.onTouchEvent(Unknown Source) at android.view.View.dispatchTouchEvent(View.java:3910) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:936) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:936) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:936) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:936) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:936) at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1713) at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1118) at android.app.Activity.dispatchTouchEvent(Activity.java:2086) at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1697) at android.view.ViewRoot.handleMessage(ViewRoot.java:1785) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:123) at android.app.ActivityThread.main(ActivityThread.java:4627) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:521) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618) at dalvik.system.NativeStart.main(Native Method)

mksaint13 commented 11 years ago

Почему, ее использовать можно, но я б на данный момент не советовал, так как в у этой функции есть ряд багов до которых еще руки не дошли )

maxxx commented 11 years ago

никаких новостей по null в getRectBounds ? Баг все также проявляется при клике на карту с непрогруженным до конца слоем

alexkipar commented 11 years ago

никто не пришел к какому-то воркэраунду? в приложении изредка у разных пользователей приложение валиться с этим же стектрейсом

apodkin commented 11 years ago

У меня продолжало падать, в конце концов написал такой костыль:

public class YandexMapContainer extends FrameLayout {

    @Override
    public boolean dispatchTouchEvent(MotionEvent motionEvent) {
        try {
            return super.dispatchTouchEvent(motionEvent);
        } catch (Exception e) {
            return false;
        }
    }
}

Положил карту в него. Теперь все исключения тупо гасятся, приложение не падает.

eugene0785 commented 10 years ago

Аналогичная проблема, также в итоге пришлось применить решение с глушением исключений. Ждем официального фикса.

sirekanyan commented 7 years ago

Столкнулся с аналогичной проблемой: NullPointerException: Attempt to invoke virtual method 'float ru.yandex.yandexmapkit.utils.ScreenPoint.getX()' on a null object reference

java.lang.NullPointerException: Attempt to invoke virtual method 'float ru.yandex.yandexmapkit.utils.ScreenPoint.getX()' on a null object reference
    at ru.yandex.yandexmapkit.overlay.OverlayItem.getRectBounds(Unknown Source)
    at ru.yandex.yandexmapkit.overlay.Overlay.a(Unknown Source)
    at ru.yandex.yandexmapkit.overlay.Overlay.onSingleTapUp(Unknown Source)
    at ru.yandex.yandexmapkit.OverlayManager.onSingleTapUp(Unknown Source)
    at ru.yandex.yandexmapkit.MapController.onSingleTapUp(Unknown Source)
    at ru.yandex.ae.onSingleTapUp(Unknown Source)
    at android.view.GestureDetector.onTouchEvent(GestureDetector.java:595)
    at ru.yandex.ae.a(Unknown Source)
    at ru.yandex.yandexmapkit.MapController.onTouchEvent(Unknown Source)
    at ru.yandex.yandexmapkit.MapStaticView.onTouchEvent(Unknown Source)
    at android.view.View.dispatchTouchEvent(View.java:8808)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2581)
        ...