从预填充数据库中读取数据时出错

error reading data from the pre-filled database

我有一个位于 assets/databases/ 的数据库。我使用库 android-sqlite-asset-helper 试图存档数据库,没有帮助。错误仍然存​​在

   E/SQLiteAssetHelper: Couldn't open databases/brodsky.db for writing (will try read-only):
    com.readystatesoftware.sqliteasset.SQLiteAssetHelper$SQLiteAssetException: Missing databases/databases/brodsky.db file (or .zip, .gz archive) in assets, or target folder not writable
        at android.content.res.AssetManager.openAsset(Native Method)
        at android.content.res.AssetManager.open(AssetManager.java:336)
        at android.content.res.AssetManager.open(AssetManager.java:310)
        at com.readystatesoftware.sqliteasset.SQLiteAssetHelper.copyDatabaseFromAssets(SQLiteAssetHelper.java:436)
        at com.readystatesoftware.sqliteasset.SQLiteAssetHelper.createOrOpenDatabase(SQLiteAssetHelper.java:400)
        at com.readystatesoftware.sqliteasset.SQLiteAssetHelper.getWritableDatabase(SQLiteAssetHelper.java:176)
        at com.readystatesoftware.sqliteasset.SQLiteAssetHelper.getReadableDatabase(SQLiteAssetHelper.java:254)
        at rodionova.lyubov.brodsky.db.PoemsProvider.query(PoemsProvider.java:40)
        at android.content.ContentProvider.query(ContentProvider.java:1140)
        at android.content.ContentProvider$Transport.query(ContentProvider.java:262)
        at android.content.ContentResolver.query(ContentResolver.java:506)

数据库助手:

    public class PoemsDbHelper extends SQLiteAssetHelper {

    private static String DB_NAME = "databases/brodsky.db";
    private static final int DB_VERSION = 1;

    public PoemsDbHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }
}

还有一个 class ContentProvider,因为它也在日志中的错误中指定

public class PoemsProvider 扩展了 ContentProvider { private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH); 私人静态最终 int POEMS = 1; 私人静态最终 int POEM = 2; private static final int FACTS = 3; private static final int BIOGRAPHY = 4;

static {
    URI_MATCHER.addURI(PoemsContract.AUTHORITY, "poems", POEMS);
    URI_MATCHER.addURI(PoemsContract.AUTHORITY, "poems/#", POEM);
    URI_MATCHER.addURI(PoemsContract.AUTHORITY, "facts", FACTS);
    URI_MATCHER.addURI(PoemsContract.AUTHORITY, "biography", BIOGRAPHY);
}

private PoemsDbHelper poemsDbHelper;

@Override
public boolean onCreate() {
    poemsDbHelper = new PoemsDbHelper(getContext());
    return true;
}

@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
                    @Nullable String[] selectionArgs, @Nullable String sortOrder) {
    SQLiteDatabase db = poemsDbHelper.getReadableDatabase();
    switch (URI_MATCHER.match(uri)) {
        case POEMS:
            if (TextUtils.isEmpty(sortOrder)) {
                sortOrder = PoemsContract.Poems.COLUMN_ID + " DESC";
            }

            return db.query(PoemsContract.Poems.TABLE_NAME,
                    projection,
                    selection,
                    selectionArgs,
                    null,
                    null,
                    sortOrder);

        case POEM:
            String id = uri.getLastPathSegment();
            if (TextUtils.isEmpty(selection)) {
                selection = PoemsContract.Poems._ID + " = ?";
                selectionArgs = new String[]{id};
            } else {
                selection = selection + " AND " + PoemsContract.Poems._ID + " = ?";

                String[] newSelectionArgs = new String[selectionArgs.length + 1];

                System.arraycopy(selectionArgs, 0, newSelectionArgs, 0, selectionArgs.length);

                newSelectionArgs[newSelectionArgs.length - 1] = id;

                selectionArgs = newSelectionArgs;
            }
        case FACTS:
            if (TextUtils.isEmpty(sortOrder)) {
                sortOrder = PoemsContract.Facts.COLUMN_ID + " DESC";
            }

            return db.query(PoemsContract.Facts.TABLE_NAME,
                    projection,
                    selection,
                    selectionArgs,
                    null,
                    null,
                    sortOrder);
        case BIOGRAPHY:
            if (TextUtils.isEmpty(sortOrder)) {
                sortOrder = PoemsContract.Biography.COLUMN_ID + " DESC";
            }

            return db.query(PoemsContract.Biography.TABLE_NAME,
                    projection,
                    selection,
                    selectionArgs,
                    null,
                    null,
                    sortOrder);

        default:
            return null;
    }

}

而不是private static String DB_NAME = "databases/brodsky.db";

你应该使用private static String DB_NAME = "brodsky.db";

SQliteAssetHelper 在自述文件中包含以下内容:-

Extend SQLiteAssetHelper as you would normally do SQLiteOpenHelper, providing the constructor with a database name and version number:

public class MyDatabase extends SQLiteAssetHelper {

    private static final String DATABASE_NAME = "northwind.db";
    private static final int DATABASE_VERSION = 1;

    public MyDatabase(Context context) {
      super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }
}

SQLiteAssetHelper relies upon asset file and folder naming conventions. Your assets folder will either be under your project root, or under src/main if you are using the default gradle project structure. At minimum, you must provide the following:

A databases folder inside assets A SQLite database inside the databases folder whose file name matches the database name you provide in code (including the file extension, if any) For the example above, the project would contain the following:

assets/databases/northwind.db