sqlite db在移动设备上找不到但在仿真器上运行

时间:2018-06-09 19:35:20

标签: java android sqlite

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

我可以查询此表,当我通过模拟器执行此操作时,一切正常。

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

  

android.database.sqlite.SQLiteException:没有这样的表:person(代码   1):,同时编译:从人WHERE rowid = 292

中选择SELECT名称

当我在设备上试用它时,我希望我的设备上自动提供我的填充sqlite数据库,但基于上述错误,看起来并非如此。

  

我确实查看了过去的问题,但这些问题与我的问题不符。

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

         
        

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

      
  2.   
  3. 我尝试卸载该应用程序并重新安装它并没有什么区别。

  4.   

我的sdk设置细节(如果相关)。

  

minSdkVersion 16

     

targetSdkVersion 27

     

移动设备:使用Android 8.0.0版

请告知我如何在安装时自动附带应用程序(当我在Android Studio上单击运行时)。

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

    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 个答案:

答案 0 :(得分:1)

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

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

    • a)填充数据库(通常使用SQLite管理工具),
    • b)将此(文件作为数据库)复制到assets文件夹中,然后: -
    • c)从assets文件夹中检索它。

      • 使用SQLiteAssetHelper使这很容易,注意到SQLiteAssethelper数据库文件需要存在于数据库文件夹中(您很可能需要创建此文件)) 。

然后我怀疑你是在过早地调用: -

 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对象时才尝试打开数据库。
  • 将创建数据库(如果该数据库不存在),然后它将创建人员表。
  • 即使数据库存在,它也会继续检查表是否存在,如果不存在则会创建表。
  • 例外情况是资产文件夹中不存在资产文件,在这种情况下会引发运行时异常(好像缺少这种情况会出现严重错误,因为它应该始终存在,因为它是封装)。
  • 如果有两行(取决于 MIMINUM_ROWS_IN_PERSONTABLE 的值),它还会在创建时填充表格或填充表格。

如果资产文件 person.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),它将包含两个表(sqlite_master和android_metadata),但不包含人员表,例如: -

enter image description here

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

e.g。如果person.txt是: -

enter image description here

然后运行App将导致日志包含: -

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