TileProvider с использованием локальной плитки

Я хотел бы использовать новую функциональность TileProvider последнего API Android Maps (v2), чтобы наложить некоторые пользовательские плитки на GoogleMap . Однако, поскольку мои пользователи не будут иметь интернет в течение некоторого времени, я хочу сохранить плитки, хранящиеся в структуре zipfile / folder на устройстве. Я буду генерировать свои плитки, используя Maptiler с geotiffs . Мои вопросы:

  1. Каким будет лучший способ хранить плитки на устройстве?
  2. Как я могу создать TileProvider, который возвращает локальные fragmentы?

  1. Вы можете поместить плитки в папку с ресурсами (если это приемлемо для размера приложения) или загрузить их все при первом запуске и поместить их в хранилище устройств (SD-карту).

  2. Вы можете реализовать TileProvider следующим образом:


 public class CustomMapTileProvider implements TileProvider { private static final int TILE_WIDTH = 256; private static final int TILE_HEIGHT = 256; private static final int BUFFER_SIZE = 16 * 1024; private AssetManager mAssets; public CustomMapTileProvider(AssetManager assets) { mAssets = assets; } @Override public Tile getTile(int x, int y, int zoom) { byte[] image = readTileImage(x, y, zoom); return image == null ? null : new Tile(TILE_WIDTH, TILE_HEIGHT, image); } private byte[] readTileImage(int x, int y, int zoom) { InputStream in = null; ByteArrayOutputStream buffer = null; try { in = mAssets.open(getTileFilename(x, y, zoom)); 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 e) { e.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) {} } } private String getTileFilename(int x, int y, int zoom) { return "map/" + zoom + '/' + x + '/' + y + ".png"; } } 

И теперь вы можете использовать его с вашим экземпляром GoogleMap:

 private void setUpMap() { mMap.setMapType(GoogleMap.MAP_TYPE_NONE); mMap.addTileOverlay(new TileOverlayOptions().tileProvider(new CustomMapTileProvider(getResources().getAssets()))); CameraUpdate upd = CameraUpdateFactory.newLatLngZoom(new LatLng(LAT, LON), ZOOM); mMap.moveCamera(upd); } 

В моем случае у меня также возникла проблема с координатой y из плиток, сгенерированной MapTiler, но мне это удалось, добавив этот метод в CustomMapTileProvider:

 /** * Fixing tile's y index (reversing order) */ private int fixYCoordinate(int y, int zoom) { int size = 1 << zoom; // size = 2^zoom return size - 1 - y; } 

и вызвать его из метода getTile () следующим образом:

 @Override public Tile getTile(int x, int y, int zoom) { y = fixYCoordinate(y, zoom); ... } 

[Обно]

Если вы знаете область exac вашей пользовательской карты, вы должны вернуть NO_TILE для отсутствия fragmentов из getTile(...) .

Вот как я это сделал:

 private static final SparseArray TILE_ZOOMS = new SparseArray() {{ put(8, new Rect(135, 180, 135, 181 )); put(9, new Rect(270, 361, 271, 363 )); put(10, new Rect(541, 723, 543, 726 )); put(11, new Rect(1082, 1447, 1086, 1452)); put(12, new Rect(2165, 2894, 2172, 2905)); put(13, new Rect(4330, 5789, 4345, 5810)); put(14, new Rect(8661, 11578, 8691, 11621)); }}; @Override public Tile getTile(int x, int y, int zoom) { y = fixYCoordinate(y, zoom); if (hasTile(x, y, zoom)) { byte[] image = readTileImage(x, y, zoom); return image == null ? null : new Tile(TILE_WIDTH, TILE_HEIGHT, image); } else { return NO_TILE; } } private boolean hasTile(int x, int y, int zoom) { Rect b = TILE_ZOOMS.get(zoom); return b == null ? false : (b.left <= x && x <= b.right && b.top <= y && y <= b.bottom); } 

Возможность добавления пользовательских tileproviders в новый API (v2) замечательна, однако вы отмечаете, что ваши пользователи в основном офлайн. Если пользователь отключен при первом запуске приложения, вы не можете использовать новый API, поскольку он требует, чтобы пользователь был в сети (по крайней мере, один раз, чтобы создать кеш, похоже), иначе он будет отображать только черный экран.

EDIT 2 / 22-14: Недавно я снова столкнулся с тем же вопросом – с пользовательскими плитками для приложения, которое должно было работать в автономном режиме. Выбрал его, добавив невидимый (w / h 0/0) mapview в исходное представление, где клиенту пришлось загрузить некоторый контент. Кажется, что это работает и позволяет мне использовать карту в автономном режиме позже.

  • Как открыть другое действие для элемента recyclerView onclick
  • Как сделать мою прикладную систему
  • Узнайте, прокручивается ли ListView до конца?
  • Как получить доступ к дочерним представлениям fragmentа внутри родительской активности fragmentа?
  • Ваш путь к проекту содержит символы, отличные от ASCII, android studio
  • Как управлять кнопкой возврата в действии
  • Почему получение Google Directions для Android с использованием данных KML больше не работает?
  • Языковые ограничения для Android Lint для проверки отсутствующих переводов
  • Как я могу вернуться к родительской активности правильно?
  • Как я могу получить список смонтированного внешнего хранилища Android-устройства
  • Как обрабатывать сообщения обработчика, когда действие / fragment приостановлено
  • Давайте будем гением компьютера.