使用带有文件sql sqlite的Room

时间:2018-03-13 17:15:41

标签: android android-room

我想使用带有文件路径sqlite的Room,里面有数据(在Android平板电脑上下载sqlite) 但我不知道......

我尝试使用RoomAsset,但它不起作用。

你有什么想法吗?

1 个答案:

答案 0 :(得分:0)

这对我有用:

公共类ExternalSQLiteOpenHelper实现SupportSQLiteOpenHelper {     私人决赛OpenHelper mDelegate;

ExternalSQLiteOpenHelper(Context context, String name,
                      String pathDirectoryDb,
                      SQLiteDatabase.CursorFactory factory, int version,
                      DatabaseErrorHandler errorHandler,
                      Callback callback) {
    mDelegate = createDelegate(context, name, pathDirectoryDb, factory, version, errorHandler, callback);
}

private OpenHelper createDelegate(Context context, String name,
                                  String pathDirectoryDb,
                                  SQLiteDatabase.CursorFactory factory, int version, DatabaseErrorHandler errorHandler,
                                  final Callback callback) {
    return new OpenHelper(context, name,pathDirectoryDb, factory, version, errorHandler) {
        @Override
        public final void onCreate(SQLiteDatabase sqLiteDatabase) {
            mWrappedDb = new FrameworkSQLiteDatabase(sqLiteDatabase);
            callback.onCreate(mWrappedDb);
        }

        @Override
        public final void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
            callback.onUpgrade(getWrappedDb(sqLiteDatabase), oldVersion, newVersion);
        }

        @Override
        public final void onConfigure(SQLiteDatabase db) {
            callback.onConfigure(getWrappedDb(db));
        }

        @Override
        public final void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            callback.onDowngrade(getWrappedDb(db), oldVersion, newVersion);
        }

        @Override
        public void onOpen(SQLiteDatabase db) {
            callback.onOpen(getWrappedDb(db));
        }
    };
}

@Override
public String getDatabaseName() {
    return mDelegate.getDatabaseName();
}

@Override
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public void setWriteAheadLoggingEnabled(boolean enabled) {
    mDelegate.setWriteAheadLoggingEnabled(enabled);
}

@Override
public SupportSQLiteDatabase getWritableDatabase() {
    return mDelegate.getWritableSupportDatabase();
}

@Override
public SupportSQLiteDatabase getReadableDatabase() {
    return mDelegate.getReadableSupportDatabase();
}

@Override
public void close() {
    mDelegate.close();
}

abstract static class OpenHelper extends SQLiteExternHelper {

    FrameworkSQLiteDatabase mWrappedDb;

    OpenHelper(Context context, String name,
               String pathDirectoryDb,
               SQLiteDatabase.CursorFactory factory, int version,
               DatabaseErrorHandler errorHandler) {
        super(context, name, pathDirectoryDb, factory, version, errorHandler);
    }

    SupportSQLiteDatabase getWritableSupportDatabase() {
        SQLiteDatabase db = super.getWritableDatabase();
        return getWrappedDb(db);
    }

    SupportSQLiteDatabase getReadableSupportDatabase() {
        SQLiteDatabase db = super.getReadableDatabase();
        return getWrappedDb(db);
    }

    FrameworkSQLiteDatabase getWrappedDb(SQLiteDatabase sqLiteDatabase) {
        if (mWrappedDb == null) {
            mWrappedDb = new FrameworkSQLiteDatabase(sqLiteDatabase);
        }
        return mWrappedDb;
    }

    @Override
    public synchronized void close() {
        super.close();
        mWrappedDb = null;
    }
}

}

公共类ExternalSQLiteOpenHelperFactory实现SupportSQLiteOpenHelper.Factory {

private static final String TAG =ExternalSQLiteOpenHelperFactory.class.getSimpleName() ;
private String pathDirectoryDb;

public ExternalSQLiteOpenHelperFactory(String pathDirectoryDb) {
    GILogUtil.i(TAG,"ExternalSQLiteOpenHelperFactory CONSTRUCTOR" );
    this.pathDirectoryDb = pathDirectoryDb;
}

@Override
public SupportSQLiteOpenHelper create(SupportSQLiteOpenHelper.Configuration configuration) {
    return new ExternalSQLiteOpenHelper(configuration.context, configuration.name,
            pathDirectoryDb,
            null,
            1,
            null,
            configuration.callback
    );

}

}

公共类SQLiteExternHelper扩展了SQLiteOpenHelper {

private static final String TAG           = SQLiteExternHelper.class.getSimpleName();

private final Context       mContext;
private final String        mName;
private final CursorFactory mFactory;
private final int           mNewVersion;

private SQLiteDatabase mDatabase       = null;
private boolean        mIsInitializing = false;

private String mDatabasePath;
private String mDatabaseFilePath;

private String mAssetPath;

private String mUpgradePathFormat;

private int mForcedUpgradeVersion = 0;


public SQLiteExternHelper(Context context, String name, String pathDirectoryDb, CursorFactory factory, int version, DatabaseErrorHandler errorHandler) {
    super(context, name, factory, version, errorHandler);

    if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);
    if (name == null) throw new IllegalArgumentException("Database name cannot be null");

    mContext = context;
    mName = name;
    mFactory = factory;
    mNewVersion = version;

    mDatabasePath = pathDirectoryDb;
    mDatabaseFilePath = mDatabasePath + "/" + name;

    GILogUtil.i(TAG,"mDatabasePath:" +  mDatabasePath);
    GILogUtil.i(TAG,"mDatabaseFilePath:" +  mDatabaseFilePath);
    mUpgradePathFormat = mDatabaseFilePath + "_upgrade_%s-%s.sql";
}



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

    if (mIsInitializing) {
        throw new IllegalStateException("getWritableDatabase called recursively");
    }

    // If we have a read-only database open, someone could be using it
    // (though they shouldn't), which would cause a lock to be held on
    // the file, and our attempts to open the database read-write would
    // fail waiting for the file lock.  To prevent that, we acquire the
    // lock on the read-only database, which shuts out other users.

    boolean        success = false;
    SQLiteDatabase db      = null;
    //if (mDatabase != null) mDatabase.lock();
    try {
        mIsInitializing = true;
        //if (mName == null) {
        //    db = SQLiteDatabase.create(null);
        //} else {
        //    db = mContext.openOrCreateDatabase(mName, 0, mFactory);
        //}
        db = createOrOpenDatabase(false);

        int version = db.getVersion();

        // do force upgrade
        if (version != 0 && version < mForcedUpgradeVersion) {
            db = createOrOpenDatabase(true);
            db.setVersion(mNewVersion);
            version = db.getVersion();
        }

        if (version != mNewVersion) {
            db.beginTransaction();
            try {
                if (version == 0) {
                    onCreate(db);
                } else {
                    if (version > mNewVersion) {
                        Log.w(TAG, "Can't downgrade read-only database from version " +
                                version + " to " + mNewVersion + ": " + db.getPath());
                    }
                    onUpgrade(db, version, mNewVersion);
                }
                db.setVersion(mNewVersion);
                db.setTransactionSuccessful();
            } finally {
                db.endTransaction();
            }
        }

        onOpen(db);
        success = true;
        return db;
    } finally {
        mIsInitializing = false;
        if (success) {
            if (mDatabase != null) {
                try {
                    mDatabase.close();
                } catch (Exception e) {
                }
                //mDatabase.unlock();
            }
            mDatabase = db;
        } else {
            //if (mDatabase != null) mDatabase.unlock();
            if (db != null) db.close();
        }
    }

}

/**
 * Create and/or open a database.  This will be the same object returned by
 * {@link #getWritableDatabase} unless some problem, such as a full disk,
 * requires the database to be opened read-only.  In that case, a read-only
 * database object will be returned.  If the problem is fixed, a future call
 * to {@link #getWritableDatabase} may succeed, in which case the read-only
 * database object will be closed and the read/write object will be returned
 * in the future.
 *
 * <p class="caution">Like {@link #getWritableDatabase}, this method may
 * take a long time to return, so you should not call it from the
 * application main thread, including from
 * {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.
 *
 * @return a database object valid until {@link #getWritableDatabase}
 * or {@link #close} is called.
 * @throws SQLiteException if the database cannot be opened
 */
@Override
public synchronized SQLiteDatabase getReadableDatabase() {
    if (mDatabase != null && mDatabase.isOpen()) {
        return mDatabase;  // The database is already open for business
    }

    if (mIsInitializing) {
        throw new IllegalStateException("getReadableDatabase called recursively");
    }

    try {
        return getWritableDatabase();
    } catch (SQLiteException e) {
        if (mName == null) throw e;  // Can't open a temp database read-only!
        Log.e(TAG, "Couldn't open " + mName + " for writing (will try read-only):", e);
    }

    SQLiteDatabase db = null;
    try {
        mIsInitializing = true;
        String path = mContext.getDatabasePath(mName).getPath();
        db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READONLY);
        if (db.getVersion() != mNewVersion) {
            throw new SQLiteException("Can't upgrade read-only database from version " +
                    db.getVersion() + " to " + mNewVersion + ": " + path);
        }

        onOpen(db);
        Log.w(TAG, "Opened " + mName + " in read-only mode");
        mDatabase = db;
        return mDatabase;
    } finally {
        mIsInitializing = false;
        if (db != null && db != mDatabase) db.close();
    }
}

/**
 * Close any open database object.
 */
@Override
public synchronized void close() {
    if (mIsInitializing) throw new IllegalStateException("Closed during initialization");

    if (mDatabase != null && mDatabase.isOpen()) {
        mDatabase.close();
        mDatabase = null;
    }
}

@Override
public void onConfigure(SQLiteDatabase db) {
    // not supported!
}

@Override
public void onCreate(SQLiteDatabase db) {
    // do nothing - createOrOpenDatabase() is called in
    // getWritableDatabase() to handle database creation.
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    Log.w(TAG, "Upgrading database " + mName + " from version " + oldVersion + " to " + newVersion + "...");

    ArrayList<String> paths = new ArrayList<String>();
    getUpgradeFilePaths(oldVersion, newVersion - 1, newVersion, paths);

    if (paths.isEmpty()) {
        Log.e(TAG, "no upgrade script path from " + oldVersion + " to " + newVersion);
        throw new SQLiteAssetException("no upgrade script path from " + oldVersion + " to " + newVersion);
    }

    Collections.sort(paths, new VersionComparator());
    for (String path : paths) {
        try {
            Log.w(TAG, "processing upgrade: " + path);
            InputStream is  = mContext.getAssets().open(path);
            String      sql = IOUtil.convertStreamToString(is);
            if (sql != null) {
                List<String> cmds = DbUtil.splitSqlScript(sql, ';');
                for (String cmd : cmds) {
                    if (cmd.trim().length() > 0) {
                        db.execSQL(cmd);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    Log.w(TAG, "Successfully upgraded database " + mName + " from version " + oldVersion + " to " + newVersion);

}

@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    // not supported!
}

/**
 * Bypass the upgrade process (for each increment up to a given version) and simply
 * overwrite the existing database with the supplied asset file.
 *
 * @param version bypass upgrade up to this version number - should never be greater than the
 * latest database version.
 * @deprecated use {@link #setForcedUpgrade} instead.
 */
@Deprecated
public void setForcedUpgradeVersion(int version) {
    setForcedUpgrade(version);
}

/**
 * Bypass the upgrade process (for each increment up to a given version) and simply
 * overwrite the existing database with the supplied asset file.
 *
 * @param version bypass upgrade up to this version number - should never be greater than the
 * latest database version.
 */
public void setForcedUpgrade(int version) {
    mForcedUpgradeVersion = version;
}

/**
 * Bypass the upgrade process for every version increment and simply overwrite the existing
 * database with the supplied asset file.
 */
public void setForcedUpgrade() {
    setForcedUpgrade(mNewVersion);
}

private SQLiteDatabase createOrOpenDatabase(boolean force) throws SQLiteAssetException {


    SQLiteDatabase db   = null;
    File           file = new File(mDatabaseFilePath);
    if (file.exists()) {
        db = returnDatabase();
    }
    //SQLiteDatabase db = returnDatabase();

    if (db != null) {
        // database already exists
        if (force) {
            Log.w(TAG, "forcing database upgrade!");

            db = returnDatabase();
        }
        return db;
    } else {

        db = returnDatabase();
        return db;
    }
}

private SQLiteDatabase returnDatabase() {
    try {
        SQLiteDatabase db = SQLiteDatabase.openDatabase(mDatabaseFilePath, mFactory, SQLiteDatabase.OPEN_READWRITE);
        GILogUtil.i(TAG, "successfully opened database " + mDatabaseFilePath);
        return db;
    } catch (SQLiteException e) {
        GILogUtil.e(TAG, "could not open database " + mDatabaseFilePath + " - " + e.getMessage());
        return null;
    }
}


private InputStream getUpgradeSQLStream(int oldVersion, int newVersion) {
    String path = String.format(mUpgradePathFormat, oldVersion, newVersion);
    try {
        return mContext.getAssets().open(path);
    } catch (IOException e) {
        Log.w(TAG, "missing database upgrade script: " + path);
        return null;
    }
}

private void getUpgradeFilePaths(int baseVersion, int start, int end, ArrayList<String> paths) {

    int a;
    int b;

    InputStream is = getUpgradeSQLStream(start, end);
    if (is != null) {
        String path = String.format(mUpgradePathFormat, start, end);
        paths.add(path);
        a = start - 1;
        b = start;
        is = null;
    } else {
        a = start - 1;
        b = end;
    }

    if (a < baseVersion) {
        return;
    } else {
        getUpgradeFilePaths(baseVersion, a, b, paths); // recursive call
    }

}

/**
 * An exception that indicates there was an error with SQLite asset retrieval or parsing.
 */
@SuppressWarnings("serial")
public static class SQLiteAssetException extends SQLiteException {

    public SQLiteAssetException() {
    }

    public SQLiteAssetException(String error) {
        super(error);
    }
}

}