2013-12-06 4 views
7

Я хочу использовать Spatialite вместо простого SQLite с Xamarin на Android, чтобы управлять и отображать географические данные. Встроенный SQLite не позволяет загружать расширения. Как мне это сделать?Как использовать Spatialite с Xamarin на Android

ответ

9

Короткий ответ: вам нужно использовать собственный настраиваемый SQLite в качестве базовой библиотеки Android, как и в других библиотеках NDK. Сложная часть состоит в том, чтобы получить полезный не такой тривиальный C# API для базы данных. Документы Xamarin, похоже, имеют руководства только для простых простых API-интерфейсов.

Как я уже привык к Java, чем .Net, тогда я использовал комбинацию Android Java library (.jar) и родной библиотеки Android (.so). В библиотеке Android Java уже есть оболочка Java API для базы данных, это точно такая же оболочка, которая может использоваться в обычных приложениях Java Java. Разумеется, также возможен технически прямой доступ к родной библиотеке из C#, поэтому java/jar можно исключить из истории. Если вы знаете хорошие инструменты для этого, дайте мне знать.

  1. Создать .jar проект связывания для Xamarin, добавьте его к тому же решению, как ваш Android проект
  2. Добавить jsqlite.jar в папку Фляг из привязок проекта. Получите это отсюда:
  3. Добавьте собственные библиотеки двоичных файлов (libjsqlite.so и libproj.so) в приложение , создайте папку libs/armeabi для этого. Получите их от Nutiteq AdvancedMap3D project
  4. Определите файлы .so как AndroidNativeLibrary и установите Копировать в каталог вывода
  5. Исправьте определения привязки, чтобы удалить ошибки сборки. Добавьте следующее Transforms/Metadata.xml вашего проекта привязок:
<remove-node path="/api/package[@name='jsqlite']/class[@name='Backup']/field[@name='handle']" /> 
<remove-node path="/api/package[@name='jsqlite']/class[@name='Database']/field[@name='handle']"/> 
<attr path="/api/package[@name='jsqlite']" name="managedName">jsqlite</attr> 

Это должно генерировать вы работаете C# API для комплектного SQLite, вместе с SpatiaLite, proj.4 и GEOS включены. Сам API DB jsqlite отличается от других API-интерфейсов C# SQLite, вам нужно использовать классы обратного вызова. См следующие примеры Для проверки версий модулей:

try { 
    db.Open ("/sdcard/mapxt/estonia-latest-map.sqlite", Constants.SqliteOpenReadonly); 
    // show versions to verify that modules are there 
    db.Exec ("SELECT spatialite_version(), proj4_version(), geos_version(), sqlite_version()", new GeneralQryResult()); 
} catch (jsqlite.Exception ex) { 
    Log.Error(ex.LocalizedMessage); 
} 

... 

// prints query results as text 
public class GeneralQryResult : Java.Lang.Object, ICallback 
{ 

    public bool Newrow (string[] rowdata) 
    { 
     string row = ""; 
     foreach (var data in rowdata) { 
      row += data + " | "; 
     } 

     Log.Info(row); 
     return false; 
    } 

    public void Types (string[] types) 
    { 
     // never called really 
    } 

    public void Columns (string[] cols){ 
     Log.Debug ("Query result:"); 
     string row = ""; 
     foreach (var col in cols) { 
      row += col + " | "; 
     } 
     Log.Info (row); 
    } 
} 

Наконец теперь запрос реальных пространственных данных, используя Nutiteq 3D Maps SDK for Xamarin визуализировать его:

// Spatialite query, show results on map 
// 1. create style and layer for data 

LineStyle.Builder lineStyleBuilder = new LineStyle.Builder(); 
lineStyleBuilder.SetColor (NutiteqComponents.Color.Argb(0xff, 0x5C, 0x40, 0x33)); //brown 
lineStyleBuilder.SetWidth (0.05f); 
LineStyle lineStyle = lineStyleBuilder.Build(); 

GeometryLayer geomLayer = new GeometryLayer (view.Layers.BaseLayer.Projection); 
view.Layers.AddLayer (geomLayer); 

// 2. do the query, pass results to the layer 
Database db = new Database(); 

try { 
    db.Open ("/sdcard/mapxt/estonia-latest-map.sqlite", Constants.SqliteOpenReadonly); 

    // spatial query. Limit to 1000 objects to avoid layer overloading 
    String qry = "SELECT id, HEX(AsBinary(Transform(geometry,3857))), sub_type, name FROM ln_railway LIMIT 1000"; 
    db.Exec (qry, new SpatialQryResult (geomLayer, lineStyle)); 
} catch (jsqlite.Exception ex) { 
    Log.Error(ex.LocalizedMessage); 
} 

... 

// adds query results to given layer, with given style 
public class SpatialQryResult : Java.Lang.Object, ICallback 
{ 

    GeometryLayer _geomLayer; 
    Style _geomStyle; 

    public SpatialQryResult(GeometryLayer geomLayer, Style geomStyle){ 
     _geomLayer = geomLayer; 
     _geomStyle = geomStyle; 
    } 

    public bool Newrow (string[] rowdata) 
    { 

     string id = rowdata [0]; 
     string geomHex = rowdata [1]; 
     string type = rowdata [2]; 
     string name = rowdata [3]; 

     Label label; 
     if (name != null && name.Length > 1) { 
      label = new DefaultLabel (name, type); 
     } else { 
      label = null; 
     } 

     Geometry[] lineGeoms = WkbRead.ReadWkb(new ByteArrayInputStream(Utils 
      .HexStringToByteArray(geomHex)), rowdata); 

     // following fails if not Line, change for other geometries 
     foreach (Line lineGeom in lineGeoms) { 
      _geomLayer.Add(new Line(lineGeom.VertexList, label, (LineStyle)_geomStyle, _geomLayer)); 
     } 

     return false; 
    } 
} 
Смежные вопросы