来自:http://blog.csdn.net/arcgis_mobile/article/details/7565877

ArcGIS for Android中现已经提供了离线缓存图片的加载功能,极大的提高了我们访问地图的效率,对于离线的数据编辑暂时还不支持,而现在对于离线数据编辑操作的需求越来越多,那我们如何才能实现离线数据编辑功能呢?下面我们介绍一下,通过sqlite来实现离线数据编辑的解决方案。

    一、离线数据编辑解决方案

离线编辑无非就是将所需的数据下载到我们的手持端进行存储,当无法连接网络时,数据的读取、显示、编辑、保存都是通过本地数据库完成的;而后,当可以连接网络时,再将编辑的数据从手持端的数据库中提取出来进行在线数据提交。

    二、离线数据编辑实现步骤

根据上面的流程图我们来分析一下,实现离线数据编辑的步骤:

1、 通过ArcGIS Server来发布一个FeatureService服务用于数据下载或上传;

2、 手持端编写通过服务请求业务数据的代码;

在手持端编写下载数据的代码,通过FeatureService服务进行数据的下载,代码如下:

Query query = new Query();

query.setOutFields(new String[] {"*" });                 query.setInSpatialReference(featureLayer.getSpatialReference());

query.setWhere("objectid in ("+where+")");

flayer.selectFeatures(query, ArcGISFeatureLayer.SELECTION_METHOD.NEW,new CallbackListener<FeatureSet>() {

publicvoid onError(Throwable e) {

}

publicvoid onCallback(FeatureSet queryResults) {

}

});

3、 在手持端创建数据库和业务数据表;

在手持端中,我们需要数据库来存储业务数据,因此我们需要创建Sqlite数据库和相应的业务表。

在创建数据库时,我们可以通过扩展Android的帮助类SQLiteOpenHelper来维护和操作数据库和表,创建的表要与我们下载的业务数据的表结构一致。

public class DatabaseHelper extends SQLiteOpenHelper {

public static final String SYSTEM_TABLE = "sqlite_master";

private static final int VERSION=1;

public static final String TABLEORFIELDS =  "tableOrfields";

public static final String TABLENAME = "Environment";

public DatabaseHelper(Context context, String name, CursorFactory factory,

int version) {

super(context, name, factory, version);

// TODO Auto-generated constructor stub

}

public DatabaseHelper(Context context, String name){

this( context,  name,VERSION);

}

public DatabaseHelper(Context context, String name,int version){

this(context,name,null,version);

}

@Override

public void onCreate(SQLiteDatabase db) {

//创建的表结构

String sql = "CREATE TABLE IF NOT EXISTS  "+TABLENAME+"(OBJECTID INTEGER,CODE INTEGER,省名 TEXT,县区名 TEXT,土地覆盖 TEXT, SHAPE TEXT, MARK INT) ";

db.execSQL(sql);

}

@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

// TODO Auto-generated method stub

}

}

4、 将下载的数据存储到创建的数据库中;

将第2步下载的要素数据,储存到事先创建好的数据库中,要素的属性我们可以直接存储到我们创建的表中,由于sqlite数据库不支持空间数据类型,因此对于要素的空间几何的存储成为要点,对此,我们可以将空间几何解析拼凑成定制的字符串进行存储,我们可以按照WKT格式拼字符串,如,点:point ( 10.05 10.28 ),线:linestring ((10.0510.28 , 20.95 20.89 )),面:polygon ((10 10, 10 20, 20 20, 20 15, 10 10))。

将空间几何对象转成WKT的核心代码如下:

/**

* 将几何对象生成wkt字符串

*/

public static String GeometryToWKT(Geometry geometry){

if(geometry ==null){

return null;

}

String geoStr = "";

Geometry.Type type = geometry.getType();

if("Point".equals(type.name())){

Point pt = (Point)geometry;

geoStr = type.name()+"("+pt.getX() +" "+pt.getY()+")";

}else if("Polygon".equals(type.name()) ||"Polyline".equals(type.name())){

MultiPath pg = (MultiPath)geometry;

geoStr = type.name()+"("+"";

int pathSize = pg.getPathCount();

for(int j=0;j<pathSize;j++){

String temp = "(";

int size = pg.getPathSize(j);

for(int i=0;i<size;i++){

Point pt = pg.getPoint(i);

temp +=pt.getX() +" "+pt.getY()+",";

}

temp = temp.substring(0, temp.length()-1)+")";

geoStr +=temp+",";

}

geoStr = geoStr.substring(0, geoStr.length()-1)+")";

}else if("Envelope".equals(type.name())){

Envelope env = (Envelope)geometry;

geoStr = type.name()+"("+ env.getXMin() +","+env.getYMin()+","+env.getXMax()+","+env.getYMax()+")";

}else if("MultiPoint".equals(type.name())){

}else{

geoStr = null;

}

return geoStr;

}

将查询的数据插入到sqlite的核心代码:

//数据批量插入

private void insertGraphics(Graphic[] gps){

//开启事务,使用事务为了提高数据操作的效率

db.beginTransaction();

for(Graphic gp : gps){

ContentValues values = new ContentValues();

String[] attributs = gp.getAttributeNames();

for(String att : attributs){

Object attStr = gp.getAttributeValue(att);

String temp = "";

if(attStr ==null){

}else{

temp = gp.getAttributeValue(att).toString();

}

values.put(att,temp );

}

Geometry gt = gp.getGeometry();

String wktStr = GeometryToWKT(gt);

values.put("shape",wktStr);                                                       values.put("mark", 0);

db.insert(DatabaseHelper.TABLENAME,null, values);

}

db.setTransactionSuccessful();//设置事务成功

db.endTransaction();//结束事务

插入数据时启用Sqlite的事务机制,可以提高批量插入数据的速度。

5、 离线状态时,查询手持端数据库中的数据在设备上展示;

当我们要显示数据时,可以将数据库的数据查询出来,将查询的每条记录生成空间要素对象属性,将我们上面拼凑的字符串反解析生成空间要素对象,也就是将WKT数据格式解析成为一个空间要素对象。

将WKT数据字符串解析成空间几何对象的核心代码:

/**

* 将wkt字符串拼成几何对象

*/

public static Geometry WKTToGeometry(String wkt){

Geometry geo = null;

if(wkt ==null || wkt ==""){

return null;

}

String headStr = wkt.substring(0, wkt.indexOf("("));

String temp = wkt.substring(wkt.indexOf("(")+1, wkt.lastIndexOf(")"));

if(headStr.equals("Point")){

String[] values = temp.split(" ");

geo = new Point(Double.valueOf(values[0]),Double.valueOf(values[1]));

}else if(headStr.equals("Polyline") || headStr.equals("Polygon")){

geo = parseWKT(temp,headStr);

}else if(headStr.equals("Envelope")){

String[] extents = temp.split(",");

geo = new Envelope(Double.valueOf(extents[0]),Double.valueOf(extents[1]),Double.valueOf(extents[2]),Double.valueOf(extents[3]));

}else if(headStr.equals("MultiPoint")){

}else{

return null;

}

return geo;

}

private static Geometry parseWKT(String multipath,String type){

String subMultipath = multipath.substring(1, multipath.length()-1);

String[] paths;

if(subMultipath.indexOf("),(") >=0 ){

paths = subMultipath.split("),(");//多个几何对象的字符串

}else{

paths = new String[]{subMultipath};

}

Point startPoint = null;

MultiPath path = null ;

if(type.equals("Polyline")){

path = new Polyline();

}else{

path = new Polygon();

}

for(int i=0;i<paths.length;i++){

String[] points = paths[i].split(",");

startPoint = null;

for(int j=0;j<points.length;j++){

String[] pointStr = points[j].split(" ");

if(startPoint ==null){

startPoint = new Point(Double.valueOf(pointStr[0]),Double.valueOf(pointStr[1]));

path.startPath(startPoint);

}else{

path.lineTo(new Point(Double.valueOf(pointStr[0]),Double.valueOf(pointStr[1])));

}

}

}

return path;

}

6、 在设备上编辑要素数据;

对于要素的编辑可以分为两方面,一方面是属性的编辑,另一方面是空间编辑,对于这两方面的操作,官方提供的例子中提供了类似的功能(AttributeEditor和GeometryEditor两个例子)。

1)属性编辑

对于属性修改无非就是对Graphic对象的中的属性进行修改, Graphic不能添加事件监听,所以不能像按钮一样,添加一个点击事件弹出该要素的相关信息,我们可以通过GraphicsLayer的getGraphicIDs(float x, float y,int tolerance)方法来获取要素及其要素的相关属性,可悲是Graphic中没提供修改属性的接口,只能新建一个Graphic对象并在他的构造方法中来添加更新后的属性或者是通过GraphicsLayer的updateGraphic(int id,Map<String,Object> attributes)的方法来更新Graphic的属性,并且将修改的要素属性更新到本地sqlite数据库中及其修改表中mark字段的状态。

2)空间编辑

对于Graphic对象我们不仅可以改变他的属性还可以修改它的空间位置信息,对于点、线、面的修改略有不同。

点修改时,直接更新Graphic的Geometry即可,不过Graphic没有提供修改Geometry的接口,我们只能通过GraphicsLayer的updateGraphic(int id,Geometry geometry)方法来实现更新它的空间位置。

线和面的空间位置改变主要指的是线或面的节点的位置修改,我们可以点击线或面上的一个节点进行拖动用GeometryEngine.getNearestVertex()可以得到我们点击的点,距离几何体的哪个节点最近,并返回一个Proximity2DResult对象,通过这个对象我们可以得到这个节点Index位置,再通过线或面对象的setPoint(int index,Point point)方法更新节点,这时我们的图形就可以改变了,将更新后的Graphic的空间对象重新解析成定义的格式入库及其修改表中mark字段的状态。

7、 将编辑后的数据更新到设备数据库中;

将编辑后的数据通过第4步的方式更新到本地数据库中,更新数据的代码如下:

SQLiteDatabase db = this.getWritableDatabase();

db.beginTransaction();

db.update(table, values, whereClause, whereArgs);

db.setTransactionSuccessful();

db.endTransaction();

如果要多次更新时,可以使用sqlite数据库的事务机制,来提高执行效率。

8、 在线时通过ArcGIS Server的服务提交业务数据;

通过sqlite查询,将本地数据库中的数据查询出来,并将数据拼成空间要素对象,再通过FeatureService服务将数据更新到图层上。

更新数据代码如下:

Graphic[] gps = new Graphic[list.size()];

gps = list.toArray(gps);

featureLayerupdate.applyEdits(null, null, gps, null)

List为Graphic对象的列表,上面的操作是更新操作,如果需要添加或删除只需将Graphic数组放到不同的参数位置上即可。

到此,离线数据编辑操作基本完成,待日后spatialite空间数据库日渐完善后,离线编辑将变的更加简单,期待中。

ArcGIS for Android离线数据编辑实现原理的更多相关文章

  1. Arcgis for android 离线查询

    参考.. 官方API demo ... 各种资料 以及.. ArcGIS for Android示例解析之高亮要素-----HighlightFeatures ttp://blog.csdn.net/ ...

  2. arcgis for android常见问题回答

    Q:arcgis for android最新版本是多少?(2014-7-18) Arcgis for android 10.2.3 sdk 百度盘下载地址:http://pan.baidu.com/s ...

  3. ArcGIS For Android 的标绘与可视化

    参考 1. CSDN 相关博文 2. ArcGIS for Android 离线数据空间分析--叠加分析 3. ArcGIS for Android Runtime100 基本操作(五)——绘制图层和 ...

  4. Arcgis For Android之离线地图实现的几种方式

    为什么要用,我想离线地图的好处是不言而喻的,所以很多人做系统的时候都会考虑用离线地图.在此,我给大家介绍几种Arcgis For Android下加载离线地图的方式. 在Arcgis For Andr ...

  5. ArcGis for Android 工作与学习

    ArcGis安装 需求 windows7(32/64) Eclipse3.6以上版本 Android Sdk 2.2以上 Jdk 7 安装步骤 Eclipse安装 下载ArcGis插件 在Eclips ...

  6. 外业数据采集平台(GPS+Android Studio+Arcgis for android 100.2.1)

    外业数据采集平台 1. 综述 在室外,通过平板或者手机接收GPS坐标,实时绘制点.线.面数据,以便为后续进行海域监测.土地确权.地图绘图提供有效数据和依据. 2. 技术路线 Android studi ...

  7. 【Arcgis for android】相关教程收集自网络

    请加入qq群:143501213 一起交流和学习 推荐博客: 张云飞VIR http://www.cnblogs.com/vir56k/tag/arcgis%20for%20android/ arcg ...

  8. Android端代码染色原理及技术实践

    导读 高德地图开放平台产品不断迭代,代码逻辑越来越复杂,现有的测试流程不能保证完全覆盖所有业务代码,测试不到的代码及分支,会存在一定的风险.为了保证测试全面覆盖,需要引入代码覆盖率做为测试指标,需要对 ...

  9. 创建一个ArcGIS for Android 新项目并显示出本地的地图

    1.准备工作:首先要配置好android的开发环境,然后在Eclipse中安装ArcGIS for Android的开发控件:在ArcCatalog中发布好本地的地图服务. 2.安装完ArcGIS f ...

随机推荐

  1. java web 学习笔记 - 表达式语言

    1.表达式语言简介 主要为了简化mvc中 jsp的代码量,方便进行属性的输出.还可以避免进行属性为空等的判断,表达式默认将null设置为"". 表达式语言的一个最大的好处就是,只需 ...

  2. Swift protocol extension method is called instead of method implemented in subclass

    Swift protocol extension method is called instead of method implemented in subclass protocol MyProto ...

  3. CREATE AGGREGATE - 定义一个新的聚集函数

    SYNOPSIS CREATE AGGREGATE name ( BASETYPE = input_data_type, SFUNC = sfunc, STYPE = state_data_type ...

  4. cksum - 一个文件的检查和以及字节数

    SYNOPSIS(总览) ../src/cksum [OPTION]... [FILE]... DESCRIPTION(描述) 输出CRC(循环冗余校验码)检查和以及每个FILE的字节数. --hel ...

  5. B1. Concurrent 多线程的创建

    [概述] 多线程的创建常用的有两种方法:1). 继承 Thread 类: 2). 实现 Runnable 接口: 3). 实现 Callable 接口. [继承 Thread 类] /** * 1. ...

  6. javascript脚本的延时加载

    javascript脚本的延时加载 向HTML页面中插入js代码的主要方法是使用<script>标签,在实际的开发中多采用外部文件的方式,主要考虑到外部js代码的可维护性及可缓存性等优点. ...

  7. 「 Luogu P1122 」 最大子树和

    # 题目大意 真讨厌题面写的老长老长的. 这个题的意思就是给定一棵无根树,每个节点都有一个美丽值(可能是负数),可以删掉一些边来删除某些点,现在要求你求出可以删掉任意条边的情况下,这个树上的剩余节点的 ...

  8. 五段实用的js高级技巧

    技巧一之setTimeout. 应用案例:比如你想一个函数循环执行10次,怎么办?以前通常是先setInterval,然后clearInterval,技巧一就是克服这个问题 复制代码 代码如下: (f ...

  9. Linux学习笔记(一) 文件系统

    对于每一个 Linux 学习者来说,了解 Linux 文件系统的结构是十分有必要的 因为在 Linux 中一切皆文件,可以说只有深入了解 Linux 的文件系统,才会对 Linux 有更深刻的理解 L ...

  10. Python之函数作业

    Python之函数作业 爬页面 #爬虫页面,send一次爬一次 from urllib.request import urlopen def get(): while True: url = yiel ...