我有一个从资产文件中读取的sqlite数据库。那是一个如何度过难关的问题。一切正常,但是如果进入设置->应用程序->并清除缓存和数据、数据库等,则应用程序抛出一个sqliteexception没有这样的表:bus_end(代码1):编译时:选择*from,因为基被覆盖。
通过文件管理器,我看到数据库存在,但它只是空的,这是逻辑的。如果你在经理面前一脚踢开,新的文件就会更有效…也就是说,我知道用户可以清除缓存,然后一切都会下降。如何解决这个问题?
这是我的代码:
public class DatabaseHelper extends SQLiteOpenHelper {
//The Android's default system path of your application database.
private static String DB_PATH = "";
private static final int DB_VERSION = 1;
private static String DB_NAME = "app_database.db";
private final Context myContext;
private SQLiteDatabase myDataBase;
public DatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
this.myContext = context;
}
/**
*
* Создает пустую базу данных в системе и переписывает ее с помощью собственной базы данных.
*/
public void createDataBase() throws IOException {
boolean dbExist = checkDataBase();
if (!dbExist)
this.getWritableDatabase();//Создает и/или открывает базу данных
if (myDataBase.isOpen()){
myDataBase.close();
}
try {
copyDataBase();
} catch (IOException e) {
throw new Error(e + "Error copying database");
}
}
/**
* Check if the database already exist to avoid re-copying the file each time you open the application.
*
* @return true if it exists, false if it doesn't
*/
private boolean checkDataBase() {
SQLiteDatabase checkDB = null;
String path = DB_PATH + DB_NAME;
try {
checkDB = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY);
} catch (SQLiteException e) {
//database does't exist yet
}
if (checkDB != null) {
checkDB.close();
}
return checkDB != null;
}
/**
* Copies your database from your local assets-folder to the just created empty database in the
* system folder, from where it can be accessed and handled.
* This is done by transfering bytestream.
*/
private void copyDataBase() throws IOException { //Откройте локальный db в качестве входного потока
InputStream myInput = myContext.getAssets().open(DB_NAME); //Путь к только что созданному пустому db
String outFileName = DB_PATH + DB_NAME; //Откройте пустой бит в качестве выходного потока
OutputStream myOutput = new FileOutputStream(outFileName);
//передавать байты из входного файла в выходной файл
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
//Закрыть потоки
myOutput.flush();
myOutput.close();
myInput.close();
}
public void openDataBase() throws SQLException {
String myPath = DB_PATH;
myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
}
// ПОЛУЧИТЬ
public Cursor getAllData(String table_name) {
myDataBase = getReadableDatabase();
return myDataBase.query(table_name, null, null, null, null, null, null);
}
@Override
public synchronized void close() {
if (myDataBase != null)
myDataBase.close();
super.close();
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
和碎片
private void retrieve() {
listStationItemList.clear();
try {
db.createDataBase();
db.openDataBase();
} catch (Exception e) {
e.printStackTrace();
}
//RETRIEVE
Cursor cursor = db.getAllData(TABLE_BUS);
//LOOP AND ADD TO ARRAYLIST
while (cursor.moveToNext()) {
long _id = cursor.getLong(0);
String name = cursor.getString(1);
String details = cursor.getString(2);
ItemListStation p = new ItemListStation(name, details);
listStationItemList.add(p);
}
//CHECK IF ARRAYLIST ISNT EMPTY
if (!(listStationItemList.size() < 1)) {
recyclerView.setAdapter(adapter);
}
db.close();
}
最佳答案
我相信您在创建/复制过程中有一些问题;
mydatabase变量将为空。
db_path变量设置为“”,因此复制由于只读而失败,日志中有一个类似的异常(注意第2行,还注意更改了代码以不捕获此类异常并忽略它,因此找不到表,因为新的db为空而不被覆盖)
:。-
2018-12-02 02:50:25.525 5780-5780/so53569158.so53569158fragmentlistview D/DBOUTFILE: Outfilename (the database file to be written to) is set to app_database.db
2018-12-02 02:50:25.525 5780-5780/so53569158.so53569158fragmentlistview D/AndroidRuntime: Shutting down VM
2018-12-02 02:50:25.527 5780-5780/so53569158.so53569158fragmentlistview E/AndroidRuntime: FATAL EXCEPTION: main
Process: so53569158.so53569158fragmentlistview, PID: 5780
java.lang.Error: java.io.FileNotFoundException: app_database.db (Read-only file system)Error copying database
at so53569158.so53569158fragmentlistview.DatabaseHelper.createDatabaseAlt(DatabaseHelper.java:59)
at so53569158.so53569158fragmentlistview.DatabaseHelper.<init>(DatabaseHelper.java:29)
at so53569158.so53569158fragmentlistview.MainActivity.onCreate(MainActivity.java:40)
at android.app.Activity.performCreate(Activity.java:6975)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
下面是一个建议的方法,它不打开数据库,而是检查数据库文件是否存在。
如果它没有,那么它也检查父目录的存在,并且如果它不存在就创建它。
没有创建数据库时,该目录不存在。
我相信使用
checkDB = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY);
是为了克服不存在的目录,可能是有问题的。只检查文件可能存在一个缺陷,因为它可能不是数据库文件(可以通过打开前16个字节的检查来进行进一步的检查,该检查必须符合sqlite头数据)。
不管怎样,这是有效的代码
请注意recyclerview和arraylist的使用,它们的源代码已经被注释掉了,所以我不必创建寻找解决方案所必需的代码。
请注意,一些注释掉的代码被注释掉了,因为它被替代代码或替代方法替换了。
一。片段代码(使用了mainfragment):-
公共类mainfragment扩展了fragment{
DatabaseHelper db;
String TABLE_BUS = "bus_end";
public static MainFragment newInstance() {
return new MainFragment();
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_mis_entradas_local, container, false);
db = new DatabaseHelper(getContext()); //<<<<<<<<<< Assumed you had this
retrieve(); //<<<<<<<<<< Assumed you had this
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
private void retrieve() {
//listStationItemList.clear(); // Commented out for convenience
/**
* Block commeneted out NOT NEEDED WITH NEW METHODOLOGY
*/
/*
try {
db.createDataBase();
db.openDataBase();
} catch (Exception e) {
e.printStackTrace();
}
*/
//RETRIEVE
Cursor cursor = db.getAllData(TABLE_BUS);
//LOOP AND ADD TO ARRAYLIST
while (cursor.moveToNext()) {
long _id = cursor.getLong(0);
String name = cursor.getString(1);
String details = cursor.getString(2);
//ItemListStation p = new ItemListStation(name, details); //<<<<<<<<<< Commented out for convenience
//listStationItemList.add(p); //<<<<<<<<<< Commented out for convenience
}
/**
* Block below commented out for convenience
*/
/*
//CHECK IF ARRAYLIST ISNT EMPTY
if (!(listStationItemList.size() < 1)) {
recyclerView.setAdapter(adapter);
*/
db.close();
}
}
注意,它不会直接尝试调用createdatabase,然后调用opendatabase,这是在构造databasehelper时完成的。所以代码块被注释掉了。
2.databasehelper.java
public class DatabaseHelper extends SQLiteOpenHelper {
//The Android's default system path of your application database.
private static String DB_PATH = "";
private static final int DB_VERSION = 1;
private static String DB_NAME = "app_database.db";
private final Context myContext;
private SQLiteDatabase myDataBase;
public DatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
this.myContext = context;
createDatabaseAlt();
myDataBase = this.getWritableDatabase();
}
/**
* NOTE NOT USED SEE createDatabaseAlt below (it's replacment)
* Создает пустую базу данных в системе и переписывает ее с помощью собственной базы данных.
*/
public void createDataBase() throws IOException {
boolean dbExist = checkDataBase();
if (!dbExist) {
this.getWritableDatabase(); //<<<<<<<<<< myDatabase will be null
myDataBase = this.getWritableDatabase();//Создает и/или открывает базу данных
}
if (myDataBase.isOpen()){
myDataBase.close();
}
try {
copyDataBase(); //<<<<<<<<<< Copy fails due to app_database.db (Read-only file system)Error copying database
} catch (IOException e) {
throw new Error(e + "Error copying database");
}
}
// Alternative Create Database
public void createDatabaseAlt() {
if (!checkDB()) {
try {
copyDataBase();
} catch (IOException e) {
throw new Error(e + "Error copying database");
}
}
}
/**
* Check if the database already exist to avoid re-copying the file each time you open the application.
*
* @return true if it exists, false if it doesn't
*/
private boolean checkDataBase() {
SQLiteDatabase checkDB = null;
String path = DB_PATH + DB_NAME;
try {
checkDB = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY);
} catch (SQLiteException e) {
//database does't exist yet
}
if (checkDB != null) {
checkDB.close();
}
return checkDB != null;
}
// Alternative Check that doesn't open the database to create the directory
private boolean checkDB() {
File db = new File(myContext.getDatabasePath(DB_NAME).getPath());
if (db.exists()) return true;
File dbdir = new File(db.getParent());
if (!dbdir.exists()) {
dbdir.mkdirs();
}
return false;
}
/**
* Copies your database from your local assets-folder to the just created empty database in the
* system folder, from where it can be accessed and handled.
* This is done by transfering bytestream.
*/
private void copyDataBase() throws IOException { //Откройте локальный db в качестве входного потока
InputStream myInput = myContext.getAssets().open(DB_NAME); //Путь к только что созданному пустому db
//String outFileName = DB_PATH + DB_NAME; //Откройте пустой бит в качестве выходного потока
OutputStream myOutput = new FileOutputStream(myContext.getDatabasePath(DB_NAME).getPath());
//передавать байты из входного файла в выходной файл
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
//Закрыть потоки
myOutput.flush();
myOutput.close();
myInput.close();
}
/**
* Not used NOTE this open database as read-only and thus was the cause of one of the issues
*/
public void openDataBase() throws SQLException {
String myPath = DB_PATH;
myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
}
// ПОЛУЧИТЬ
public Cursor getAllData(String table_name) {
myDataBase = getReadableDatabase();
return myDataBase.query(table_name, null, null, null, null, null, null);
}
@Override
public synchronized void close() {
if (myDataBase != null)
myDataBase.close();
super.close();
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
注:旧/冗余代码已保留在中,并在必要时进行了注释
请参阅/阅读评论