我有一个从资产文件中读取的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) {
    }
}

注:旧/冗余代码已保留在中,并在必要时进行了注释
请参阅/阅读评论

08-17 17:48