You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 19:15:01