如何在没有闪烁的情况下更新TileOverlay?

时间:2013-01-19 00:27:24

标签: android google-maps-android-api-2

我有一些动态图块内容显示在地图上(特别是天气图像 - 雷达,卫星,温度等)。我正在使用Google Maps API for Android v2。

我遇到的问题显然是更新磁贴图像的唯一方法(即当新数据到达时,或者帧在时间推移动画中前进时)是调用TileOverlay.clearImageCache。不幸的是,当我这样做时,瓷砖覆盖层会闪烁一会儿。这是因为clearImageCache会立即从显示中删除现有的图块图像,但在解码和显示新的图块图像之前会有一段延迟。

我正在使用自定义TileProvider来缓存切片图像,而不是每次都从服务器中获取它们。但即使它只提供缓存的磁贴(即我的TileProvider.getTile实现没有明显的延迟),用户仍然可以看到闪烁的延迟。

有谁知道避免这种闪烁的方法?有什么方法可以双重缓冲瓷砖覆盖?我尝试使用附加到地图的两个TileOverlay对其进行双缓冲,其中一个是不可见的。但是,即使在我调用clearImageCache之后,看不见的TileOverlay也没有开始从我的TileProvider中获取任何图块。

4 个答案:

答案 0 :(得分:1)

是否可以加载即将发布的图块但是可见性设置为false? Tile.setVisible(false);

然后当您想要更改时(在即将加载的图块之后),将即将显示的图块设置为可见并且当前图块是不可见的?

CurrentTile.setVisible(false);
NewTile.setVisible(true);

这种方式更改都发生在同一个渲染帧中,并且没有延迟等待缓存的图像加载。

答案 1 :(得分:0)

一个相当不错的解决方案是将磁贴下载和缓存从TileProvider中分离出来。通过这种方式,您可以完全控制何时下载它们,并且仅在下载所有内容后替换byte []引用。

这可能有点复杂,因为你必须处理当前的可见区域并放大而不是全部下载它们,而只是那些可见的区域。

修改

使用以下代码进行测试:

try {
    InputStream is = getAssets().open("tile1.jpg");
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    int b = is.read();
    while (b != -1) {
        baos.write(b);
        b = is.read();
    }
    byte[] array = baos.toByteArray();
    cache = new Tile(256, 256, array);
    is = getAssets().open("tile2.jpg");
    baos = new ByteArrayOutputStream();
    b = is.read();
    while (b != -1) {
        baos.write(b);
        b = is.read();
    }
    array = baos.toByteArray();
    nextCache = new Tile(256, 256, array);
} catch (IOException ex) {
    Log.e("tag", "error reading tiles", ex);
}

tileOverlay = map.addTileOverlay(new TileOverlayOptions().tileProvider(new TileProvider() {
    @Override
    public Tile getTile(int x, int y, int zoom) {
        return cache;
    }
}));

以后某个地方:

Tile temp = cache;
cache = nextCache;
nextCache = temp;
tileOverlay.clearTileCache();

“最快”的可能代码仍然失败。

如果您无法切换到GroundOverlay或Markers,另一个想法是尝试使用第三方地图图块,您当前的天气图块上方和下方的图块,以便他们可以在几秒钟后加载并切换它们(使用zOrder)。

答案 2 :(得分:0)

为此,我找到的解决方案是使图层的透明度为1。这使它们隐藏但仍在请求拼贴。然后,您可以切换透明度为1和0的图层。

由于在两层透明度的更改之间进行了一次渲染调用,因此仍有一些闪烁的可能性。没有办法使它成为原子操作。

还发现,没有什么好方法可以知道图层何时完全加载了图块。即使您从TileProvider返回了图块,Google Maps也必须对其进行一些处理,因此在切换图块之前您需要一些延迟。

答案 3 :(得分:0)

对我有用的解决方案(我尝试每秒刷新瓷砖):

    // Adding "invisible" overlay
    val newTileOverlay =  mMap?.addTileOverlay(
        TileOverlayOptions()
            .tileProvider(getTileProvider()).transparency(1f).visible(true)
    )

    mTileOverlay?.transparency = 0.5f // making previous overlay visible
    mOldTileOverlay?.remove() // removing previously displayed visible overlay
    mOldTileOverlay = mTileOverlay
    mTileOverlay = newTileOverlay

所以我们一次有两层(一层可见,一层不可见)。我不确定它如何影响性能。