【问题标题】:How can I use my custom sqlite database with android app? [duplicate]如何将我的自定义 sqlite 数据库与 android 应用程序一起使用? [复制]
【发布时间】:2015-06-27 22:27:55
【问题描述】:

我有一个静态的 sqlite 数据库。我怎样才能将它包含在应用程序中?我应该把它放在我的项目文件夹中的哪里?我应该如何从 DatabaseHandler 访问它?

我在网上找到的所有东西都只是使用 sqlite 来创建一个新的数据库并在其中存储用户或临时数据,而不是使用带有预定义数据的现有数据库。

Official Google docs 没有说明如何做到这一点。

【问题讨论】:

  • 只需将其放在您的assets 文件夹中。然后将其复制到您的应用程序数据库路径(如果不存在)。用它。开心点。

标签: java android sqlite android-studio


【解决方案1】:

处理这种情况基本上就是做一个文件拷贝。

棘手的部分是

  • 仅在需要时创建数据库(否​​则直接打开)
  • 实现升级逻辑

我编写了一个示例 Helper 类来演示如何从您的资产中加载数据库。

public abstract class SQLiteAssetHelper extends SQLiteOpenHelper {

    // ----------------------------------
    // CONSTANTS
    // ----------------------------------

    private static final String DATABASE_DIR_NAME = "databases";

    // ----------------------------------
    // ATTRIBUTES
    // ----------------------------------

    private final Context mContext;
    private final CursorFactory mFactory;

    private SQLiteDatabase mDatabase;

    private String mDatabaseName;
    private String mDatabaseAssetPath;
    private String mDatabaseDiskPath;

    private boolean mIsProcessingDatabaseCreation; // Database creation may take some time

    // ----------------------------------
    // CONSTRUCTORS
    // ----------------------------------

    public SQLiteAssetHelper(Context context, String name, CursorFactory factory, String destinationPath, int version) {
        super(context, name, factory, version);

        mContext = context;
        mFactory = factory;

        mDatabaseName = name;

        mDatabaseAssetPath = DATABASE_DIR_NAME + "/" + name;
        if (destinationPath == null) {
            mDatabaseDiskPath = context.getApplicationInfo().dataDir + "/" + DATABASE_DIR_NAME;
        } else {
            mDatabaseDiskPath = destinationPath;
        }
    }

    // ----------------------------------
    // OVERRIDEN METHODS
    // ----------------------------------

    @Override
    public synchronized SQLiteDatabase getWritableDatabase() {
        if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) {
            // the database is already open and writable
            return mDatabase;
        }

        if (mIsProcessingDatabaseCreation) {
            throw new IllegalStateException("getWritableDatabase is still processing");
        }

        SQLiteDatabase db = null;
        boolean isDatabaseLoaded = false;

        try {
            mIsProcessingDatabaseCreation = true;
            db = createOrOpenDatabase();
            // you should probably check for database new version and process upgrade if necessary
            onOpen(db);
            isDatabaseLoaded = true;
            return db;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            mIsProcessingDatabaseCreation = false;
            if (isDatabaseLoaded) {
                if (mDatabase != null) {
                    try {
                        mDatabase.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                mDatabase = db;
            } else {
                if (db != null) db.close();
            }
        }
    }

    @Override
    public final void onCreate(SQLiteDatabase db) {
        // getWritableDatabase() actually handles database creation so nothing to code here
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // TODO implement your upgrade logic here
    }

    // ----------------------------------
    // PRIVATE METHODS
    // ----------------------------------

    private void copyDatabaseFromAssets() throws IOException {

        String dest = mDatabaseDiskPath + "/" + mDatabaseName;
        String path = mDatabaseAssetPath;

        InputStream is = mContext.getAssets().open(path);

        File databaseDestinationDir = new File(mDatabaseDiskPath + "/");
        if (!databaseDestinationDir.exists()) {
            databaseDestinationDir.mkdir();
        }
        IOUtils.copy(is, new FileOutputStream(dest));
    }

    private SQLiteDatabase createOrOpenDatabase() throws IOException {

        SQLiteDatabase db = null;
        File file = new File (mDatabaseDiskPath + "/" + mDatabaseName);
        if (file.exists()) {
            db = openDatabase();
        }

        if (db != null) {
            return db;
        } else {
            copyDatabaseFromAssets();
            db = openDatabase();
            return db;
        }
    }

    private SQLiteDatabase openDatabase() {
        try {
            SQLiteDatabase db = SQLiteDatabase.openDatabase(
                    mDatabaseDiskPath + "/" + mDatabaseName, mFactory, SQLiteDatabase.OPEN_READWRITE);
            return db;
        } catch (SQLiteException e) {
            e.printStackTrace();
            return null;
        }
    }

    // ----------------------------------
    // NESTED CLASSES
    // ----------------------------------

    private static class IOUtils {

        private static final int BUFFER_SIZE = 1024;

        public static void copy(InputStream in, OutputStream outs) throws IOException {
            int length;
            byte[] buffer = new byte[BUFFER_SIZE];

            while ((length = in.read(buffer)) > 0) {
                outs.write(buffer, 0, length);
            }

            outs.flush();
            outs.close();
            in.close();
        }

    }; // IOUtils

}

然后你只需要像这样创建一个从上面扩展的类:

public class MyDbHelper extends SQLiteAssetHelper {

    // ----------------------------------
    // CONSTANTS
    // ----------------------------------

    private static final int DATABASE_VERSION = 1;
    private static final String DATABASE_FILE_NAME = "test.db";

    // ----------------------------------
    // CONSTRUCTORS
    // ----------------------------------

    public MyDbHelper(Context context) {
        super(context, DATABASE_FILE_NAME, null, context.getFilesDir().getAbsolutePath(), DATABASE_VERSION);
    }

}

每次您从 MyDbHelper 实例调用 getWritableDatabase() 时,它都会为您完成所有复制/打开工作并返回可写数据库。

正如我之前所说,我没有在这个示例中实现 upgrade() 方法,你必须这样做。 我也没有实现 getReadableDatabase(),因为我通常只使用 getWritableDatabase()。您可能需要这样做。

如果你想测试它,只需执行以下操作:

  • 复制上面的代码
  • 在您的资产中创建一个名为“databases”的文件夹,并将您的 sqlite 数据库文件插入其中
  • 在 MyDatabaseHelper 中,将 DATABASE_FILE_NAME 常量的值更改为资产文件夹中数据库的名称
  • 不要忘记实例化 MyDatabaseHelper 并调用 getWritableDatabse()

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-24
    • 2011-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多