문제

I recently optimized my TileProvider code for an offline map tiling and I have a new problem where getTile may not be called for up to a minute--and occasionally never--after loading the map or following a CameraChange.

I initialize the TileProvider this way (this is in setUpMap(), onResume(), and within a function that I call if I reset the map or if my offline map's on/off setting is changed):

if (mapsOn()) customOverlay = mMap.addTileOverlay(new TileOverlayOptions().tileProvider
            (new MyTileProvider())); 

(I save as customOverlay so that I can call customOverlay.clearTileCache() in onStop() because otherwise I seem to have memory problems.)

And my TileProvider, following the example here, modified to fetch tiles from a zipfile:

public class MyTileProvider implements TileProvider {
    private final int TILE_WIDTH = 256;
    private final int TILE_HEIGHT = 256;
    private static final int BUFFER_SIZE = 16 * 1024;
    private String pathToZipFile = MyConstants.TILE_PROVIDER_PATH_PREFIX;
    private ZipResourceFile zipFile;
    private String currentPath;

    public MyTileProvider()  {
    }

    public Tile getTile(int x, int y, int zoom)  {  
//debug code here shows this is not getting called when the maps are not loading. 
//How do I force it to be called?
        byte[] image = readTileImage(x, y, zoom);
        return image == null ? NO_TILE : new Tile (TILE_WIDTH, TILE_HEIGHT, image);
    }

    private byte[] readTileImage(int x, int y, int zoom)  {
        InputStream in = null;
        ByteArrayOutputStream buffer = null;

        if (zipFile==null) initializeZipFile(x, zoom);

        try {
            in = zipFile.getInputStream(zoom+"/"+x+"/"+y+".png");
            buffer = new ByteArrayOutputStream();
            int nRead;
            byte[] data = new byte[BUFFER_SIZE];

            while ((nRead = in.read(data, 0, BUFFER_SIZE)) != -1) {
                buffer.write(data, 0, nRead);
            }                
            buffer.flush();
            return buffer.toByteArray();

        } catch (IOException e1) {      
            e1.printStackTrace();
            return null;
        } catch (OutOfMemoryError e)  {
            e.printStackTrace();
            return null;
        } finally  {
            if (in!=null) try { in.close(); } catch (Exception ignored)  {}
            if (buffer != null)  try { buffer.close();  } catch (Exception ignored) {}
        }       
    }

    public void initializeZipFile(int x, int zoom)  {       
            //code to choose the correct zip file based upon the zoom level and x coordinate
    }
}
도움이 되었습니까?

해결책 2

I think there is a logical and a technical flaw in your code:

The logical one:
You are using one variable zipFile although you have different files depending on the x and zoom parameter. So even in case zipFile != null, it may contain the wrong content.

If you have e.g. loaded the file for lets say x=1 and zoom=1, you will continue to use this file, even if zoom changed to 2. So just checking for null is not sufficient.

The technical one:
TileProvider must be threadsafe. This is not the case in your coding. You may just add a synchronized to your readTileImage method. But this will probably slow down the whole loading process and it still would not work without resetting the stream each time readTileImage is called. So the "caching" of the stream is not of much help. I think the way you organize the tiles, by having all y-coordinates for the same x and zoom level in the same file makes things that complicated. The map will try to load tiles for different x and y values in parallel. I do not see, how this can be accomplished using the same stream. I would keep a separate file for each x, y, and zoom triple.

다른 팁

Use the "@Override" declaration!

  @Override
    public Tile getTile(int x, int y, int zoom) {...}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top