база данных Android размером более 1 МБ в папке активов - PullRequest
0 голосов
/ 12 октября 2019

Итак, у меня есть эта база данных размером около 7 МБ, и когда я впервые начал разрабатывать приложения в 2014 году, я прочитал, что я должен разделить базу данных на части по 1 МБ и поместить ее в папку активов следующим образом: 01.db 02.db 03.db... 07.db

И в моем классе db helper у меня было

private void copyDataBase(File DBFile) throws IOException
    {
        AssetManager am = myContext.getAssets();
        OutputStream os = new FileOutputStream(DBFile);
        DBFile.createNewFile();
        byte []b = new byte[1024];
        int i, r;
        String []Files = am.list("");
        Arrays.sort(Files);
        for(i=1;i<15;i++) //I have definitely less than 10 files; you might have more
        {
            String fn = String.format("0%d.db", i);
            System.out.println(fn);
            if(Arrays.binarySearch(Files, fn) < 0) //No such file in assets - time to quit the loop
                break;
            InputStream is = am.open(fn);
            while((r = is.read(b)) != -1)
                os.write(b, 0, r);
            is.close();
        }
        os.close();
    }

Этот фрагмент кода по-прежнему актуален? Вот мой полный класс помощника по БД, у кого-нибудь из вас есть обновленная версия? DatabaseHelper.class

public class DatabaseHelper extends SQLiteOpenHelper {

private SQLiteDatabase myDataBase;
private final Context myContext;

//public static String PACKAGE_NAME
//PACKAGE_NAME = getApplicationContext().getPackageName();
//The Androids default system path of your application database.
//private static String DB_PATH = "/data/data/"+PACKAGE_NAME+"/databases/";
private static String DB_PATH = "";
private static String DB_NAME = "fulldb6";//name of your Database
//File DBFile                 = new File(DB_PATH, DB_NAME);
File DBFile;



/**
  * Constructor
  * Takes and keeps a reference of the passed context in order to access to the application assets and resources.
  * @param context
  */

public DatabaseHelper(Context context) {

    super(context, DB_NAME, null, 3);
    this.myContext = context;
    DB_PATH = myContext.getDatabasePath(this.DB_NAME).getPath();;
    DBFile  = myContext.getDatabasePath(this.DB_NAME);

    //System.out.println(DBFile.getPath());
}

/**
  * Creates a empty database on the system and rewrites it with your own database.
  * */
public void createDataBase() throws IOException{

    boolean dbExist = checkIfDataBaseExists();

    if(dbExist){
        //do nothing - database already exist
    } else{

        //By calling this method and empty database will be created into the default system path
        //of your application so we are gonna be able to overwrite that database with our database.
        this.getReadableDatabase();

        try {
            copyDataBase(DBFile);
        } catch (IOException e) {
            throw new Error("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 checkIfDataBaseExists(){

    SQLiteDatabase checkDB = null;

    try{
        String myPath = DB_PATH;
        checkDB       = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);

    } catch(SQLiteException e){


    }

    if(checkDB != null){

        checkDB.close();

    }

    return checkDB != null ? true : false;
}



private void copyDataBase(File DBFile) throws IOException
{
    AssetManager am = myContext.getAssets();
    OutputStream os = new FileOutputStream(DBFile);
    DBFile.createNewFile();
    byte []b = new byte[1024];
    int i, r;
    String []Files = am.list("");
    Arrays.sort(Files);
    for(i=1;i<15;i++) //I have definitely less than 10 files; you might have more
    {
        String fn = String.format("0%d.db", i);
        System.out.println(fn);
        if(Arrays.binarySearch(Files, fn) < 0) //No such file in assets - time to quit the loop
            break;
        InputStream is = am.open(fn);
        while((r = is.read(b)) != -1)
            os.write(b, 0, r);
        is.close();
    }
    os.close();
}


public void openDataBase() throws SQLException{

        //Open the database
        String myPath = DB_PATH ;
        myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);

}

@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) {

}

Также кто-нибудь знает, вызывает ли какой-либо сбой жесткое кодирование пути db_path к /data/data/com.packagename/databases? В устройствах без памяти и, возможно, дБ хранится на SD-карте? Многие люди сообщали о сбоях или не работающем приложении, которое я не мог воспроизвести на моем устройстве и эмуляторах Android.

Должен ли я проверить, если нет памяти для установки БД в SDCard?

1 Ответ

0 голосов
/ 12 октября 2019

Этот фрагмент кода по-прежнему актуален?

Это приведет к сбоям для Android 9+, так как getReadableDatabase приведет к созданию файлов -wal и -shm (WAL по умолчанию включен в Android 9+), которые помечены какпринадлежит новой базе данных. Новая база данных перезаписывается, но файлы -wal и -shm остаются. Копирование работает, но когда база данных открывается через SQliteOpenHelper, ошибка из-за существующих файлов -shm и -wal приводит к тому, что используемая база данных пуста, т. Е. Данные были стерты, и, как правило, приложение вылетает с таблицей, не найденной.

Единственная причина, я подозреваю, что использование getReadableDatabase или (getWritableDatabase без разницы, если нет катастрофы как таковой) использовалось исторически, заключается в том, что кто-то обнаружил, что он обошел OpenError ENOENT, когда он не был 'т использовал. Что делает база данных get ??? в рамках долгого и сложного процесса открытия базы данных, так это создает каталог баз данных, если он не существует.

Почему очевидное использование mkdirs не был использован, я понятия не имею.

Эффективный способ проверки и подготовки копии файла базы данных из ресурсов - это проверить, существует ли файл базы данных (если он существует, то нет необходимости копировать из активов), если он этого не делает. существующий, затем проверьте файл parentFile (папка баз данных), чтобы увидеть, существует ли он. Если он не существует, выполните mkdirs в родительском файле, а затем скопируйте файл.

  • Нет необходимости открывать файл базы данных,
  • нет генерации файлов -wal и -swm,
  • нет базовой обработки для создания файла базы данных, -файл shm и файл -wal просто для их отбрасывания. -нет исчезновения трюков с таблицами.

/ data / data / com.packagename / database

В связи с проблемами возникло много проблем (в основном опечаток),Тем не менее, нет необходимости в сложном коде. Используйте Context getDatabasePath (dbname) для возврата пути. Единственный жесткий код (и это должно быть 1 место как константа) - это имя базы данных (DB_NAME в вашем случае).

Итак, у меня есть эта база данных размером около 7 МБ, и когда я впервые начал разрабатывать приложенияв 2014 году я прочитал, что я должен разделить базу данных на 1 МБ и поместить ее в папку ресурсов следующим образом: 01.db 02.db 03.db ... 07.db

Я недумаю, что это ограничение остается. Я считаю, что активы могут быть частью 100 Мб для APK, но большие данные можно обрабатывать с помощью расширенных APK.

...