java - 从资产复制的数据库在 api 28 上为空(无表)
问题描述
我使用以下代码将数据库文件导出到手机内存。它在 Android 24 上运行良好,但在 API 28 上它只提供一个空文件:
public void exportDatabse() {
try {
if (sd.canWrite()) {
String backupDBPath = "nameBCK.db";
File currentDB = new File(MainActivity.this.getDatabasePath("dataBaseName.db").getPath());
File backupDB = new File(sd, backupDBPath);
if (currentDB.exists()) {
FileChannel src = new FileInputStream(currentDB).getChannel();
FileChannel dst = new FileOutputStream(backupDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
Toast.makeText(this,getString(R.string.stSuccess2),
Toast.LENGTH_LONG).show();
}
}
else {
REQUEST_TYPE=0;
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);}
} catch (Exception e) {
Toast.makeText(this,getString(R.string.stFaild),Toast.LENGTH_LONG).show();
}
}
我还使用 onRequestPermissionsResult 请求写入存储的权限。
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (REQUEST_TYPE==0) exportDatabse();
if (REQUEST_TYPE==1) importDB();
} else {
if (REQUEST_TYPE==0) Toast.makeText(this,getString(R.string.stFaild2),Toast.LENGTH_LONG).show();
if (REQUEST_TYPE==1) Toast.makeText(this,getString(R.string.stFaild3),Toast.LENGTH_LONG).show();
Log.e("value", "Permission Denied, You cannot use local drive .");
}
break;
default:
throw new IllegalStateException("Unexpected value: " + requestCode);
}
}
解决方案
我已经回答了这个问题。此问题仅出现在 Android 28 上。
public class DataBase extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "database.db";
private static String DATABASE_PATH = "";
private static String LAST_DATABASE_PATH = "";
private SQLiteDatabase mDataBase;
private final Context ctx;
public DataBase2(@Nullable Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
DATABASE_PATH = context.getDatabasePath(DATABASE_NAME).getPath();
this.ctx = context;
if (!checkIfDBExists()) {
createDataBase();
}
File dbFile = new File(Environment.getDataDirectory().getPath()+"/data/"+ BuildConfig.APPLICATION_ID +"/databases");
if (dbFile.isDirectory()) {
String[] child = dbFile.list();
assert child != null;
for (int i = 0; i < child.length; i++) {
if (!(child[i].equals("database.db") || child[i].equals(DATABASE_NAME))) {
new File(dbFile, child[i]).delete();
}
}
}
}
public void createDataBase() {
this.getReadableDatabase();
this.close();
try {
copyDataBase();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
try {
File DbFile = ctx.getDatabasePath(DATABASE_NAME);
if (DbFile.exists()) {
copyDataBase();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private boolean checkIfDBExists() {
File dbFile = new File(DATABASE_PATH);
return dbFile.exists();
}
public void openDataBase() {
close();
mDataBase = SQLiteDatabase.openDatabase(DATABASE_PATH, null, CREATE_IF_NECESSARY);
}
private void copyDataBase() throws IOException {
InputStream mInput = ctx.getAssets().open("database.db");
String outfileName = DATABASE_PATH;
OutputStream mOutput = new FileOutputStream(outfileName);
byte[] buffer = new byte[1024];
int mLength;
while ((mLength = mInput.read(buffer)) > 0) {
mOutput.write(buffer, 0, mLength);
}
mOutput.flush();
mInput.close();
mOutput.close();
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public synchronized void close() {
if (mDataBase != null)
mDataBase.close();
SQLiteDatabase.releaseMemory();
super.close();
}
}
推荐阅读
- json - Swift 在保护语句中返回 NULL
- asp.net - 如何在 AWS S3 中托管 .net 应用程序
- sql - 带有表值函数错误的 SQL 交叉应用选择
- tsql - 如何在 T-SQL 中的联合查询中按结果集排序
- postgresql - postgreql 如何管理表发布中涉及的添加或更改的列?
- mysql - 如何在typeorm + nestjs中的子实体对象中获取父ID
- java - Kotlin javax.script 支持示例
- angular - docker中的角度与lerna没有建立
- reactjs - 侧边栏切换 URL 的反应路由但不改变实际视图
- c# - 源自“System.Transactions.JitSafeGetContextTransaction”的“无法转换”异常?