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

时间:2011-07-09 18:35:25

标签: 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文件夹复制db时,似乎并未创建所有表。以下是来自市场小组中用户的一条反馈消息:

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

所以真的很受欢迎。对于某些用户,似乎没有任何表被复制。

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

有趣的是我在每次启动时调用表创建代码只是为了确保db表存在,并且它没有修复它(这里的代码片段):

   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设备,只是跟随上述论坛帖子的主角。

背景:

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

我尚未添加的一件事是检查可用空间,但接下来会是这样。如果我认为没有足够的可用空间,我可能只是创建整个数据库空。但是如果在复制资产文件夹db时它的可用空间不足,那么数据库应该被损坏我想。

BTW:Oncreate和Onupgrade目前是空的:

@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
  }

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

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

HTC Aria,2.1,占地面积小,16mb堆

Original Droid,2.2.1

三星Galaxy,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;
    }

3 个答案:

答案 0 :(得分:2)

我想我会更新这个答案,因为它有点旧。 至少在平板电脑上,从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 //数据库。

答案 1 :(得分:1)

对不起,留下了这个。

所以我最终决定检查并删除/创建第一次启动时复制的数据库中不存在的任何表(远程复制通常在包中提供的任何数据)。

这是一个我知道的黑客,但至少它已经过了我们无法解决的问题。

答案 2 :(得分:0)

看一下这篇文章here,它有一个很好的创建/复制db方法,它总是对我有用。还尝试将数据库切换成&lt; 1mb块然后重新组合 - 这就是我在处理大型数据库时所做的事情。 例如:

static private void CopyDatabase(Context Ctxt, File DBFile) throws IOException
{
AssetManager am = Ctxt.getAssets();
OutputStream os = new FileOutputStream(DBFile);
DBFile.createNewFile();
byte []b = new byte[1024];
int i, r;
String []Files = am.list("");
Arrays.sort(Files);
for(i=1;i<10;i++)
{
       String fn = String.format("%d.db", i);
    if(Arrays.binarySearch(Files, fn) < 0)
           break;
    InputStream is = am.open(fn);
    while((r = is.read(b)) != -1)
        os.write(b, 0, r);
    is.close();
}
os.close();
}

希望这有帮助!