AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 77164866
Accepted
Matias Chiaia
Matias Chiaia
Asked: 2023-09-24 04:54:04 +0800 CST2023-09-24 04:54:04 +0800 CST 2023-09-24 04:54:04 +0800 CST

使用预填充的房间数据库时应用程序崩溃

  • 772

我正在尝试使用预先填充的 Room 数据库,但在尝试使用该数据库时出现崩溃,并出现以下错误: java.lang.NullPointerException: cursor.getString(toColumnIndex) must not be null

一切正常,直到我添加该createFromAsset("databses/test.db")方法,当它崩溃时。如果我不执行该getAllCocktails()方法,则不会发生任何崩溃。我已经检查了我插入的数据库是否完全相同,并且找不到任何差异(我还检查了使用 AppInspection 加载的数据)

我不仅进行了测试,getAllCocktails()还尝试使用完全参数化的构造函数进行插入

我将发布(一些)我的代码和日志,以便更容易诊断我尝试使用 Room 的版本 2.5.1 和 2.5.2

测试.db文件

活动:

public class PedirTragoActivity extends AppCompatActivity {

    AppDatabase db;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_pedir_trago1_1);

        db = AppDatabase.getInstance(this.getApplication());

        db.cocktailDAO().getAllCocktails();
    }
}

房间数据库:

@Database(entities = {
        BottleEntity.class,
        BottleIngredientEntity.class,
        CocktailEntity.class,
        CocktailIngredientEntity.class,
        IngredientTypeEntity.class
},
        version = 7)
public abstract class AppDatabase extends RoomDatabase {
    public static AppDatabase INSTANCE;

    public abstract BottleDAO bottleDAO();

    public abstract BottleIngredientDAO bottleIngredientDAO();

    public abstract CocktailDAO cocktailDAO();

    public abstract CocktailIngredientDAO cocktailIngredientDAO();

    public abstract IngredientTypeDAO ingredientTypeDAO();
    public static AppDatabase getInstance(Context context) {
        if (INSTANCE == null) {
            INSTANCE = Room.databaseBuilder(context, AppDatabase.class, "barbotApp.db")
                    .allowMainThreadQueries()
                    .fallbackToDestructiveMigration()
                    .createFromAsset("databases/test.db")
                    .build();

        }
        return INSTANCE;
    }
}

瓶子实体:

@Entity(tableName = "bottles")
public class BottleEntity {
    @PrimaryKey
    @NonNull
    private int position;//Del 0 al 7 son alcoholes, el 8 es shaker y del 9 al 16 son mezclas
    private String name;
    @NonNull
    private int capacity;
    @NonNull
    private int currentAmount;

    public BottleEntity() {
    }

    public BottleEntity(int position, String name, int capacity, int currentAmount) {
        this.position = position;
        this.name = name;
        this.capacity = capacity;
        this.currentAmount = currentAmount;
    }
    @Ignore
    public BottleEntity(int position, String name, int capacity) {
        this.position = position;
        this.name = name;
        this.capacity = capacity;
        this.currentAmount = capacity;
    }

    public int getPosition() {
        return position;
    }

    public void setPosition(int position) {
        this.position = position;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getCapacity() {
        return capacity;
    }

    public void setCapacity(int capacity) {
        this.capacity = capacity;
    }

    public int getCurrentAmount() {
        return currentAmount;
    }

    public void setCurrentAmount(int currentAmount) {
        this.currentAmount = currentAmount;
    }
}

瓶子成分实体:

@Entity(tableName = "bottle_ingredient",
        foreignKeys = {
                @ForeignKey(entity = BottleEntity.class, parentColumns = "position", childColumns = "bottlePos"),
                @ForeignKey(entity = IngredientTypeEntity.class, parentColumns = "id", childColumns = "ingredientId")
        })
public class BottleIngredientEntity {

    @PrimaryKey(autoGenerate = true)
    @NonNull
    private int id;

    @NonNull
    private int bottlePos;


    @NonNull
    private int ingredientId;


    public BottleIngredientEntity() {
    }

    public BottleIngredientEntity(int bottlePos, int ingredientId) {
        this.bottlePos = bottlePos;
        this.ingredientId = ingredientId;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getBottlePos() {
        return bottlePos;
    }

    public void setBottlePos(int bottlePos) {
        this.bottlePos = bottlePos;
    }

    public int getIngredientId() {
        return ingredientId;
    }

    public void setIngredientId(int ingredientId) {
        this.ingredientId = ingredientId;
    }
}

鸡尾酒成分实体:

@Entity(tableName = "cocktail_ingredients",
        foreignKeys = {
                @ForeignKey(entity = IngredientTypeEntity.class, parentColumns = "id", childColumns = "typeId"),
                @ForeignKey(entity = CocktailEntity.class, parentColumns = "id", childColumns = "cocktailId")
        })
public class CocktailIngredientEntity {
    @PrimaryKey(autoGenerate = true)
    @NonNull
    private int id;
    @NonNull
    private int typeId;
    @NonNull
    private int quantity;
    @NonNull
    private int cocktailId;

    public CocktailIngredientEntity(int typeId, int quantity, int cocktailId) {
        this.typeId = typeId;
        this.quantity = quantity;
        this.cocktailId = cocktailId;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getTypeId() {
        return typeId;
    }

    public void setTypeId(int typeId) {
        this.typeId = typeId;
    }

    public int getQuantity() {
        return quantity;
    }

    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }

    public int getCocktailId() {
        return cocktailId;
    }

    public void setCocktailId(int cocktailId) {
        this.cocktailId = cocktailId;
    }
}

成分类型实体:

@Entity(tableName = "ingredient_types")
public class IngredientTypeEntity {
    @PrimaryKey(autoGenerate = true)
    @NonNull
    private int id;
    private String name;

    public IngredientTypeEntity() {
    }

    public IngredientTypeEntity(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

鸡尾酒实体:

@Entity(tableName = "cocktails")
public class CocktailEntity {
    @PrimaryKey(autoGenerate = true)
    @NonNull
    private int id;

    private String name;

    @NonNull
    private boolean isOnStock;
    @NonNull
    private boolean hasIce;

    private String imgName;

    public CocktailEntity(String name, boolean isOnStock, boolean hasIce, String imgName) {
        this.name = name;
        this.isOnStock = isOnStock;
        this.hasIce = hasIce;
        this.imgName = imgName;
    }

    @Ignore
    public CocktailEntity(String name, boolean hasIce, String imaName) {
        this.name = name;
        this.isOnStock = false;
        this.hasIce = hasIce;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isOnStock() {
        return isOnStock;
    }

    public void setOnStock(boolean onStock) {
        isOnStock = onStock;
    }

    public boolean isHasIce() {
        return hasIce;
    }

    public void setHasIce(boolean hasIce) {
        this.hasIce = hasIce;
    }

    public String getImgName() {
        return imgName;
    }

    public void setImgName(String imgName) {
        this.imgName = imgName;
    }
}

鸡尾酒道:

@Dao
public interface CocktailDAO {

    @Insert
    long insertCocktail(CocktailEntity cocktail);

    @Query("SELECT id FROM cocktails WHERE name = :name")
    int getCocktailId(String name);

    @Query("SELECT c.* FROM cocktails AS c WHERE c.id = :id")
    CocktailEntity getCocktail(int id); //Need to use a repository, separate this 2 parts

    @Query("SELECT * FROM cocktails")
    List<CocktailEntity> getAllCocktails();

    @Query("SELECT cocktails.id FROM cocktails")
    List<Integer> getAllCocktailIds();

    @Query("SELECT * FROM cocktails" +
            " WHERE cocktails.isOnStock = 1")
    List<CocktailEntity> getAllCocktailsInStock();

    @Query("SELECT isOnStock FROM cocktails WHERE id = :id")
    boolean isCocktailInStock(int id);

    @Query("UPDATE cocktails SET isOnStock = :isOnStock WHERE id = :id")
    void updateCocktailStock(int id, boolean isOnStock);
}

Logcat:

2023-09-23 17:17:20.600  8250-8250  Choreographer           com.mecatronica.barbot               I  Skipped 67 frames!  The application may be doing too much work on its main thread.
2023-09-23 17:17:20.801  8250-8594  AdrenoGLES-0            com.mecatronica.barbot               I  QUALCOMM build                   : 03e27f8, I326e6aff90
                                                                                                    Build Date                       : 11/02/20
                                                                                                    OpenGL ES Shader Compiler Version: EV031.32.02.04
                                                                                                    Local Branch                     : mybrancheb1d781c-1a78-f1f4-8c78-ac1f6bcc2cee
                                                                                                    Remote Branch                    : quic/gfx-adreno.lnx.1.0.r116-rel
                                                                                                    Remote Branch                    : NONE
                                                                                                    Reconstruct Branch               : NOTHING
2023-09-23 17:17:20.801  8250-8594  AdrenoGLES-0            com.mecatronica.barbot               I  Build Config                     : S P 10.0.7 AArch64
2023-09-23 17:17:20.801  8250-8594  AdrenoGLES-0            com.mecatronica.barbot               I  Driver Path                      : /vendor/lib64/egl/libGLESv2_adreno.so
2023-09-23 17:17:20.813  8250-8594  AdrenoGLES-0            com.mecatronica.barbot               I  PFP: 0x016ee190, ME: 0x00000000
2023-09-23 17:17:21.019  8250-8594  LB                      com.mecatronica.barbot               E  fail to open file: No such file or directory
2023-09-23 17:17:21.021  8250-8594  OpenGLRenderer          com.mecatronica.barbot               I  Davey! duration=1547ms; Flags=1, IntendedVsync=42335033169415, Vsync=42336149836037, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=42336161943432, AnimationStart=42336162004370, PerformTraversalsStart=42336162065047, DrawStart=42336409293120, SyncQueued=42336445054213, SyncStart=42336445465515, IssueDrawCommandsStart=42336445624838, SwapBuffers=42336577074578, FrameCompleted=42336581385203, DequeueBufferDuration=272760, QueueBufferDuration=682187, GpuCompleted=1893829464, 
2023-09-23 17:17:21.027  8250-8250  Looper                  com.mecatronica.barbot               W  PerfMonitor doFrame : time=424ms vsyncFrame=0 latency=1127ms procState=2 historyMsgCount=10 (msgIndex=1 wall=1223ms seq=4 running=1128ms runnable=12ms late=2999ms h=android.app.ActivityThread$H w=159) (msgIndex=5 wall=1007ms seq=8 running=2ms runnable=1ms io=4ms late=3591ms h=android.app.ActivityThread$H w=127)
2023-09-23 17:17:21.154  8250-8250  Looper                  com.mecatronica.barbot               W  PerfMonitor doFrame : time=35ms vsyncFrame=0 latency=459ms procState=2 historyMsgCount=4 (msgIndex=1 wall=424ms seq=14 running=255ms runnable=1ms late=1127ms h=android.view.Choreographer$FrameHandler c=android.view.Choreographer$FrameDisplayEventReceiver) (msgIndex=4 wall=78ms seq=17 running=70ms runnable=2ms late=413ms h=android.view.ViewRootImpl$ViewRootHandler c=androidx.appcompat.app.AppCompatDelegateImpl$2)
2023-09-23 17:17:28.708  8250-8250  MiuiFrameworkFactory    com.mecatronica.barbot               V  get AllImpl object = android.common.MiuiFrameworkFactoryImpl@b038154
2023-09-23 17:17:28.726  8250-8250  MirrorManager           com.mecatronica.barbot               W  this model don't Support
2023-09-23 17:17:28.773  8250-8250  Timeline                com.mecatronica.barbot               I  Timeline: Activity_launch_request time:42344334
2023-09-23 17:17:28.996  8250-8250  DecorView[]             com.mecatronica.barbot               D  getWindowModeFromSystem  windowmode is 1
2023-09-23 17:17:28.997  8250-8250  DecorView               com.mecatronica.barbot               D  createDecorCaptionView windowingMode:1 mWindowMode 1 isFullscreen: true
2023-09-23 17:17:30.631  8250-8250  AndroidRuntime          com.mecatronica.barbot               D  Shutting down VM
2023-09-23 17:17:30.646  8250-8250  AndroidRuntime          com.mecatronica.barbot               E  FATAL EXCEPTION: main
                                                                                                    Process: com.mecatronica.barbot, PID: 8250
                                                                                                    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mecatronica.barbot/com.mecatronica.barbot.PedirTragoActivity}: java.lang.NullPointerException: cursor.getString(toColumnIndex) must not be null
                                                                                                        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3550)
                                                                                                        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3710)
                                                                                                        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
                                                                                                        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
                                                                                                        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
                                                                                                        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2146)
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:106)
                                                                                                        at android.os.Looper.loop(Looper.java:236)
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:8057)
                                                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:656)
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967)
                                                                                                    Caused by: java.lang.NullPointerException: cursor.getString(toColumnIndex) must not be null
                                                                                                        at androidx.room.util.TableInfoKt.readForeignKeyFieldMappings(TableInfo.kt:536)
                                                                                                        at androidx.room.util.TableInfoKt.readForeignKeys(TableInfo.kt:488)
                                                                                                        at androidx.room.util.TableInfoKt.readTableInfo(TableInfo.kt:472)
                                                                                                        at androidx.room.util.TableInfo$Companion.read(TableInfo.kt:130)
                                                                                                        at androidx.room.util.TableInfo.read(Unknown Source:2)
                                                                                                        at com.mecatronica.barbot.database.AppDatabase_Impl$1.onValidateSchema(AppDatabase_Impl.java:136)
                                                                                                        at androidx.room.RoomOpenHelper.onCreate(RoomOpenHelper.kt:72)
                                                                                                        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onCreate(FrameworkSQLiteOpenHelper.kt:244)
                                                                                                        at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:411)
                                                                                                        at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:316)
                                                                                                        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableOrReadableDatabase(FrameworkSQLiteOpenHelper.kt:232)
                                                                                                        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.innerGetDatabase(FrameworkSQLiteOpenHelper.kt:190)
                                                                                                        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getSupportDatabase(FrameworkSQLiteOpenHelper.kt:151)
                                                                                                        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.kt:104)
                                                                                                        at androidx.room.SQLiteCopyOpenHelper.getWritableDatabase(SQLiteCopyOpenHelper.kt:71)
                                                                                                        at androidx.room.RoomDatabase.inTransaction(RoomDatabase.kt:638)
                                                                                                        at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.kt:457)
                                                                                                        at com.mecatronica.barbot.database.daos.CocktailDAO_Impl.getAllCocktails(CocktailDAO_Impl.java:177)
                                                                                                        at com.mecatronica.barbot.PedirTragoActivity.onCreate(PedirTragoActivity.java:63)
                                                                                                        at android.app.Activity.performCreate(Activity.java:8157)
                                                                                                        at android.app.Activity.performCreate(Activity.java:8129)
                                                                                                        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1310)
                                                                                                        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3523)
                                                                                                        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3710) 
                                                                                                        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
                                                                                                        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
                                                                                                        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
                                                                                                        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2146) 
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:106) 
                                                                                                        at android.os.Looper.loop(Looper.java:236) 
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:8057) 
                                                                                                        at java.lang.reflect.Method.invoke(Native Method) 
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:656) 
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967) 
2023-09-23 17:17:30.716  8250-8250  Process                 com.mecatronica.barbot               I  Sending signal. PID: 8250 SIG: 9

sql dump form test.db:

PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS "ingredient_types"
(
    id   INTEGER not null
        constraint ingredient_types_pk
            primary key,
    name TEXT
);
INSERT INTO ingredient_types VALUES(1,'SHAKE');
INSERT INTO ingredient_types VALUES(2,'limón');
INSERT INTO ingredient_types VALUES(3,'ron');
INSERT INTO ingredient_types VALUES(4,'tonica');
INSERT INTO ingredient_types VALUES(5,'ginebra');
INSERT INTO ingredient_types VALUES(6,'campari');
INSERT INTO ingredient_types VALUES(7,'naranja');
INSERT INTO ingredient_types VALUES(8,'fernet');
INSERT INTO ingredient_types VALUES(9,'coca');
INSERT INTO ingredient_types VALUES(10,'durazno');
INSERT INTO ingredient_types VALUES(11,'granadina');
INSERT INTO ingredient_types VALUES(12,'vodka');
CREATE TABLE IF NOT EXISTS "bottle_ingredient"
(
    id           INTEGER not null
        constraint bottle_ingredient_pk
            primary key,
    bottlePos    INTEGER not null
        constraint bottle_ingredient_bottles_position_fk
            references bottles,
    ingredientId INTEGER not null
        constraint bottle_ingredient_ingredient_types_id_fk
            references ingredient_types
);
INSERT INTO bottle_ingredient VALUES(1,8,5);
INSERT INTO bottle_ingredient VALUES(2,9,6);
INSERT INTO bottle_ingredient VALUES(3,10,8);
INSERT INTO bottle_ingredient VALUES(4,11,3);
INSERT INTO bottle_ingredient VALUES(5,12,12);
INSERT INTO bottle_ingredient VALUES(7,0,2);
INSERT INTO bottle_ingredient VALUES(8,1,4);
INSERT INTO bottle_ingredient VALUES(9,2,7);
INSERT INTO bottle_ingredient VALUES(10,3,9);
INSERT INTO bottle_ingredient VALUES(11,4,10);
INSERT INTO bottle_ingredient VALUES(12,5,11);
INSERT INTO bottle_ingredient VALUES(13,16,1);
CREATE TABLE IF NOT EXISTS "bottles"
(
    position      INTEGER not null
        constraint bottles_pk
            primary key,
    name          TEXT,
    capacity      INTEGER not null,
    currentAmount INTEGER not null
);
INSERT INTO bottles VALUES(0,'limon',2000,2000);
INSERT INTO bottles VALUES(1,'tonica',2000,2000);
INSERT INTO bottles VALUES(2,'naranja',2000,2000);
INSERT INTO bottles VALUES(3,'coca',2000,2000);
INSERT INTO bottles VALUES(4,'durazno',2000,2000);
INSERT INTO bottles VALUES(5,'granadina',2000,2000);
INSERT INTO bottles VALUES(6,'Mezcla 7',1,1);
INSERT INTO bottles VALUES(7,'Mezcla 8',1,1);
INSERT INTO bottles VALUES(8,'ginebra',700,700);
INSERT INTO bottles VALUES(9,'campari',750,750);
INSERT INTO bottles VALUES(10,'fernet',750,750);
INSERT INTO bottles VALUES(11,'ron',750,750);
INSERT INTO bottles VALUES(12,'vodka',700,700);
INSERT INTO bottles VALUES(13,'Bottle 6',1,1);
INSERT INTO bottles VALUES(14,'Bottle 7',1,1);
INSERT INTO bottles VALUES(15,'Bottle 8',1,1);
INSERT INTO bottles VALUES(16,'Shakeo',1000,1000);
CREATE TABLE IF NOT EXISTS "cocktail_ingredients"
(
    id         INTEGER not null
        constraint cocktail_ingredients_pk
            primary key,
    typeId     INTEGER not null
        constraint cocktail_ingredients_ingredient_types_id_fk
            references ingredient_types,
    quantity   INTEGER not null,
    cocktailId INTEGER not null
        constraint cocktail_ingredients_cocktails_id_fk
            references cocktails
);
INSERT INTO cocktail_ingredients VALUES(1,6,60,1);
INSERT INTO cocktail_ingredients VALUES(2,7,136,1);
INSERT INTO cocktail_ingredients VALUES(3,9,146,2);
INSERT INTO cocktail_ingredients VALUES(4,8,50,2);
INSERT INTO cocktail_ingredients VALUES(5,5,60,3);
INSERT INTO cocktail_ingredients VALUES(6,4,136,3);
INSERT INTO cocktail_ingredients VALUES(7,3,50,4);
INSERT INTO cocktail_ingredients VALUES(8,9,120,4);
INSERT INTO cocktail_ingredients VALUES(9,2,10,4);
INSERT INTO cocktail_ingredients VALUES(10,12,40,5);
INSERT INTO cocktail_ingredients VALUES(11,10,20,5);
INSERT INTO cocktail_ingredients VALUES(12,7,40,5);
INSERT INTO cocktail_ingredients VALUES(13,1,30,5);
INSERT INTO cocktail_ingredients VALUES(14,11,40,5);
CREATE TABLE IF NOT EXISTS "cocktails"
(
    id        INTEGER not null
        constraint cocktails_pk
            primary key,
    name      TEXT,
    isOnStock INTEGER not null,
    hasIce    INTEGER not null,
    imgName   TEXT
);
INSERT INTO cocktails VALUES(1,'campari',1,1,'campari');
INSERT INTO cocktails VALUES(2,'fernet',1,1,'fernet');
INSERT INTO cocktails VALUES(3,'gin tonic',1,1,'gintonic');
INSERT INTO cocktails VALUES(4,'ron cola',1,1,'roncola');
INSERT INTO cocktails VALUES(5,'sex On  the beach',1,1,'sexOnTheBeach');
COMMIT;
android
  • 1 1 个回答
  • 51 Views

1 个回答

  • Voted
  1. Best Answer
    MikeT
    2023-09-24T05:15:48+08:002023-09-24T05:15:48+08:00

    It all works fine until I add the createFromAsset("databses/test.db") method

    and then from the logcat:-

    cursor.getString(toColumnIndex) must not be null

    Is probably due to the data from the asset having nulls (or at least one null) in a column when the column in the @Entity annotated class does not allow nulls.

    It should also be noted that if you exclude db.cocktailDAO().getAllCocktails(); then the database will not even be accessed and thus not even created. That is just getting an instance of the database does not open the database, the open is delayed until an attempt is made to access the database.

    Summary of findings

    The issue, is as predicted, the asset. However it has nothing to do with the getAllCocktails method other than this is what causes the database to be opened and thus the copy of the asset then the opeing of the database.

    In this case, as the asset is first copied to a temporary database and then to the actual Room database, the exception was (it is believed) the copy from the asset to the actual database where the exception occurred.

    The actual issue being due to discrepancies between the database schema expected (actually required) by Room and the schema of the asset.

    As is always suggested, rather than trying to predict Room VERY STRICT schema requirements, the schema that is available in the generated after successfully compiling the project, should be used.

    See fix below for how this specific issue can be resolved.

    It won't appear to be an issue until you actually try to retrieve the data and hence why the issue only appears when you introduce the data from the asset.

    You have two options:-

    1. modify the @Entity annotated class to allow nulls for the column(s), or
    2. modify the source data to not have nulls.

    You may wish to modify your question to include:-

    1. The @Entity annotated class or classes.
    2. The @Dao annotated class.

    Working example showing the issue is very likely with the asset

    Created AS project using your code (other than using MainActivity instead of PedirTragoActivity) and altered MainActivity to be:-

    public class MainActivity extends AppCompatActivity {
    
        AppDatabase db;
        String TAG = "DBINFO";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            db = AppDatabase.getInstance(this.getApplication());
            logAllCocktails(db.cocktailDAO().getAllCocktails(),"STG01");
            db.cocktailDAO().insertCocktail(new CocktailEntity("C1",false,"Blah1"));
            db.cocktailDAO().insertCocktail(new CocktailEntity("C2",true,"Blah2"));
            db.cocktailDAO().insertCocktail(new CocktailEntity("C3",false,"Blah3"));
            logAllCocktails(db.cocktailDAO().getAllCocktails(),"STG02");
            db.close();
        }
    
        void logAllCocktails(List<CocktailEntity> allCocktails,String tag_suffix) {
            Log.d(TAG +tag_suffix,"Starting Log of All Cocktails where supplied list has " + allCocktails.size() + " items.");
            for (CocktailEntity ce: allCocktails) {
                Log.d(
                        TAG+tag_suffix,
                        "Cocktail Name is " + ce.getName() + " HasIce is " + ce.isHasIce() + " ID is " + ce.getId() + " ImageName is " + ce.getImgName()
                );
            }
        }
    }
    

    Ran the above twice with createFromAsset commented out. Log showed first 0 Cocktails, the after the 3 inserts 3 Cocktails. Second run showed 3 and 6.

    Note the addition of the close (this to force the WAL to be committed so just one file).

    Used Device Explorer to copy the database file into the assets folder and then into the assets/database folder as test.db e.g. :-

    enter image description here

    Uninstalled the App included the createFromAsset code and reran:-

    Resultant Log:-

    2023-09-24 07:51:34.929 21370-21370/a.a.so77164866javaroomnpefromasset D/DBINFOSTG01: Starting Log of All Cocktails where supplied list has 6 items.
    2023-09-24 07:51:34.929 21370-21370/a.a.so77164866javaroomnpefromasset D/DBINFOSTG01: Cocktail Name is C1 HasIce is false ID is 1 ImageName is null
    2023-09-24 07:51:34.929 21370-21370/a.a.so77164866javaroomnpefromasset D/DBINFOSTG01: Cocktail Name is C2 HasIce is true ID is 2 ImageName is null
    2023-09-24 07:51:34.929 21370-21370/a.a.so77164866javaroomnpefromasset D/DBINFOSTG01: Cocktail Name is C3 HasIce is false ID is 3 ImageName is null
    2023-09-24 07:51:34.929 21370-21370/a.a.so77164866javaroomnpefromasset D/DBINFOSTG01: Cocktail Name is C1 HasIce is false ID is 4 ImageName is null
    2023-09-24 07:51:34.929 21370-21370/a.a.so77164866javaroomnpefromasset D/DBINFOSTG01: Cocktail Name is C2 HasIce is true ID is 5 ImageName is null
    2023-09-24 07:51:34.929 21370-21370/a.a.so77164866javaroomnpefromasset D/DBINFOSTG01: Cocktail Name is C3 HasIce is false ID is 6 ImageName is null
    2023-09-24 07:51:34.953 21370-21370/a.a.so77164866javaroomnpefromasset D/DBINFOSTG02: Starting Log of All Cocktails where supplied list has 9 items.
    2023-09-24 07:51:34.953 21370-21370/a.a.so77164866javaroomnpefromasset D/DBINFOSTG02: Cocktail Name is C1 HasIce is false ID is 1 ImageName is null
    2023-09-24 07:51:34.953 21370-21370/a.a.so77164866javaroomnpefromasset D/DBINFOSTG02: Cocktail Name is C2 HasIce is true ID is 2 ImageName is null
    2023-09-24 07:51:34.953 21370-21370/a.a.so77164866javaroomnpefromasset D/DBINFOSTG02: Cocktail Name is C3 HasIce is false ID is 3 ImageName is null
    2023-09-24 07:51:34.953 21370-21370/a.a.so77164866javaroomnpefromasset D/DBINFOSTG02: Cocktail Name is C1 HasIce is false ID is 4 ImageName is null
    2023-09-24 07:51:34.953 21370-21370/a.a.so77164866javaroomnpefromasset D/DBINFOSTG02: Cocktail Name is C2 HasIce is true ID is 5 ImageName is null
    2023-09-24 07:51:34.953 21370-21370/a.a.so77164866javaroomnpefromasset D/DBINFOSTG02: Cocktail Name is C3 HasIce is false ID is 6 ImageName is null
    2023-09-24 07:51:34.953 21370-21370/a.a.so77164866javaroomnpefromasset D/DBINFOSTG02: Cocktail Name is C1 HasIce is false ID is 7 ImageName is null
    2023-09-24 07:51:34.953 21370-21370/a.a.so77164866javaroomnpefromasset D/DBINFOSTG02: Cocktail Name is C2 HasIce is true ID is 8 ImageName is null
    2023-09-24 07:51:34.953 21370-21370/a.a.so77164866javaroomnpefromasset D/DBINFOSTG02: Cocktail Name is C3 HasIce is false ID is 9 ImageName is null
    
    • i.e. NO NPE Crash
    • Originally the 6 rows from the previous runs, then
    • 9 rows after 3 new rows inserted.
    • Note the constrcutor public CocktailEntity(String name, boolean hasIce, String imaName) was used, hence the nulls for imageName (and that these being null are not an issue)

    Edit using downloaded mediafile test.db

    In short this is fine and works (at both Version 1 and Version 7).

    As such the issue does not appear to be with the supplied code (database wise) nor with the file itself.

    i.e. at Version 7, for a fresh install then the log (as per the code above) results in :-

    2023-09-24 12:01:19.596 D/DBINFOSTG01: Starting Log of All Cocktails where supplied list has 5 items.
    2023-09-24 12:01:19.596 D/DBINFOSTG01: Cocktail Name is campari HasIce is true ID is 1 ImageName is campari
    2023-09-24 12:01:19.596 D/DBINFOSTG01: Cocktail Name is fernet HasIce is true ID is 2 ImageName is fernet
    2023-09-24 12:01:19.596 D/DBINFOSTG01: Cocktail Name is gin tonic HasIce is true ID is 3 ImageName is gintonic
    2023-09-24 12:01:19.596 D/DBINFOSTG01: Cocktail Name is ron cola HasIce is true ID is 4 ImageName is roncola
    2023-09-24 12:01:19.596 D/DBINFOSTG01: Cocktail Name is sex On  the beach HasIce is true ID is 5 ImageName is sexOnTheBeach
    2023-09-24 12:01:19.608 D/DBINFOSTG02: Starting Log of All Cocktails where supplied list has 8 items.
    2023-09-24 12:01:19.608 D/DBINFOSTG02: Cocktail Name is campari HasIce is true ID is 1 ImageName is campari
    2023-09-24 12:01:19.608 D/DBINFOSTG02: Cocktail Name is fernet HasIce is true ID is 2 ImageName is fernet
    2023-09-24 12:01:19.608 D/DBINFOSTG02: Cocktail Name is gin tonic HasIce is true ID is 3 ImageName is gintonic
    2023-09-24 12:01:19.608 D/DBINFOSTG02: Cocktail Name is ron cola HasIce is true ID is 4 ImageName is roncola
    2023-09-24 12:01:19.609 D/DBINFOSTG02: Cocktail Name is sex On  the beach HasIce is true ID is 5 ImageName is sexOnTheBeach
    2023-09-24 12:01:19.609 D/DBINFOSTG02: Cocktail Name is C1 HasIce is false ID is 6 ImageName is null
    2023-09-24 12:01:19.609 D/DBINFOSTG02: Cocktail Name is C2 HasIce is true ID is 7 ImageName is null
    2023-09-24 12:01:19.609 D/DBINFOSTG02: Cocktail Name is C3 HasIce is false ID is 8 ImageName is null
    

    Therefore the issue is perhaps likely to the differences between the two Apps, which could be many.

    • The device (works on AS emulator for 10.1 device API 28)
    • The Activity (very simple initial Activity without anything special layout wise) i.e. the layouts for the Activity are different.
    • You have Entities commented out in the posted code BUT do you have the other entities excluded when testing/running? if not then the log indicates Foreign Key activity. So it may be that the issue is due to NULL being an invalid Foreign Key.
      • error is immediately after at androidx.room.util.TableInfoKt.readForeignKeyFieldMappings(TableInfo.kt:536)
      • kt perhaps indicates Kotlin code, for a java App????

    Edit Adding additional Entities

    • Add BottleEntity, no issues after run.
    • Add BottleIngredientEntity, requires IngredientTypeEntity.
    • Add IngredientTypeEntity NPE cursor.getString(toColumnIndex) must not be null

    So issue is with IngredientTypeEntity/BottleIngredientEnitity

    • commented out FKEY definitions, issue remains.
    • commented out IngredientTYpeEntity, issue remains.
    • commented out BottleIngredientEntity, re-introduced IngredientTypeEntity, no issues after run.

    As such issue very much appears to be with BottleIngredientEntity.

    - note uninstalling App prior to each run.
    

    At this stage comment out createFromAsset to see if issue is with schema rather than data

    • include db.getOpenHelper().getWritableDatabase(); to force open of the database.

    • exclude inserts and logging as probably not an issue.

    • run App, no issue.

    • reintroduce BottleIngredientEntity and run App, not an issue.

    • reintroduce FKEY definitions for BottleIngredientEntity and run App, not an issue.

    So the issue very much appears to be the BottleIngredientEntity and how Room manages handling the asset. iirc that a temp db is used which is then copied.

    • Compare schemas BottleIngredient table:-

    Asset is:-

    CREATE TABLE "bottle_ingredient"
    (
        id           INTEGER not null
            constraint bottle_ingredient_pk
                primary key,
        bottlePos    INTEGER not null
            constraint bottle_ingredient_bottles_position_fk
                references bottles,
        ingredientId INTEGER not null
            constraint bottle_ingredient_ingredient_types_id_fk
                references ingredient_types
    )
    

    Room is :-

    CREATE TABLE `bottle_ingredient` (
        `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 
        `bottlePos` INTEGER NOT NULL, 
        `ingredientId` INTEGER NOT NULL, 
        FOREIGN KEY(`bottlePos`) REFERENCES `bottles`(`position`) ON UPDATE NO ACTION ON DELETE NO ACTION , 
        FOREIGN KEY(`ingredientId`) REFERENCES `ingredient_types`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION 
    )
    
    • I suspect that even without the NPE issue that an Expected but Found exception would eventuate.

    Advised fix


    My suggestion is to drop using the asset you currently have and use a Tool (know nothing about Datagrip) where YOU create the schema in accordance with Room and populate the data accordingly.

    That is:-

    1. compile the project then inspect the java(generated) (visible from Android Studio's Android View)
    2. locate the AppDatabase_Impl class.
    3. find the createAllTables method in the class and copy the SQL for creating the tables (no need to create room_master_table or insert into it).
    4. change the database version, via the tool or SQL to version 7
    5. populate the tables as required.
    6. save the database ensuring that there is a single file (i.e. no -wal or -shm file) (e.g. with Navicat you have to close navicat for it to fully commit).
    7. then copy this file into the asset.

    note DO NOT turn Foreign Keys off, I suspect that the column cannot be null is due to an invalid reference in the data that you load and that this exception occurs as part of the copying of the asset from the temp to actual db.

    example of getting the CREATE SQL :-

    enter image description here



    FINAL FIX


    As per the above, I believe the core issue is that the SCHEMA of your asset database does not match what Room expects BUT this is masked due to an exception as part of the asset copy when copying the asset to the final Room database from the temporary initial copy.

    So the fix is to use the expected schema, the SQL for which is available in the generate java in the createAllTables method of the AppDatabase_Impl class (i.e. the @Database annotated class suffixed with _Impl).

    To utilise the existing data in the asset, then a conversion can be run. This will rename the existing tables, create the new tables as per the generated SQL and then load the data from the renamed tables. Additionally it will set the user_version (the database version) to 7 (to ensure that fallback doesn't clear the database as there appears to no Migrations, so a version less than 7 would then expect a Migration but in the absence clear the database).

    The SQL script being:-

    SELECT * FROM pragma_user_version;
    /* RUN ALTERS ONCE ONLY ELSE WILL FAIL OR COPY POTENTIALLY NOT ORIGINAL DATA */
    /* COMMENTED OUT AS ALREADY DO ONCE */
    /*
    ALTER TABLE bottles RENAME TO bottles_old;
    ALTER TABLE bottle_ingredient RENAME TO bottle_ingredient_old;
    ALTER TABLE cocktail_ingredients RENAME TO cocktail_ingredients_old;
    ALTER TABLE cocktails RENAME TO cocktails_old;
    ALTER TABLE ingredient_types RENAME TO ingredient_types_old;
    */
     /* Optional DROPS but ensures tables are recreated */
    DROP TABLE IF EXISTS `cocktail_ingredients`; /* best to drop tables with FKEYS first */
    DROP TABLE IF EXISTS `bottle_ingredient`; /* best to drop tables with FKEYS first */
    DROP TABLE IF EXISTS `cocktails`;
    DROP TABLE IF EXISTS `bottles`;
    DROP TABLE IF EXISTS ingredient_types;
    CREATE TABLE IF NOT EXISTS `cocktails` (
        `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 
        `name` TEXT, `isOnStock` INTEGER NOT NULL, 
        `hasIce` INTEGER NOT NULL, `imgName` TEXT
    );
    CREATE TABLE IF NOT EXISTS `bottles` (
        `position` INTEGER NOT NULL, `name` TEXT, 
        `capacity` INTEGER NOT NULL, 
        `currentAmount` INTEGER NOT NULL, 
        PRIMARY KEY(`position`)
    );
    /* NOTE MOVED TO BEFORE bottle_ingredients */
    CREATE TABLE IF NOT EXISTS `ingredient_types` (
        `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 
        `name` TEXT
    );
    CREATE TABLE IF NOT EXISTS `bottle_ingredient` (
        `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 
        `bottlePos` INTEGER NOT NULL, 
        `ingredientId` INTEGER NOT NULL, 
        FOREIGN KEY(`bottlePos`) REFERENCES `bottles`(`position`) ON UPDATE NO ACTION ON DELETE NO ACTION , 
        FOREIGN KEY(`ingredientId`) REFERENCES `ingredient_types`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION
    );
    CREATE TABLE IF NOT EXISTS `cocktail_ingredients` (
        `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 
        `typeId` INTEGER NOT NULL, 
        `quantity` INTEGER NOT NULL, 
        `cocktailId` INTEGER NOT NULL, 
        FOREIGN KEY(`typeId`) REFERENCES `ingredient_types`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , 
        FOREIGN KEY(`cocktailId`) REFERENCES `cocktails`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION 
    );
    INSERT INTO cocktails SELECT * FROM cocktails_old;
    INSERT INTO bottles SELECT * FROM bottles_old;
    INSERT INTO ingredient_types SELECT * FROM ingredient_types_old;
    INSERT INTO bottle_ingredient SELECT * FROM bottle_ingredient_old;
    INSERT INTO cocktail_ingredients SELECT * FROM cocktail_ingredients_old;
    PRAGMA user_version = 7;
    SELECT * FROM pragma_user_version;
    
    • Note that Navicat was used, Navicat allows multiple statements to be executed and also multiple outputs.
    • Please read comments ESPECIALLY that the ALL important ALTER statements have been commented out.

    Once converted (and checked for the correct/expected data) then save the database file, ensuring that there is no -wal or -shm file (with Navicat you have to close/end Navicat for it to close the file). Then copy the file into the asset and all should be fine.

    • Note you may wish to drop the ????_old tables (but Room will not care that they exist, but they will waste space (minimum 4k per compnent (table index ....))).

    After following the above, uninstalling the App and running then the log (inserts commented out):-

    2023-09-24 14:01:14.970 D/DBINFOSTG02: Starting Log of All Cocktails where supplied list has 5 items.
    2023-09-24 14:01:14.970 D/DBINFOSTG02: Cocktail Name is campari HasIce is true ID is 1 ImageName is campari
    2023-09-24 14:01:14.970 D/DBINFOSTG02: Cocktail Name is fernet HasIce is true ID is 2 ImageName is fernet
    2023-09-24 14:01:14.970 D/DBINFOSTG02: Cocktail Name is gin tonic HasIce is true ID is 3 ImageName is gintonic
    2023-09-24 14:01:14.970 D/DBINFOSTG02: Cocktail Name is ron cola HasIce is true ID is 4 ImageName is roncola
    2023-09-24 14:01:14.970 D/DBINFOSTG02: Cocktail Name is sex On  the beach HasIce is true ID is 5 ImageName is sexOnTheBeach
    

    Using App Inspection (to run a query) shows:-

    enter image description here

    • 0

相关问题

  • 滚动 Recyclerview 应覆盖工具栏

  • 底部像素溢出并且导航功能不起作用

  • 从列表中选择一种颜色,在 Android 中找不到数组

  • 将 MapLibre 添加到新的 Android 项目不起作用

  • 我应该将矢量图像放入资源还是绘图中?我的应用程序中有数千个向量

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    使用 <font color="#xxx"> 突出显示 html 中的代码

    • 2 个回答
  • Marko Smith

    为什么在传递 {} 时重载解析更喜欢 std::nullptr_t 而不是类?

    • 1 个回答
  • Marko Smith

    您可以使用花括号初始化列表作为(默认)模板参数吗?

    • 2 个回答
  • Marko Smith

    为什么列表推导式在内部创建一个函数?

    • 1 个回答
  • Marko Smith

    我正在尝试仅使用海龟随机和数学模块来制作吃豆人游戏

    • 1 个回答
  • Marko Smith

    java.lang.NoSuchMethodError: 'void org.openqa.selenium.remote.http.ClientConfig.<init>(java.net.URI, java.time.Duration, java.time.Duratio

    • 3 个回答
  • Marko Smith

    为什么 'char -> int' 是提升,而 'char -> Short' 是转换(但不是提升)?

    • 4 个回答
  • Marko Smith

    为什么库中不调用全局变量的构造函数?

    • 1 个回答
  • Marko Smith

    std::common_reference_with 在元组上的行为不一致。哪个是对的?

    • 1 个回答
  • Marko Smith

    C++17 中 std::byte 只能按位运算?

    • 1 个回答
  • Martin Hope
    fbrereto 为什么在传递 {} 时重载解析更喜欢 std::nullptr_t 而不是类? 2023-12-21 00:31:04 +0800 CST
  • Martin Hope
    比尔盖子 您可以使用花括号初始化列表作为(默认)模板参数吗? 2023-12-17 10:02:06 +0800 CST
  • Martin Hope
    Amir reza Riahi 为什么列表推导式在内部创建一个函数? 2023-11-16 20:53:19 +0800 CST
  • Martin Hope
    Michael A fmt 格式 %H:%M:%S 不带小数 2023-11-11 01:13:05 +0800 CST
  • Martin Hope
    God I Hate Python C++20 的 std::views::filter 未正确过滤视图 2023-08-27 18:40:35 +0800 CST
  • Martin Hope
    LiDa Cute 为什么 'char -> int' 是提升,而 'char -> Short' 是转换(但不是提升)? 2023-08-24 20:46:59 +0800 CST
  • Martin Hope
    jabaa 为什么库中不调用全局变量的构造函数? 2023-08-18 07:15:20 +0800 CST
  • Martin Hope
    Panagiotis Syskakis std::common_reference_with 在元组上的行为不一致。哪个是对的? 2023-08-17 21:24:06 +0800 CST
  • Martin Hope
    Alex Guteniev 为什么编译器在这里错过矢量化? 2023-08-17 18:58:07 +0800 CST
  • Martin Hope
    wimalopaan C++17 中 std::byte 只能按位运算? 2023-08-17 17:13:58 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve