Rozwiązanie dla aplikacji mapowej na Androida w trybie offline?

14

Szukam sposobu na opracowanie aplikacji dla Androida z wbudowanymi mapami, które mogą działać bez połączenia z Internetem (tj. Czy mogę uzyskać kafelki otwartej mapy do użytku offline?).

Już wcześniej tworzyłem aplikacje internetowe za pomocą Google Maps API v3. Potrzebuję ogólnej odpowiedzi jako konkretnej. Próbuję znaleźć koncepcje i technologie, których muszę się nauczyć :)

(Tymczasem znalazłem osmdroid. Czy działa w trybie offline?)

Argiropoulos Stavros
źródło
To tak naprawdę nie odpowiada na pytanie. Jeśli masz inne pytanie, możesz je zadać, klikając Zadaj pytanie . Możesz także dodać nagrodę za zwrócenie większej uwagi na to pytanie, gdy będziesz mieć wystarczającą reputację .
Jason Scheirer
Osmand nie pozwala importować żadnych niestandardowych map na życzenie użytkownika, ale pozwala tylko pobierać mapy bezpośrednio z aplikacji do użytku offline. Podobnie jak w moim przypadku, muszę nakładać arkusze górne (mapy rastrowe), które zostały przekonwertowane na * .kmz. Moje wymaganie dotyczy użycia offline. Szukam odpowiednich wskazówek, aby opracować taką aplikację do obsługi map offline na Androida.
surap
To tak naprawdę nie odpowiada na pierwotne pytanie o to, gdzie i jak uzyskać mapy do użytku offline.
MaryBeth
To tak naprawdę nie odpowiada na pytanie. Jeśli masz inne pytanie, możesz je zadać, klikając Zadaj pytanie . Możesz także dodać nagrodę za zwrócenie większej uwagi na to pytanie, gdy będziesz mieć wystarczającą reputację . - Z recenzji
John Powell,

Odpowiedzi:

13

Zrobiłem mapę offline przy użyciu ESRI Android SDK i niestandardowej warstwy kafelków. Użyłem serwera ArcGIS do wygenerowania pamięci podręcznej mapy opartej na kafelkach, a następnie umieściłem te kafelki w bazie danych SQLite i stamtąd przeszukiwałem je na podstawie wiersza i kolumny. Działa świetnie, a jeśli potrzebujesz niestandardowych map od końca do końca, jest to bardzo użyteczna metoda.

package com.main.utilinspect;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.List;

import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParser;

import android.content.Context;
import android.util.Log;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.esri.core.internal.c.d;
import com.esri.core.internal.c.h;
import com.esri.core.internal.c.l;

import com.esri.android.map.TiledServiceLayer;

public class OfflineDbTiledLayer extends TiledServiceLayer {

File workingDirectory;
String mapDefinition;
String databaseName;
private SQLiteDatabase database;
File blankImage;

byte[] blankImageBytes;

private final Object lock = new Object();


private static final String TAG = "OfflineTiledLayer";  


public OfflineDbTiledLayer(Context paramContext, File workingDirectory, String mapDefinition, String databaseName)  {
    super("required");
    this.workingDirectory = workingDirectory;
    this.mapDefinition = mapDefinition;
    this.databaseName = databaseName;

    String databasePath = workingDirectory.getAbsolutePath() + File.separator + databaseName;

    this.database = SQLiteDatabase.openDatabase(databasePath, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS); 

    this.blankImage = new File(workingDirectory.getAbsolutePath() + File.separator + "blank.png");

    RandomAccessFile raFile = null;

    try {
        raFile = new RandomAccessFile(this.blankImage, "r");

        blankImageBytes = new byte[(int) raFile.length()];
        raFile.readFully(blankImageBytes);

    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }       
    finally {
        if(raFile != null) {
            try {
                raFile.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }   

    h h1 = null;

    try
    {

    JsonParser paramJsonParser = new JsonFactory()
    .createJsonParser(new File(workingDirectory.getAbsolutePath() + File.separator + mapDefinition));
    paramJsonParser.nextToken();    

    h1 = h.a(paramJsonParser, "test");
    }
    catch(Exception ex){

    }       


    setFullExtent(h1.f());      
    setDefaultSpatialReference(h1.c());
    setInitialExtent(h1.e());

    l l1;
    List list;
    int i;
    double ad[] = new double[i = (list = (l1 = h1.d()).h).size()];
    double ad1[] = new double[i];
    for(int j = 0; j < list.size(); j++)
    {
        ad[j] = ((d)list.get(j)).b();
        ad1[j] = ((d)list.get(j)).a();
    }

    setTileInfo(new com.esri.android.map.TiledServiceLayer.TileInfo(l1.f, ad, ad1, i, l1.c, l1.b, l1.a));

    super.initLayer();
    return;     
}   

private void openDatabase(){
    if(!database.isOpen()){
        String databasePath = workingDirectory.getAbsolutePath() + File.separator + databaseName;
        this.database = SQLiteDatabase.openDatabase(databasePath, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS); 
    }
}

private void closeDatabase(){
    if(database.isOpen()){
        this.database.close();
    }
}

@Override
protected byte[] getTile(int level, int column, int row) throws Exception {
    byte[] tileImage;       

    Log.i(TAG, "getTile");

    Log.i(TAG, "getTile - retrieving tile");            

    synchronized(lock) {

        Log.i(TAG, "getTile - entered synchronized block");

        openDatabase();     

        // First check to see if the tile exists in the database
        Cursor tileCursor = database.rawQuery("SELECT image FROM tiles WHERE level = " + Integer.toString(level) + " AND row = " + Integer.toString(row) + " AND column = " + Integer.toString(column), null);

        if(tileCursor != null && tileCursor.getCount() > 0) {
            tileCursor.moveToFirst();
            tileImage = tileCursor.getBlob(0);
            Log.i(TAG, "getTile - tile found, returning image");                        
        }
        else {
            // The tile does not exist in the database, read the blank placeholder tile and serve it
            tileImage = blankImageBytes;
            Log.i(TAG, "getTile - tile not found returning blank");
        }   

        tileCursor.close();     
        this.database.close();
    }

    Log.i(TAG, "getTile - exited synchronized block");

    return tileImage;   
}

}

eptiliom
źródło
Czy możesz podać trochę kodu?
gregm
Dodałem swoją niestandardową klasę warstw, która działa.
eptiliom
7

Opracowałem aplikację z mapami offline dla Androida. Jedynym darmowym narzędziem, którego chcesz użyć, jest OSMDroid, w przeciwnym razie ESRI. OSMDroid API jest identyczny z Google, więc jeśli chcesz przełączać się między nimi, to pestka.

Sprawdź ten post , przedstawiając przykład integracji Google Maps z OSMDroid (daje także ogólne wyobrażenie o tym, jak z niego korzystać).

Elijah Saounkine
źródło
2

Istnieje świetna aplikacja o nazwie xGPS na iPhone'a i inne urządzenia. Możesz na to spojrzeć, aby uzyskać pomysły, ponieważ pozwala użytkownikom wstępnie buforować potrzebne mapy. Używam go, gdy jestem głęboko w buszu w Afryce, na Everglades na Florydzie, na łodziach lub gdziekolwiek nie mam zasięgu telefonu komórkowego. Będę buforować mapy przed podróżą, a następnie będę mógł normalnie korzystać z GPS na moim iPhonie BEZ INTERNETU.

Zasadniczo to, co robi xGPS i co chcesz zrobić, to buforować kafelki mapy lokalnie w telefonie. Miejsce na tych telefonach komórkowych jest ograniczone. Tak, nawet jeśli masz 32 GB telefonu, może to być wystarczające do buforowania małego kraju na wszystkich poziomach powiększenia (skalach). Żaden z tych telefonów (chyba że w jakiś sposób jest podłączony do pamięci zewnętrznej) nie będzie miał wystarczająco dużo miejsca, aby buforować świat na wszystkich poziomach powiększenia. Wyobrażam sobie, że wymagałoby to przechowywania petabajtów.

Musisz więc mieć możliwość poproszenia użytkownika o buforowanie „regionów” lub map, gdy jest online, aby mógł z nich korzystać offline. Dzięki xGPS jestem w stanie narysować wielokąt nad moim obszarem zainteresowania i określić, jakie poziomy powiększenia chcę buforować. Następnie zacznie pobierać wszystko dla mnie na mój telefon, albo z samego telefonu, albo z programu na moim komputerze. Następnie w aplikacji jest przycisk, który pozwala mi przejść do trybu „offline”, gdy tracę połączenie z Internetem.

CaptDragon
źródło
2

Spróbuj użyć pakietu NextGIS Mobile SDK. Tryb online / offline obejmuje edycję i automatyczną synchronizację z serwerem (NextGIS Web). Warstwy rastrowe i wektorowe, niestandardowe formularze wprowadzania, obsługa wszystkich typów geometrii.

Przykładową aplikację NextGIS Mobile można znaleźć w sklepie Google Play - https://play.google.com/store/apps/details?id=com.nextgis.mobile

Źródła są tutaj: https://github.com/nextgis/android_gisapp

Dokumentacja: http://docs.nextgis.com/docs_ngmobile/source/toc.html

Kolejna prosta aplikacja znajduje się tutaj: https://github.com/nextgis/android_muni_gisconf

Dokumentacja zestawu SDK: http://docs.nextgis.com/ngmobile_dev/toc.html

Dmitrij Barysznikow
źródło
1

Pełna wersja map offline jest dostępna w bieżącej wersji ArcGIS Android SDK. W tym przykładzie pokazano, jak pracować z lokalnym pakietem kafelków jako mapą podstawową i zachować funkcje online do funkcji offline, z których można edytować. Mam sens dostępne na github oraz uproszczoną odniesienia.

jdONeill
źródło
1

Proponuję rzucić okiem na Nutiteq 3D SDK do map, który ma funkcje offline i ciekawe dodatki, takie jak obsługa 3D. Jest produkowany przez wyspecjalizowaną firmę deweloperską, więc ma dedykowane wsparcie komercyjne i większą elastyczność niż duzi dostawcy. Oświadczenie: Jestem deweloperem.

JaakL
źródło