moagrius / TileView

TileView is a subclass of android.view.ViewGroup that asynchronously displays, pans and zooms tile-based images. Plugins are available for features like markers, hotspots, and path drawing.
MIT License
1.46k stars 337 forks source link

Tiles disappear on pan change #452

Closed drshavit closed 6 years ago

drshavit commented 6 years ago

Hi,

First of all, thank you for your efforts on this project, it has helped me a lot on my recent assignments.

I am trying to create a map with two detail levels: 1 - 5 columns over 4 rows, 256x256 pixels each. Total image size is (1280,1024). 2 - 10 columns over 8 rows, 256x256 pixels each. Total image size is (2560,2048).

The Bitmaps are stored in mapData, an object that contains a HashMap of detail level -> list of tile objects. each tile object contains vertical location, horizontal location and the actual bitmap (decoded from Base64 String). vertical and horizontal locations start from (1,1).

From what I could understand from the documentation, detail level 1f is the most zoomed-in. So I am using the following definitions:

map.setBitmapProvider(new BitmapProviderMap());
map.setSize(2560, 2048);
map.addDetailLevel(1f, mapData.getImagesPerDetailLevel(2), mapData.getTileWidth(2), mapData.getTileHeight(2));
map.addDetailLevel(0.5f, mapData.getImagesPerDetailLevel(1), mapData.getTileWidth(1), 
mapData.getTileHeight(1));
map.setShouldRenderWhilePanning(true);
map.setShouldScaleToFit(true);
map.setScaleLimits(0, 1);
map.setScale(0);

Since detail level 1 is exactly twice as small as detail level 2, I assigned detail scale 0.5f to it. I hope that is the correct value for it..

My BitmapProvider implementation:

private class BitmapProviderMap implements BitmapProvider
    {
        @Override
        public Bitmap getBitmap(Tile tile, Context context)
        {
            return mapData.getTileImage(tile.getDetailLevel().getScale(), tile.getRow() + 1, tile.getColumn() + 1);
        }
    }

I am experiencing two issues: 1) On load, even though I setScale(0), getBitmap is requesting only 1f scale images. I see the images from detail level 2, which is not what I expect to see completely zoomed out. getBitmap never requests for 0.5f scale images, no matter what I do. 2) After the map is loaded, whenever I zoom or pan, the area that is no longer visible is not re-rendered when it should be visible again. I added some debugs to getBitmap, and I can see that the same Bitmap object that was originally fetched on load is returned from mapData.getTileImage, but for some reason, the area is grey. After enough pans and zooms, the entire map is gone.

I am probably doing something wrong that is causing these issues, I have tried setting many other definitions for the TileView object, but I feel like I'm going around in circles.

Thank you

moagrius commented 6 years ago

Can you post your project somewhere public?

drshavit commented 6 years ago

I knew I was at fault. The Bitmap is being recycled after it leaves the FOV. Because it is saved in an object, the Bitmap instance itself is being recycled. When it is called again, the recycled image is returned, and is obviously empty.

The way it was generated before:

byte[] imageAsByteArray = Base64.decode(image, Base64.DEFAULT);
imageBitmap = BitmapFactory.decodeByteArray(imageAsByteArray, 0, imageAsByteArray.length);

and the getter for the image: return imageBitmap causing the same Bitmap to be returned.

The code that now works: imageAsByteArray = Base64.decode(image, Base64.DEFAULT);

and the getter for the image: return BitmapFactory.decodeByteArray(imageAsByteArray, 0, imageAsByteArray.length); So the byte array is saved as property, and a new Bitmap is created every time the getter is called.

As for the fact that the second layer was not called, I messed around with the definitions and it's all working great now.

Thank you!