Android Room仅在Lollipop5.1(SDK22)出现主键位置重复的无效架构问题
问题:Room在Android 5.1(SDK22)下联合主键Schema验证崩溃
定义的Room Entity类
@Entity(tableName = "game_regions", primaryKeys = {"_game", "_region_area"}, foreignKeys = { @ForeignKey( entity = GameEntity.class, parentColumns = "_id", childColumns = "_game" ), @ForeignKey( entity = RegionAreaEntity.class, parentColumns = "_id", childColumns = "_region_area" )}) public class GameRegionsEntity { @NonNull @ColumnInfo(name = "_game") private String game; @NonNull @ColumnInfo(name = "_region_area") private String regionArea; public GameRegionsEntity(@NonNull String game, @NonNull String regionArea) { this.game = game; this.regionArea = regionArea; } @NonNull public String getGame() { return game; } public void setGame(@NonNull String game) { this.game = game; } @NonNull public String getRegionArea() { return regionArea; } public void setRegionArea(@NonNull String regionArea) { this.regionArea = regionArea; } }
对应的SQL建表语句
CREATE TABLE "game_regions" ( "_game" TEXT NOT NULL, "_region_area" TEXT NOT NULL, PRIMARY KEY("_game","_region_area"), FOREIGN KEY("_region_area") REFERENCES "region_areas"("_id"), UNIQUE("_game","_region_area"), FOREIGN KEY("_game") REFERENCES "games"("_id") );
异常信息
java.lang.IllegalStateException: Pre-packaged database has an invalid schema: game_regions(GameRegionsEntity). Expected: TableInfo{name='game_regions', columns={_region_area=Column{name='_region_area', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=2, defaultValue='undefined'}, _game=Column{name='_game', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1, defaultValue='undefined'}}, foreignKeys=[ForeignKey{referenceTable='games', onDelete='NO ACTION +', onUpdate='NO ACTION', columnNames=[_game], referenceColumnNames=[_id]}, ForeignKey{referenceTable='region_areas', onDelete='NO ACTION +', onUpdate='NO ACTION', columnNames=[_region_area], referenceColumnNames=[_id]}], indices=[]} Found: TableInfo{name='game_regions', columns={_game=Column{name='_game', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1, defaultValue='undefined'}, _region_area=Column{name='_region_area', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1, defaultValue='undefined'}}, foreignKeys=[ForeignKey{referenceTable='region_areas', onDelete='NO ACTION +', onUpdate='NO ACTION', columnNames=[_region_area], referenceColumnNames=[_id]}, ForeignKey{referenceTable='games', onDelete='NO ACTION +', onUpdate='NO ACTION', columnNames=[_game], referenceColumnNames=[_id]}], indices=null}
问题分析
对比预期与实际的TableInfo,唯一差异是:预期中两个联合主键的primaryKeyPosition分别为1和2,而Android 5.1设备上实际返回的primaryKeyPosition均为1。该问题仅在SDK22出现,原因是Android 5.1搭载的SQLite版本(3.8.10)较低,Room在解析该版本SQLite的系统表时,无法正确识别联合主键的顺序,导致Schema验证失败。
解决方案
方案1:禁用该表的Schema验证
在Room的@Database注解中,将game_regions表加入excludeFromValidation列表,跳过该表的Schema校验:
@Database( entities = {GameRegionsEntity.class, GameEntity.class, RegionAreaEntity.class}, version = 1, excludeFromValidation = {"game_regions"} ) public abstract class AppDatabase extends RoomDatabase { // ... DAO定义 }
方案2:升级Room版本
检查并升级Room到较新的稳定版本(如2.4.0及以上),部分低版本Room存在的旧SQLite兼容性问题已被修复。
方案3:改用Room Migration生成表
避免使用预打包数据库,改用Room的Migration机制在应用启动时创建表。Room会根据Entity定义自动生成符合各版本SQLite要求的建表语句,确保主键顺序被正确识别。
内容的提问来源于stack exchange,提问作者Nexussim Lements
相关产品推荐
相关产品推荐

