默認的sqlite數據庫是放在/data/data/database目錄下的,今天看騰訊雲IM的demo發現再該路徑下找不到它存放消息的數據庫,找了下后發現居然是放在/data/data/files目錄下的,雖然不知道為什么要放到這個目錄,不過仔細想了下突然發覺假如把數據庫放到非data目錄下的話,就可以不借助contentprovider之類的方式實現跨應用訪問數據庫了,雖然安全性會降低,但在部分場景下還是會有所作用的。
閱讀下了SqliteOpenHelper的源碼,和數據庫路徑相關部分如下。
public SQLiteDatabase getWritableDatabase() {
synchronized (this) {
return getDatabaseLocked(true);
}
}
public SQLiteDatabase getReadableDatabase() {
synchronized (this) {
return getDatabaseLocked(false);
}
}
private SQLiteDatabase getDatabaseLocked(boolean writable) {
if (mDatabase != null) {
if (!mDatabase.isOpen()) {
// Darn! The user closed the database by calling mDatabase.close().
mDatabase = null;
} else if (!writable || !mDatabase.isReadOnly()) {
// The database is already open for business.
return mDatabase;
}
}
if (mIsInitializing) {
throw new IllegalStateException("getDatabase called recursively");
}
SQLiteDatabase db = mDatabase;
try {
mIsInitializing = true;
if (db != null) {
if (writable && db.isReadOnly()) {
db.reopenReadWrite();
}
} else if (mName == null) {
db = SQLiteDatabase.create(null);
} else {
try {
if (DEBUG_STRICT_READONLY && !writable) {
String path = mContext.getDatabasePath(mName).getPath()
db = SQLiteDatabase.openDatabase(path, mFactory,
SQLiteDatabase.OPEN_READONLY, mErrorHandler);
} else {
db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ?
Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0,
mFactory, mErrorHandler);
}
} catch (SQLiteException ex) {
if (writable) {
throw ex;
}
Log.e(TAG, "Couldn't open " + mName
+ " for writing (will try read-only):", ex);
final String path = mContext.getDatabasePath(mName).getPath();
db = SQLiteDatabase.openDatabase(path, mFactory,
SQLiteDatabase.OPEN_READONLY, mErrorHandler);
}
}
........
其實是調用了mContext的getDataBasePath方法,這個方法是在ContextImpl中實現的,再看下源碼
@Override public File getDatabasePath(String name) { return validateFilePath(name, false); } private File validateFilePath(String name, boolean createDirectory) { File dir; File f; if (name.charAt(0) == File.separatorChar) { String dirPath = name.substring(0, name.lastIndexOf(File.separatorChar)); dir = new File(dirPath); name = name.substring(name.lastIndexOf(File.separatorChar)); f = new File(dir, name); } else { dir = getDatabasesDir(); f = makeFilename(dir, name); } if (createDirectory && !dir.isDirectory() && dir.mkdir()) { FileUtils.setPermissions(dir.getPath(), FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, -1, -1); } return f; }
好吧,原來這么簡單,原來Android本身已經實現了自定義路徑的方法了,只要傳入的path的第一個字符為"/"就行了。
總結下就一句話,只要傳入自定義路徑的完整路徑就好了。。。。