android - 使用从 Android 上的 Assets 文件夹复制的 sqlite 数据库时出现的问题

标签 android

虽然我们通常得到好评,但以下错误堆积如山,让我们感到悲痛:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.svs.missions.MissionsGalleryView}: android.database.sqlite.SQLiteException: no such table: missions: , while compiling: SELECT * FROM missions WHERE banner is not null order by title COLLATE NOCASE
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2787)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2803)
at android.app.ActivityThread.access$2300(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2136)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:144)
at android.app.ActivityThread.main(ActivityThread.java:4937)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.database.sqlite.SQLiteException: no such table: missions: , while compiling: SELECT * FROM missions WHERE banner is not null order by title COLLATE NOCASE
at android.database.sqlite.SQLiteCompiledSql.native_compile(Native Method)
at android.database.sqlite.SQLiteCompiledSql.compile(SQLiteCompiledSql.java:91)
at android.database.sqlite.SQLiteCompiledSql.<init>(SQLiteCompiledSql.java:64)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:80)
at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:46)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:53)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1409)
at android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1293)
at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1248)
at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1328)
...

从 assets 文件夹复制数据库时,似乎并没有创建所有表。这是市场面板中一位用户的反馈消息:

“Whenever I click on "missions" the app force closes. all other links seem ok.”

所以真的是碰碰运气。对于某些用户来说,似乎没有任何表格被复制。

我很想完全删除数据库副本并在启动时创建数据库,但我仍然不能保证会创建数据库(并且不会获得应用程序附带的任何元数据,除非我们在发布时下载它,顺便说一句,有很多数据)。虽然对我来说似乎有点傻。支持这么多不同的平台。如此脱节。

有趣的是,我在每次启动时调用表创建代码只是为了确保数据库表存在,但它并没有修复它(这里是 fragment ):

   this.openDB();
    db.execSQL("CREATE TABLE  if not exists missions (_id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, description TEXT, created TEXT, orgHTML TEXT, UNIQUE(id) ON CONFLICT IGNORE);");
...
this.closeDB();

我发现了这个:

http://www.anddev.org/networking-database-problems-f29/missing-table-in-sqlite-with-specific-version-of-desire-hd-t50364.html

并且我已经应用了解决方法,但仍然收到错误报告。

我不确定它是否只在 HTC 设备上,只是按照上面那个论坛帖子的引导。

背景:

数据库位于 Assets 文件夹中。它有 2.8mb 大,我分配了一个 .mp3 扩展名以避免压缩,以便它可以复制(修复一个众所周知的旧问题)。

我还没有添加的一件事是检查可用空间,但那将是下一个。如果我想没有足够的可用空间,我可能只是将整个数据库创建为空。但是,如果在复制 Assets 文件夹数据库时它用完了可用空间,我认为数据库应该已损坏。

顺便说一句:Oncreate 和 Onupgrade 目前是空的:

@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
  }

@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}

这适用于我们所有的测试设备:

HTC Aria,2.1,占用空间小,16mb 堆

原始机器人,2.2.1

三星银河,2.2

华硕平板电脑(没有型号),3.0

Xoom,3.1

DB 类扩展了 sqliteopenhelper:

public class DBManager extends SQLiteOpenHelper {

这是使用的代码(由于我们的用户还没有联系我们,不幸的是我们不知道 Log.e 写的是什么):

  ... 

    private static final String DB_NAME = "db.mp3";
    private static final String DB_PATH = "/data/data/com.svs/databases/";

     ... 

    public boolean createNewDatabaseFromAsset() {
        File file = new File(DB_PATH , DB_NAME);
        if (file.exists()) {
            return true;
        }
        SQLiteDatabase db_Read = null;
        db_Read=this.getReadableDatabase();
         db_Read.close(); 

         try {
            InputStream assetsDB = this.context.getAssets().open(DB_NAME);
            OutputStream dbOut = new FileOutputStream(DB_PATH + DB_NAME);

            byte[] buffer = new byte[1024];
            int length;
            while ((length = assetsDB.read(buffer)) > 0) {
                dbOut.write(buffer, 0, length);
            }

            dbOut.flush();
            dbOut.close();
            assetsDB.close();
            this.buildTables();


            Log.i(TAG, "New database created...");
            return true;
        } catch (IOException e) {
            Log.e(TAG, "IO Error. Could not create new database...");
            e.printStackTrace();
               this.buildTables();
            return false;
        } catch (SQLiteException e) {
            Log.e(TAG, "Database Locked. Could not create new database...");
            e.printStackTrace();
               this.buildTables();
            return false;
        }

   }

    public DBManager openDB() {
           if (!createNewDatabaseFromAsset())
            return null;
           if (db==null){
               dbManager = new DBManager(context);
            db = dbManager.getWritableDatabase();
           }
        return this;
    }

最佳答案

我想我会更新这个答案,因为它有点旧了。 至少在平板电脑上,从 android API 19 开始,您可以拥有多个用户。 Nexus 7 上的这些帐户至少进入目录/data/users/10/

您现在必须执行以下操作:

InputStream input = this.context.getAssets().open(DATABASE_NAME);
File dbFile = context.getDatabasePath(DATABASE_NAME);
dbFile.getParentFile().mkdir();
dbFile.createNewFile();
OutputStream output = new FileOutputStream(dbFile.getAbsolutePath());

因此您不能假设您的应用程序的路径静态位于/data/data//databases。

关于android - 使用从 Android 上的 Assets 文件夹复制的 sqlite 数据库时出现的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6636705/

相关文章:

android - 使用 adb 获取 2 个设备的完整日志

android - 关于主要 Activity : 'illegal start of expression' 的错误消息

android - android 中的 java.lang.NoSuchMethodError : java. lang.System.arraycopy([CI[CII)V 错误

android - APK扩展名(OBB文件)和应用程序包之间的区别

android - 应用内计费 - 快速设备定位 - 导致崩溃(IllegalStateException)

android - 无法在 Selenium 中使用移动模拟 chromedriver 中的 click()

Android - OpenSL ES 高麦克风增益

Android “elevation” 在 CustomView 下没有显示阴影

java - 限制 jsoup 检索的内容

android - 像谷歌地图一样滑动 BottomSheet