如何将JSONArray数据插入Room数据库?插入崩溃问题求助
解决Room数据库插入JSON城市数据的问题
看起来你已经搞定了数据库初始化的异常,但还卡在把JSON数组数据导入Room的环节,我来帮你梳理下当前代码里的问题,然后给出完整的解决方案:
1. 先修复DAO里的明显类型错误
你的CitiesDao里有几个类型不匹配的问题,这些可能会导致运行时异常或者编译错误,先改过来:
getAllCities()返回List<Banks>,应该改成List<Cities>(你查的是cities表,返回的肯定是Cities实体)findByName和findByCode的返回类型是Banks,同样要改成CitiesfindByCode的参数是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
相关产品推荐
相关产品推荐

