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

如何将JSONArray数据插入Room数据库?插入崩溃问题求助

解决Room数据库插入JSON城市数据的问题

看起来你已经搞定了数据库初始化的异常,但还卡在把JSON数组数据导入Room的环节,我来帮你梳理下当前代码里的问题,然后给出完整的解决方案:

1. 先修复DAO里的明显类型错误

你的CitiesDao里有几个类型不匹配的问题,这些可能会导致运行时异常或者编译错误,先改过来:

  • getAllCities()返回List<Banks>,应该改成List<Cities>(你查的是cities表,返回的肯定是Cities实体)
  • findByName和findByCode的返回类型是Banks,同样要改成Cities
  • findByCode的参数是int,但你的Cities实体里cityCode是String类型,得把参数改成String cityCode

修正后的DAO代码:

@Dao
public interface CitiesDao {
    @Query("SELECT * FROM cities")
    List<Cities> getAllCities();

    @Query("SELECT * FROM cities where _cityname LIKE :cityName")
    Cities findByName(String cityName);

    @Query("SELECT * FROM cities where _citycode LIKE :cityCode")
    Cities findByCode(String cityCode);

    @Query("SELECT COUNT(*) from cities")
    int countCities();

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void addCity(Cities cities);

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insertAll(Cities... cities);

    @Delete
    void delete(Cities cities);

    @Update
    void update(Cities cities);
}

2. 修正JSON遍历逻辑:别复用同一个实体对象

你原来的循环里一直用同一个Cities实例,每次循环只是覆盖它的属性值,最后列表里全是最后一条数据的副本,这完全不对!要在每次循环里创建新的Cities对象,然后添加到列表中:

// 先创建一个列表用来存所有城市数据
List<Cities> citiesList = new ArrayList<>();
try {
    JSONArray citiesJsonArray = new JSONArray(unzippedCitiesString);
    for (int i = 0; i < citiesJsonArray.length(); i++) {
        JSONObject data = citiesJsonArray.getJSONObject(i);
        String cityNumber = data.getString("pa");
        String cityName = data.getString("tar");
        
        // 每次循环都new一个新的Cities对象
        Cities city = new Cities();
        city.setCityName(cityName);
        city.setCityCode(cityNumber);
        citiesList.add(city);
    }
} catch (JSONException e) {
    e.printStackTrace();
}

3. 必须在后台线程执行数据库操作

Room默认禁止在UI线程做数据库读写(会直接抛出异常导致崩溃),所以你得把插入逻辑放到后台线程里。这里给你几种常用的实现方式:

方式一:用Thread直接开启后台线程(简单直接)

new Thread(() -> {
    // 从Application中获取初始化好的数据库实例
    MyDatabase db = ((MyApp) getApplication()).getDatabase();
    // 把列表转成数组传入insertAll
    db.citiesDao().insertAll(citiesList.toArray(new Cities[0]));
}).start();

方式二:用Executor(更规范,适合重复使用)

// 初始化一个单线程的Executor,全局可以复用
private Executor dbExecutor = Executors.newSingleThreadExecutor();

// 执行插入操作
dbExecutor.execute(() -> {
    if (!citiesList.isEmpty()) {
        MyDatabase db = ((MyApp) getApplication()).getDatabase();
        db.citiesDao().insertAll(citiesList.toArray(new Cities[0]));
    }
});

方式三:用AsyncTask(已废弃,但兼容旧版本Android)

如果你的项目需要兼容旧版本,可以用这个,但官方已经不推荐了:

new AsyncTask<Void, Void, Void>() {
    @Override
    protected Void doInBackground(Void... voids) {
        if (!citiesList.isEmpty()) {
            MyDatabase db = ((MyApp) getApplication()).getDatabase();
            db.citiesDao().insertAll(citiesList.toArray(new Cities[0]));
        }
        return null;
    }
}.execute();

4. 确认数据库初始化的正确性

你提到已经在Base Application中初始化数据库,确保你的Application代码是这样的(别加allowMainThreadQueries,除非是测试用):

public class MyApp extends Application {
    private MyDatabase database;

    @Override
    public void onCreate() {
        super.onCreate();
        database = Room.databaseBuilder(getApplicationContext(), MyDatabase.class, MyDatabase.DB_NAME)
                // .allowMainThreadQueries() // 测试时可以临时加,正式环境必须删掉!
                .build();
    }

    public MyDatabase getDatabase() {
        return database;
    }
}

注意:allowMainThreadQueries会允许在UI线程操作数据库,正式环境绝对不能加,否则会导致UI卡顿甚至ANR。

最后整合完整流程

把上面的步骤整合起来,你的完整插入逻辑就是:先解析JSON生成Cities对象列表,然后在后台线程调用DAO的insertAll方法插入所有数据。这样就能把JSON里的所有城市数据正确导入Room数据库了。

内容的提问来源于stack exchange,提问作者user6683139

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:12:16