代码之家  ›  专栏  ›  技术社区  ›  kar

SQLite DB在移动设备上未找到,但在仿真器上工作

  •  3
  • kar  · 技术社区  · 7 年前

    我已经创建了一个由一个表组成的sqlite数据库,该数据库填充了大约2000行。

    我可以查询这个表,当我通过仿真器进行查询时,一切正常。

    但当我在移动设备上测试时,它会抛出以下错误:

    android.database.sqlite.sqliteexception:没有这样的表:person(代码 1:,编译时:从rowid=292的person中选择name

    当我尝试在一个设备上,我期待我的填充SQLite数据库可以自动在我的设备上可用,但是基于上面的错误,看起来不是这样。

    我确实看过过去的问题,但它们与我的问题不匹配。

    1. 我没有为数据库存储位置设置自己的路径。

      当我在设备文件资源管理器下查找时,数据库的路径是 /data/data/com.somepackage.myappname/databases/person

    2. 我试过卸载应用程序并重新安装它,但没有什么区别。

    我的sdk安装详细信息(如果相关)。

    明斯克版本16

    目标版本27

    移动设备:使用Android 8.0.0版

    请告知我如何在安装应用程序时(当我单击android studio上的run时)自动附带数据库。

    这就是我如何将数据加载到数据库中。这只运行了一次,我目前已经注释掉了这段代码。

        try {
            SQLiteDatabase database = this.openOrCreateDatabase("person", MODE_PRIVATE, null);
            database.execSQL("DROP TABLE IF EXISTS person");
            database.execSQL("CREATE TABLE IF NOT EXISTS person (name VARCHAR, name_size INT(8))");
    
            BufferedReader br = new BufferedReader(new InputStreamReader(getAssets().open("person.txt")));
            String line;
            while ((line = br.readLine()) != null) {
                String sql = "INSERT INTO person (name, name_size) VALUES ('" + line + "', " + line.length() + ")";
                database.execSQL(sql);
            }database.close();
        }
        catch (Exception e){
            e.printStackTrace();
        }  
    

    我在oncreate方法下初始化数据库。

    database = this.openOrCreateDatabase("person", MODE_PRIVATE, null);
    

    单击按钮时,将执行以下方法。 错误出现在该方法的第一行。

    private String retrieveNextPerson(int randomIndex){
            //error on this raw query
            Cursor cursor = database.rawQuery("SELECT name from person WHERE rowid = " + randomIndex, null);
            int wordIndex = cursor.getColumnIndex("name");
            cursor.moveToFirst();
            return cursor.getString(wordIndex);
        }
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   MikeT    7 年前

    假设您没有错误地认为在模拟器(或任何设备)上运行应用程序将更改包,以便分发将包括填充的数据库

    • 分发预填充的数据库涉及

      • a)填充数据库( 通常使用sqlite管理工具 )我是说,
      • b)复制此( 作为数据库的文件 )进入资产文件夹,然后:
      • c)从assets文件夹中检索。

        • 使用 SQLiteAssetHelper 让事情变得简单, 注意到 SQLiteAssethelper DB文件需要存在于数据库文件夹中(您很可能需要创建此文件) )中。

    那么我怀疑你是在过早地调用:

     database = this.openOrCreateDatabase("person", MODE_PRIVATE, null);
    

    这样做将创建没有person表的person数据库,从而导致所描述的失败。

    在使用上述行之前,需要加载数据。

    或者,如果您在紧接着 database = this.openOrCreateDatabase("person", MODE_PRIVATE, null);

    Cursor csr = database.query("sqlite_master",null,"name='person'",null,null,null,null);
    if (csr.getCount() < 1) {
        database.execSQL("CREATE TABLE IF NOT EXISTS person (name VARCHAR, name_size INT(8))");
    ........ rest of the code that inserts data from the person.txt asset
    }
    

    将创建表。但是,它是空的 (您可以从person.txt资产复制数据)

    补充-重新评论:

    谢谢你的回复。不知道你是否错过了我提到的那部分 数据库创建已经完成,该部分已被注释 出去。我只调用了一次db创建,并加载了数据和db 只是坐在应用程序中(至少对于模拟器而言)。这个 您提到的初始化应该使用 因此,我不明白为什么这么做还为时过早。

    下面是对您的代码的一个非常可靠的重新编写,它将满足我认为最可能的潜在问题:

    public class MainActivity extends AppCompatActivity {
    
        public static final String DBNAME = "person";
        public static final String TBNAME = "person";
        public static final String COL_NAME = "name";
        public static final String COL_NAME_SIZE = "name_size";
        public static final String ASSET_FILENAME = "person.txt";
    
        public static final String SQLITE_MASTER_TABLE = "sqlite_master";
        public static final String COL_SQLITE_MATSER_NAME = "name";
    
        static final int MIMINUM_ROWS_IN_PERSONTABLE = 1;
    
        SQLiteDatabase db;
        BufferedReader br;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            checkPersonTable(); // Notes sets db either way
    
            // FOR TESTING
            long rows_in_person_table = DatabaseUtils.queryNumEntries(db,TBNAME);
            Log.d(
                    "PERSON ROW COUNT",
                    "The number of rows in the " +
                            TBNAME +
                            " table is " +
                            String.valueOf(rows_in_person_table)
            );
        }
    
    
        private void checkPersonTable() {
    
            db = this.openOrCreateDatabase(DBNAME, Context.MODE_PRIVATE,null);
            // Database will now exist but it may or may not contain the person table so check sqlite_master
            Cursor csr = db.query(
                    SQLITE_MASTER_TABLE,
                    new String[]{COL_SQLITE_MATSER_NAME},
                            COL_SQLITE_MATSER_NAME + "=?",
                            new String[]{TBNAME},
                            null,null,null
            );
            // Cursor will contain 1 row if the person table exists so check count
            int person_table_count = csr.getCount();
            csr.close();
            // Before attemtping to create the Person table ensure that the assets file exists
            // If not then throw a RunTime exception
    
            if (person_table_count < 1) {
                try {
                    if (!Arrays.asList(getResources().getAssets().list("")).contains(ASSET_FILENAME)) {
                        StringBuilder sb = new StringBuilder();
                        throw new RuntimeException("Asset file " +
                                ASSET_FILENAME +
                                " not found in the assets folder." +
                                " The following assets were found" +
                                sb
                        );
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
            if (person_table_count < 1) {
                db.execSQL("CREATE TABLE IF NOT EXISTS " + TBNAME +
                        "(" +
                        COL_NAME + " TEXT," +
                        COL_NAME_SIZE + " INTEGER" +
                        ")"
                );
                loadPersonsFromAssets();
            } else {
                // <<<<<<<<<< NOTE Optional will load data from assets if miminum nuber of rows
                //                 aren't in the person table
                if (DatabaseUtils.queryNumEntries(db,TBNAME) < MIMINUM_ROWS_IN_PERSONTABLE) {
                    loadPersonsFromAssets();
                }
            }
        }
    
        // Load the person table from the Assets File
        private void loadPersonsFromAssets() {
            try {
                BufferedReader br = new BufferedReader(new InputStreamReader(getAssets().open(ASSET_FILENAME)));
                String line, sql;
                int lines_read = 0;
                db.beginTransaction();
                while ((line = br.readLine()) != null) {
                    sql = "INSERT INTO " + TBNAME + " VALUES('" + line + "'," + String.valueOf(line.length()) + ")";
                    db.execSQL(sql);
                    lines_read++;
                }
                db.setTransactionSuccessful();
                db.endTransaction();
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException("Asset File " + ASSET_FILENAME + " not found in the assets folder.");
            }
        }
    }
    

    这将:

    • 只有在设置sqlitedatabase对象后才尝试打开数据库。
    • 将创建 如果数据库不存在,那么它将创建人表。
    • 即使数据库存在,它也会继续检查表是否存在,如果不存在,它将创建该表。
    • 异常是如果资产文件不存在于资产文件夹中,在这种情况下,将引发运行时异常(如果缺少此异常,则会出现严重错误,因为它应该始终存在,因为它是包的一部分)。
    • 它还将在创建表时填充该表,如果有两行,则填充该表(取决于 拟人行 )中。

    资产文件是否 个人.txt 不存在,则会出现类似于以下情况的异常:

    06-10 03:58:43.503 3097-3097/personthing.so50777840 E/AndroidRuntime: FATAL EXCEPTION: main
        java.lang.RuntimeException: Unable to start activity ComponentInfo{personthing.so50777840/personthing.so50777840.MainActivity}: java.lang.RuntimeException: Asset file person.txt not found in the assets folder. The following assets were found
             found asset file :- images
             found asset file :- notperson.txt
             found asset file :- sounds
             found asset file :- webkit
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
            at android.app.ActivityThread.access$600(ActivityThread.java:130)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:4745)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
            at dalvik.system.NativeStart.main(Native Method)
         Caused by: java.lang.RuntimeException: Asset file person.txt not found in the assets folder. The following assets were found
             found asset file :- images
             found asset file :- notperson.txt
             found asset file :- sounds
             found asset file :- webkit
            at personthing.so50777840.MainActivity.checkPersonTable(MainActivity.java:83)
            at personthing.so50777840.MainActivity.onCreate(MainActivity.java:39)
            at android.app.Activity.performCreate(Activity.java:5008)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
                ... 11 more
    
    • 注意 可以看到,person.txt已经 “错误地” 命名的 notperson.txt文件 强迫错误。

    注意在这个阶段数据库将存在(由于 openOrCreateDatabase )它将包含两个表(表和表),但不包含人表:—

    enter image description here

    但是,创建正确的资产文件 个人.txt (将notperson.txt重命名为person.text)将创建表并加载数据:

    例如,如果person.txt是:

    enter image description here

    然后运行应用程序将导致日志包含:

    06-10 04:39:04.277 3325-3325/? D/PERSON ROW COUNT: The number of rows in the person table is 11