Room数据库LiveData计算异常:ArrayList类型转换错误求助
问题:Room存储ArrayList时Gson解析异常
场景说明
需要在Room数据库中用两个ArrayList存储数据,实现了Entity、TypeConverter、DAO和数据插入逻辑,但运行时抛出解析异常,无法正常读取数据。
Entity类
@Entity public class User { public int getId() { return id; } @NonNull public ArrayList<String> getValues(){ return values; } @NonNull public ArrayList<String> getDates(){ return dates; } @NonNull public String getType_counter() { return type_counter; } @NonNull public String getWhere_counter() { return where_counter; } @PrimaryKey(autoGenerate = true) public int id; @ColumnInfo(name = "d") @TypeConverters({Converters.class}) public ArrayList<String> dates; // arraylist here @ColumnInfo(name = "value") @TypeConverters({Converters.class}) public ArrayList<String> values; // arraylist here @ColumnInfo(name = "type") public String type_counter; @ColumnInfo(name = "location") public String where_counter; }
TypeConverter类
public class Converters { @TypeConverter public static ArrayList<String> fromString(String value) { Type listType = new TypeToken<ArrayList<String>>() {}.getType(); return new Gson().fromJson(value, listType); } @TypeConverter public static String fromArrayList(ArrayList<String> list) { Gson gson = new Gson(); return gson.toJson(list); } }
数据插入方法
private void saveNewValue(String value, String type, String location){ // Getting current date Date c = Calendar.getInstance().getTime(); SimpleDateFormat df = new SimpleDateFormat("dd-MMM-yyyy", Locale.getDefault()); String formattedDate = df.format(c); //Saving new User userViewModel = ViewModelProviders.of(this).get(UserViewModel.class); User user = new User(); user.values.add(value); user.dates.add(formattedDate); user.type_counter = type; user.where_counter = location; userViewModel.insert(user); Toast.makeText(this, "Successfully saved!", Toast.LENGTH_SHORT).show(); }
DAO类
@Dao public interface UserDao { @Query("SELECT * FROM User ") LiveData<List<User>> getAllValues(); @Insert void insertValue(User ... users); @Delete void deleteValue(User user); @Query("SELECT location FROM User") LiveData<String[]> getAllLocations(); @Query("SELECT * from User WHERE id=:id") LiveData<User> getUserWithId(int id); }
运行时异常信息
E/AndroidRuntime: FATAL EXCEPTION: arch_disk_io_0 Process: org.tensorflow.lite.examples.detection, PID: 14774 java.lang.RuntimeException: Exception while computing database live data. at androidx.room.RoomTrackingLiveData$1.run(RoomTrackingLiveData.java:92) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) at java.lang.Thread.run(Thread.java:764) Caused by: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 1 path $ at com.google.gson.Gson.fromJson(Gson.java:944) at com.google.gson.Gson.fromJson(Gson.java:897) at com.google.gson.Gson.fromJson(Gson.java:846) at org.tensorflow.lite.examples.detection.Converters.fromString(Converters.java:15) at org.tensorflow.lite.examples.detection.db.UserDao_Impl$3.call(UserDao_Impl.java:126) at org.tensorflow.lite.examples.detection.db.UserDao_Impl$3.call(UserDao_Impl.java:109) at androidx.room.RoomTrackingLiveData$1.run(RoomTrackingLiveData.java:90) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) at java.lang.Thread.run(Thread.java:764) Caused by: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 1 path $ at com.google.gson.stream.JsonReader.beginArray(JsonReader.java:351) at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:80) at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61) at com.google.gson.Gson.fromJson(Gson.java:932) at com.google.gson.Gson.fromJson(Gson.java:897) at com.google.gson.Gson.fromJson(Gson.java:846) at org.tensorflow.lite.examples.detection.Converters.fromString(Converters.java:15) at org.tensorflow.lite.examples.detection.db.UserDao_Impl$3.call(UserDao_Impl.java:126) at org.tensorflow.lite.examples.detection.db.UserDao_Impl$3.call(UserDao_Impl.java:109) at androidx.room.RoomTrackingLiveData$1.run(RoomTrackingLiveData.java:90) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) at java.lang.Thread.run(Thread.java:764) D/OpenGLRenderer: endAllActiveAnimators on 0x72aa705400 (RippleDrawable) with handle 0x72a70ea8e0
问题原因及修复方案
核心问题
- ArrayList未初始化:创建User对象时,
dates和values字段未初始化,直接调用add()会触发空指针,且Room会将未初始化的@NonNull字段存储为空字符串,导致Gson读取时无法解析成数组。 - TypeConverter未处理null/空字符串:转换器没有处理输入为null或空字符串的场景,Gson无法将空字符串解析为ArrayList。
- TypeConverters注解位置错误:注解放在Entity字段上可能导致全局生效异常,应放在Database类上。
修复步骤
1. 初始化User类的ArrayList字段
修改User类,在字段声明或构造方法中初始化ArrayList,同时保留Room所需的无参构造:
@Entity public class User { // ... 原有getter方法 ... @PrimaryKey(autoGenerate = true) public int id; @ColumnInfo(name = "d") public ArrayList<String> dates = new ArrayList<>(); @ColumnInfo(name = "value") public ArrayList<String> values = new ArrayList<>(); @ColumnInfo(name = "type") public String type_counter; @ColumnInfo(name = "location") public String where_counter; // Room需要的无参构造 public User() { this.dates = new ArrayList<>(); this.values = new ArrayList<>(); } }
2. 完善TypeConverter的空值处理
修改Converters类,增加null和空字符串的判断逻辑:
public class Converters { @TypeConverter public static ArrayList<String> fromString(String value) { if (value == null || value.isEmpty()) { return new ArrayList<>(); } Type listType = new TypeToken<ArrayList<String>>() {}.getType(); return new Gson().fromJson(value, listType); } @TypeConverter public static String fromArrayList(ArrayList<String> list) { if (list == null) { return new Gson().toJson(new ArrayList<String>()); } Gson gson = new Gson(); return gson.toJson(list); } }
3. 迁移TypeConverters注解到Database类
在Room数据库类上添加注解,确保全局生效:
@Database(entities = {User.class}, version = 1) @TypeConverters({Converters.class}) public abstract class AppDatabase extends RoomDatabase { public abstract UserDao userDao(); }
4. 清理旧数据库
卸载应用重新安装,或添加数据库迁移逻辑,避免读取之前存储的无效数据。
验证
修复后重新运行,插入数据后查询,可正常解析ArrayList,不再抛出解析异常。
内容的提问来源于stack exchange,提问作者ALiCe P.
相关产品推荐
相关产品推荐

