Android中如何将地图长按标记保存到SQLite数据库并正常加载
问题成因汇总
getColumnIndex报Value must be ≥ 0错误核心原因:查询投影未包含对应列、列名字符串拼写/大小写不匹配、数据库升级未处理导致旧表结构残留,查询时找不到指定列。- 数据未成功入库常见原因:ContentProvider的Uri匹配逻辑错误、insert实现未做结果校验、ContentValues的键和表列名不匹配、调用insert时Uri的authority与Manifest注册值不一致。
- 重启后标记不显示原因:数据本身未入库成功、查询逻辑错误未正确遍历Cursor取值、地图异步加载未完成就执行加标记操作、经纬度/缩放级别的取值类型不匹配。
修复方案
1. 修复getColumnIndex报错
首先统一列名定义为静态常量,所有场景直接引用常量避免手写字符串出错,同时建表时确保包含所有需要的列:
// LocationsDB类中统一定义列名与建表语句 public static final String TABLE_NAME = "saved_locations"; public static final String COLUMN_LAT = "latitude"; public static final String COLUMN_LNG = "longitude"; public static final String COLUMN_ZOOM = "zoom_level"; private static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + "_id INTEGER PRIMARY KEY AUTOINCREMENT, " + COLUMN_LAT + " REAL NOT NULL, " + COLUMN_LNG + " REAL NOT NULL, " + COLUMN_ZOOM + " REAL NOT NULL)";
如果修改过表结构,必须升级数据库版本号,在onUpgrade中清理旧表:
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); onCreate(db); }
取值前先校验索引合法性,避免崩溃:
int latIndex = cursor.getColumnIndex(LocationsDB.COLUMN_LAT); if (latIndex >= 0 && !cursor.isNull(latIndex)) { double lat = cursor.getDouble(latIndex); }
2. 修复数据入库失败
首先确保ContentProvider的insert逻辑正确,添加匹配校验与日志:
// 提前定义Uri匹配规则 private static final int CODE_LOCATIONS = 1; private static final UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH); static { // 此处AUTHORITY要和Manifest注册的完全一致 sMatcher.addURI("你的Provider的AUTHORITY", "locations", CODE_LOCATIONS); } @Override public Uri insert(Uri uri, ContentValues values) { int matchCode = sMatcher.match(uri); if (matchCode != CODE_LOCATIONS) { throw new IllegalArgumentException("不支持的Uri: " + uri); } SQLiteDatabase db = dbHelper.getWritableDatabase(); long rowId = db.insert(LocationsDB.TABLE_NAME, null, values); if (rowId == -1) { Log.e("DB_INSERT", "插入失败,检查ContentValues字段是否匹配"); return null; } getContext().getContentResolver().notifyChange(uri, null); return ContentUris.withAppendedId(uri, rowId); }
长按触发存储时,ContentValues必须使用统一定义的列名常量:
@Override public void onMapLongClick(LatLng latLng) { // 先添加标记到当前地图 mMap.addMarker(new MarkerOptions().position(latLng)); // 组装入库数据 ContentValues values = new ContentValues(); values.put(LocationsDB.COLUMN_LAT, latLng.latitude); values.put(LocationsDB.COLUMN_LNG, latLng.longitude); values.put(LocationsDB.COLUMN_ZOOM, mMap.getCameraPosition().zoom); // 调用insert,Uri的AUTHORITY必须和注册值一致 getContentResolver().insert(Uri.parse("content://你的Provider的AUTHORITY/locations"), values); }
3. 修复重启后标记不显示
必须在onMapReady回调(地图加载完成)中执行查询与加标记逻辑:
@Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; // 查询所有已存标记 Cursor cursor = getContentResolver().query( Uri.parse("content://你的Provider的AUTHORITY/locations"), // 投影必须包含需要的三个列,不要漏传 new String[]{LocationsDB.COLUMN_LAT, LocationsDB.COLUMN_LNG, LocationsDB.COLUMN_ZOOM}, null, null, null ); // 遍历Cursor加标记 if (cursor != null) { while (cursor.moveToNext()) { double lat = cursor.getDouble(cursor.getColumnIndexOrThrow(LocationsDB.COLUMN_LAT)); double lng = cursor.getDouble(cursor.getColumnIndexOrThrow(LocationsDB.COLUMN_LNG)); mMap.addMarker(new MarkerOptions().position(new LatLng(lat, lng))); } cursor.close(); } // 绑定长按事件 mMap.setOnMapLongClickListener(this); }
内容的提问来源于stack exchange,提问作者Allrounder
相关产品推荐
相关产品推荐

