您不应该尝试从 Uri 打开 SQLiteDatabase。
SQLiteDatabase 被设计为直接与文件系统一起工作:它需要锁定和解锁数据库文件并管理单独的预写日志记录(-shm 和 -wal)文件,而 Uri 不一定引用 file:// 模式中的任何内容。相反,它可以是任何内容,从 https:// 或 content:// 到自定义应用程序定义的架构。
特别是自 Android 7.0 以来,Google 强制使用 content:// uri 在应用程序之间共享文件(这正是您的情况)。摘自这里:https://developer.android.com/about/versions/nougat/android-7.0-changes.html https://developer.android.com/about/versions/nougat/android-7.0-changes.html:
对于面向 Android 7.0 的应用程序,Android 框架强制执行 StrictMode API 策略,禁止在应用程序外部公开 file:// URI。如果包含文件 URI 的意图离开您的应用程序,则应用程序将失败并出现 FileUriExposedException 异常。
要在应用程序之间共享文件,您应该发送 content:// URI 并授予对该 URI 的临时访问权限。授予此权限的最简单方法是使用 FileProvider 类。有关权限和共享文件的详细信息,请参阅共享文件。
相反,您应该获取 ContentResolver,从中打开 uri InputStream 并将流内容保存到本地临时文件,然后对其使用 SQLiteDatabase.openDatabase(filePath) :
void openDatabaseFromFileDialog() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT).setType("*/*");
startActivityForResult(Intent.createChooser(intent, "Select a database"), DB_FILE_REQUEST);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == DB_FILE_REQUEST && resultCode == RESULT_OK) {
Uri dataUri= data.getData();
openDatabaseFromUri(dataUri);
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
void openDatabaseFromUri(Uri uri) {
InputStream inputStream = application.getContentResolver().openInputStream(uri);
File file = File.createTempFile("sqlite", "");
FileOutputStream outputStream = new FileOutputStream(file);
byte[] buff = new byte[1024];
int read;
while ((read = inputStream.read(buff, 0, buff.length)) > 0)
outputStream.write(buff, 0, read);
inputStream.close();
outputStream.close();
openDatabaseFromFile(file.getPath());
}
void openDatabaseFromFile(String filePath) {
// your code here
}
另外,当您从另一个应用程序(可能是第三方)获取 SQLite 流时,我强烈建议您在单独的线程/AsyncTask/等中使用数据库。您永远不知道您收到了多少 PB :)