在Android Maps API v2中跳跃标记的解决方法

12
我在Android Maps API v2上看到标记在地图上跳动,即使应用程序中没有发生任何事情。
以下是行为的视频:

https://youtu.be/cOUGD0T5Ojs

我期望的

标记应该保持在它们最初添加的经纬度上不动。

能重现问题的步骤是什么?

    1. 构建、安装并运行OneBusAway的v2.0.6标签:
      • a. git clone https://github.com/OneBusAway/onebusaway-android.git
      • b. git checkout v2.0.6
      • c. gradlew installObaGoogleDebug
      • d. adb shell am start -n com.joulespersecond.seattlebusbot/org.onebusaway.android.ui.HomeActivity
    1. 浏览到任何受支持的城市(例如西雅图或坦帕),并观察地图上绿色公交车站标记的跳动

我应该补充说,我不能总是重现这个问题。似乎一切正常工作一段时间后,当标记开始跳动时,它们就不会停止。

标记实现细节

加载用于9种标记类型(8个方向+无方向)的图标的代码在这里: https://github.com/OneBusAway/onebusaway-android/blob/master/onebusaway-android/src/google/java/org/onebusaway/android/map/googlemapsv2/StopOverlay.java#L175

我正在使用这个可绘制对象: https://github.com/OneBusAway/onebusaway-android/blob/master/onebusaway-android/src/main/res/drawable/map_stop_icon.xml

... 它由许多形状组成 - 这创建了带有白色轮廓和投影阴影的主要绿色圆圈。然后,我在此可绘制对象的顶部为每个8个方向绘制方向箭头 - 绘制方向的代码在这里:

https://github.com/OneBusAway/onebusaway-android/blob/master/onebusaway-android/src/google/java/org/onebusaway/android/map/googlemapsv2/StopOverlay.java#L208

在加载图标的代码中,我对每种类型的9个图标在第一次加载时缓存了从BitmapDescriptorFactory.fromBitmap()返回的BitmapDescriptor,所以不需要在每次放置标记时都进行此操作。
我还看到应用程序在地图屏幕上停留几分钟后崩溃并显示“很遗憾,OneBusAway已停止。”,并在Logcat中看到此异常。
08-10 16:40:02.422  15843-15929/com.joulespersecond.seattlebusbot E/AndroidRuntime﹕ FATAL EXCEPTION: GLThread 8614
    Process: com.joulespersecond.seattlebusbot, PID: 15843
    java.lang.IllegalArgumentException: Comparison method violates its general contract!
            at java.util.ComparableTimSort.mergeHi(ComparableTimSort.java:831)
            at java.util.ComparableTimSort.mergeAt(ComparableTimSort.java:449)
            at java.util.ComparableTimSort.mergeCollapse(ComparableTimSort.java:372)
            at java.util.ComparableTimSort.sort(ComparableTimSort.java:178)
            at java.util.ComparableTimSort.sort(ComparableTimSort.java:142)
            at java.util.Arrays.sort(Arrays.java:1957)
            at java.util.Collections.sort(Collections.java:1864)
            at com.google.maps.api.android.lib6.gmm6.n.bl.a(Unknown Source)
            at com.google.maps.api.android.lib6.gmm6.n.l.a(Unknown Source)
            at com.google.maps.api.android.lib6.gmm6.n.l.b(Unknown Source)
            at com.google.maps.api.android.lib6.gmm6.n.cv.f(Unknown Source)
            at com.google.maps.api.android.lib6.gmm6.n.cv.run(Unknown Source)

我在LG G4和Nexus 6上见过这个问题。下面是有关LG设备的更多详细信息。

  • LG G4 LS991,Android 5.1(LS991ZV4)

  • Google Play服务客户端库版本 = compile 'com.google.android.gms:play-services-maps:7.5.0'compile 'com.google.android.gms:play-services-maps:7.8.0'

  • 设备上的Google Play服务版本 - Google Play服务7.8.99(2134222-440)

  • Android SDK版本:compileSdkVersion 21 buildToolsVersion "21.1.2"

这个问题并不总是存在,这让我相信它是在某个时候更新了Android Google Play Services/Maps时引入的。

我也在gmaps-api-issues上为此打开了一个问题,但截至本帖发布时还没有回应:

https://code.google.com/p/gmaps-api-issues/issues/detail?id=8455

有其他人看到过这个问题吗?有任何修复的想法吗?

编辑

我应该补充说明,我不能总是重现这个问题。似乎一切正常工作一段时间,但当标记开始跳动时,它们就不会停止。

编辑2

我在Github上创建了一个较小的演示项目,使用相同的标记实现:

https://github.com/barbeau/maps-demo

然而,我还没有在那里看到同样的问题。
编辑3:我已经改为在https://github.com/OneBusAway/onebusaway-android/commit/01b35e9a07313a627843819d66b3f6a9bb7e848f中缓存位图而不是位图描述符。
我们将看到这是否可以解决问题。它是间歇性的,所以唯一的方法就是如果我在一段时间内再也没有看到这个问题,我才会知道。
编辑4:我仍然看到这个问题,所以看起来从缓存位图描述符切换到位图,并改用ContextCompat.getDrawable()没有任何效果。
编辑5:不确定是否相关,但当发生这种情况时,我还看到以下输出在Logcat中:

09-01 10:46:00.339 9278-9278/? E/libEGL﹕ validate_display:255 error 3008 (EGL_BAD_DISPLAY) 09-01 10:46:00.339 9278-9278/? E/libEGL﹕ validate_display:255 error 3008 (EGL_BAD_DISPLAY)

09-01 10:46:00.069 9278-9278/? W/ResourcesManager﹕ 资源路径'/system/framework/com.google.android.maps.jar'不存在或不包含资源。

09-01 10:46:16.019 1137-4311/? W/ActivityManager﹕ 在1000毫秒内重新启动崩溃的服务com.google.android.gms/.usagereporting.service.UsageReportingService 09-01 10:46:16.019 1137-4311/? W/ActivityManager﹕ 在11000毫秒内重新启动崩溃的服务com.google.android.gms/.icing.service.IndexService

09-01 10:48:38.609 5402-26676/? E/SQLiteDatabase﹕ 插入错误,context表的唯一约束条件context_id失败 (code 2067)。在最后插入的行中执行了重复的context_id。在本地方法中执行了SQLiteConnection.nativeExecuteForLastInsertedRowId(),然后在SQLiteConnection.executeForLastInsertedRowId()和SQLiteSession.executeForLastInsertedRowId()中执行。在SQLiteStatement.executeInsert()中执行了插入操作。在SQLiteDatabase.insertWithOnConflict()中执行插入操作。在com.google.android.contextmanager.q.ak.a(SourceFile:405)中执行了插入操作。在com.google.android.contextmanager.q.ak.b(SourceFile:380)中执行了插入操作。在com.google.android.contextmanager.q.ak.a(SourceFile:346)中执行了插入操作。在com.google.android.contextmanager.q.ak.b(SourceFile:373)中执行了插入操作。在com.google.android.contextmanager.g.a.j.a(SourceFile:58)中执行了插入操作。在com.google.android.contextmanager.g.a.a.run(SourceFile:52)中执行了插入操作。在com.google.android.contextmanager.g.i.handleMessage(SourceFile:214)中处理了消息。在Handler.dispatchMessage()中分发了消息,在Looper.loop()中循环处理消息,并在HandlerThread.run()中运行。

编辑6 我最近没有看到这个问题,我注意到LG G4设备上的Google Play服务已经升级到8.1.15(2250156-240)。因此,也许通过更新Google Play服务来解决了这个问题?我稍后会再次报告。

编辑7 我在8.1.15(2250156-240)8.1.18(2272748-240)中又见到了这个问题,尽管它似乎不像以前那么严重(即,跳动的标记更少,且跳动不太明显)。它似乎主要是在应用程序暂停一段时间后恢复时触发。如果我杀死应用程序,然后重新启动它,问题就消失了。

编辑8 我找到了一种可以持续重现这个问题的方法-请参见: https://code.google.com/p/gmaps-api-issues/issues/detail?id=8455#c2

来自上述问题:

  1. 构建,安装并运行OneBusAway的v2.0.6标签:

    a. git clone https://github.com/OneBusAway/onebusaway-android.git

    b. git checkout v2.0.6

    c. gradlew installObaGoogleDebug

    d. adb shell am start -n com.joulespersecond.seattlebusbot/org.onebusaway.android.ui.HomeActivity

  2. 将设备保持竖屏方向

  3. 如果您不在西雅图或坦帕(或任何支持的地区)物理位置上,则需要转到“设置->您的地区”手动设置地区。完成后,请将地图滚动到该地区(或在提示时选择“带我去”)。
  4. 点击地图上的公交车站
  5. 点击到站时间旁边的3个点“更多”按钮(或在滑动面板中的列表中点击到站时间)
  6. 点击选项“在地图上显示路线”
  7. 在路线加载到地图上后,将设备方向更改为横屏。
  8. 观察地图重新加载后标记的跳动

LG G4完整视频捕捉,展示了生产和发布的新步骤:https://youtu.be/oiBoMTPDVrU


1
你尝试过在地图上调用clear方法而不是对每个标记调用remove吗? - greywolf82
1
我避免使用GoogleMap.clear(),因为这会导致闪烁。当地图移动时,应用程序使用边界框视图向服务器发送请求,并获取位于该边界框内的公交车站。我在内部有一个HashMap来跟踪已经添加到地图上的站点,所以我只添加新的站点。最初,我尝试调用.clear()并重新添加所有站点,但这会产生严重的闪烁。此外,我还有其他标记在地图上,我不想清除它们。目前,当超过阈值时,我对所有标记调用Marker.remove(),然后重新开始。 - Sean Barbeau
1个回答

4
我认为这与同时存在多个SupportMapFragment实例有关。在v2.0.6中,当Activity被销毁并重新创建时,我没有正确处理片段(即在Activity在后台运行一段时间后被杀死或方向改变时)。在v2.0.6中,我的代码大致如下:
public class HomeActivity ...{

    BaseMapFragment mMapFragment;

    ...

    private void showMap() {
        FragmentManager fm = getSupportFragmentManager();
        if (mMapFragment == null) {
                mMapFragment = BaseMapFragment.newInstance();
                fm.beginTransaction()
                    .add(R.id.main_fragment_container, mMapFragment)
                    .commit();
        }
    }
    ...
}

所以,在这些情况下,我泄漏了一个BaseMapFragment的实例(它扩展了SupportMapFragment) - 在FragmentManager中已经存在一个实例,但我没有本地引用它。当我类似处理另一个片段时,我实际上注意到了这个问题,操作栏菜单项被复制了。

我将代码更改为以下内容,首先检查FragmentManager是否有现有的BaseMapFragment

public class HomeActivity ...{

    BaseMapFragment mMapFragment;

    ...

    private void showMap() {
        FragmentManager fm = getSupportFragmentManager();            
        // First check to see if an instance of BaseMapFragment already exists            
        mMapFragment = (BaseMapFragment) fm.findFragmentByTag(BaseMapFragment.TAG);

        if (mMapFragment == null) {
            mMapFragment = BaseMapFragment.newInstance();
            fm.beginTransaction()
                    .add(R.id.main_fragment_container, mMapFragment, BaseMapFragment.TAG)
                    .commit();
        }
    }
    ...
}

UI流程在主分支中已更改(不再打开新的Activity查看路线),因此我无法直接测试此代码更改后问题是否仍然可重现。但是,我创建了此分支,该分支从主分支分支出来,但更改为具有与v2.0.6相同的UI流程,并包括上述修复片段泄漏的内容。

https://github.com/CUTR-at-USF/onebusaway-android/tree/jumpingMarkersTest

通过对这个分支进行一些快速测试,似乎在方向改变时正确处理片段(即不泄漏片段)可能已经解决了跳跃标记的问题 - 至少使用上述步骤,在安卓5.1的LG G4上不再重现。


2
我遇到了完全相同的问题。通过以上建议修复碎片,也修复了跳动标记。 - Herve Thu
我没有泄漏片段实例的问题。但我遇到了这个跳转标记问题,有人能帮忙吗? - ABDUL RAHMAN

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接