Відправити додаток до бази даних


959

Якщо у вашій програмі потрібна база даних, і вона оснащена вбудованими даними, який найкращий спосіб відправити цю програму? Повинен я:

  1. Створіть базу даних SQLite і включіть її до .apk?

  2. Включіть до програми команди SQL і чи створити він базу даних та вставити дані при першому використанні?

Недоліки, які я бачу:

  1. Можливі невідповідності версій SQLite можуть спричинити проблеми, і я в даний час не знаю, куди повинна відправлятися база даних і як отримати доступ до неї.

  2. Створення та заповнення бази даних на пристрої може зайняти дуже багато часу.

Будь-які пропозиції? Будемо дуже вдячні вказівки на документацію стосовно будь-яких питань.



6
використовувати SQLiteAssetHelper
Річард Ле Месюр'є

Відповіді:


199

Є два варіанти створення та оновлення баз даних.

Перше - створити базу даних зовні, потім помістити її в папку активів проекту, а потім скопіювати з неї всю базу даних. Це набагато швидше, якщо в базі даних багато таблиць та інших компонентів. Оновлення ініціюється зміною номера версії бази даних у файлі res / values ​​/ strings.xml. Оновлення буде виконано, створивши зовнішню нову базу даних, замінивши стару базу даних у папці активів на нову базу даних, збереживши стару базу даних у внутрішньому сховищі під іншим іменем, скопіювавши нову базу даних із папки активів у внутрішню пам’ять, перенісши все даних зі старої бази даних (яка була перейменована раніше) у нову базу даних та остаточно видалила стару базу даних. Ви можете створити базу даних спочатку за допомогоюПлагін SQLite Manager FireFox для виконання ваших заяв sql створення.

Інший варіант - створити внутрішню базу даних з файлу sql. Це не так швидко, але затримка, можливо, буде непомітна для користувачів, якщо в базі даних є лише кілька таблиць. Оновлення ініціюється зміною номера версії бази даних у файлі res / values ​​/ strings.xml. Тоді оновлення будуть виконані шляхом обробки файлу sql оновлення. Дані в базі даних залишаться незмінними, за винятком випадків, коли контейнер видалений, наприклад, опустивши таблицю.

Наведений нижче приклад демонструє, як використовувати будь-який метод.

Ось зразок файлу create_database.sql. Він повинен бути розміщений у папці активів проекту для внутрішнього методу або скопійований у "Виконати SQL" менеджера SQLite для створення бази даних для зовнішнього методу. (ПРИМІТКА. Зауважте, що коментар щодо таблиці, потрібної Android.)

--Android requires a table named 'android_metadata' with a 'locale' column
CREATE TABLE "android_metadata" ("locale" TEXT DEFAULT 'en_US');
INSERT INTO "android_metadata" VALUES ('en_US');

CREATE TABLE "kitchen_table";
CREATE TABLE "coffee_table";
CREATE TABLE "pool_table";
CREATE TABLE "dining_room_table";
CREATE TABLE "card_table"; 

Ось приклад файлу update_database.sql. Він повинен бути розміщений у папці активів проекту для внутрішнього методу або скопійований у "Виконати SQL" менеджера SQLite для створення бази даних для зовнішнього методу. (ПРИМІТКА. Зауважте, що всі три типи коментарів SQL будуть ігноровані за допомогою аналізатора sql, який включений у цей приклад.)

--CREATE TABLE "kitchen_table";  This is one type of comment in sql.  It is ignored by parseSql.
/*
 * CREATE TABLE "coffee_table"; This is a second type of comment in sql.  It is ignored by parseSql.
 */
{
CREATE TABLE "pool_table";  This is a third type of comment in sql.  It is ignored by parseSql.
}
/* CREATE TABLE "dining_room_table"; This is a second type of comment in sql.  It is ignored by parseSql. */
{ CREATE TABLE "card_table"; This is a third type of comment in sql.  It is ignored by parseSql. }

--DROP TABLE "picnic_table"; Uncomment this if picnic table was previously created and now is being replaced.
CREATE TABLE "picnic_table" ("plates" TEXT);
INSERT INTO "picnic_table" VALUES ('paper');

Ось запис, який потрібно додати у файл /res/values/strings.xml для номера версії бази даних.

<item type="string" name="databaseVersion" format="integer">1</item>

Ось діяльність, яка отримує доступ до бази даних, а потім використовує її. ( Примітка. Ви можете запустити код бази даних в окремому потоці, якщо він використовує багато ресурсів. )

package android.example;

import android.app.Activity;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;

/**
 * @author Danny Remington - MacroSolve
 * 
 *         Activity for demonstrating how to use a sqlite database.
 */
public class Database extends Activity {
     /** Called when the activity is first created. */
     @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        DatabaseHelper myDbHelper;
        SQLiteDatabase myDb = null;

        myDbHelper = new DatabaseHelper(this);
        /*
         * Database must be initialized before it can be used. This will ensure
         * that the database exists and is the current version.
         */
         myDbHelper.initializeDataBase();

         try {
            // A reference to the database can be obtained after initialization.
            myDb = myDbHelper.getWritableDatabase();
            /*
             * Place code to use database here.
             */
         } catch (Exception ex) {
            ex.printStackTrace();
         } finally {
            try {
                myDbHelper.close();
            } catch (Exception ex) {
                ex.printStackTrace();
            } finally {
                myDb.close();
            }
        }

    }
}

Ось клас помічників бази даних, де база даних створюється або оновлюється при необхідності. (ПРИМІТКА: Android вимагає створити клас, який розширює SQLiteOpenHelper для роботи з базою даних Sqlite.)

package android.example;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

/**
 * @author Danny Remington - MacroSolve
 * 
 *         Helper class for sqlite database.
 */
public class DatabaseHelper extends SQLiteOpenHelper {

    /*
     * The Android's default system path of the application database in internal
     * storage. The package of the application is part of the path of the
     * directory.
     */
    private static String DB_DIR = "/data/data/android.example/databases/";
    private static String DB_NAME = "database.sqlite";
    private static String DB_PATH = DB_DIR + DB_NAME;
    private static String OLD_DB_PATH = DB_DIR + "old_" + DB_NAME;

    private final Context myContext;

    private boolean createDatabase = false;
    private boolean upgradeDatabase = false;

    /**
     * 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, context.getResources().getInteger(
                R.string.databaseVersion));
        myContext = context;
        // Get the path of the database that is based on the context.
        DB_PATH = myContext.getDatabasePath(DB_NAME).getAbsolutePath();
    }

    /**
     * Upgrade the database in internal storage if it exists but is not current. 
     * Create a new empty database in internal storage if it does not exist.
     */
    public void initializeDataBase() {
        /*
         * Creates or updates the database in internal storage if it is needed
         * before opening the database. In all cases opening the database copies
         * the database in internal storage to the cache.
         */
        getWritableDatabase();

        if (createDatabase) {
            /*
             * If the database is created by the copy method, then the creation
             * code needs to go here. This method consists of copying the new
             * database from assets into internal storage and then caching it.
             */
            try {
                /*
                 * Write over the empty data that was created in internal
                 * storage with the one in assets and then cache it.
                 */
                copyDataBase();
            } catch (IOException e) {
                throw new Error("Error copying database");
            }
        } else if (upgradeDatabase) {
            /*
             * If the database is upgraded by the copy and reload method, then
             * the upgrade code needs to go here. This method consists of
             * renaming the old database in internal storage, create an empty
             * new database in internal storage, copying the database from
             * assets to the new database in internal storage, caching the new
             * database from internal storage, loading the data from the old
             * database into the new database in the cache and then deleting the
             * old database from internal storage.
             */
            try {
                FileHelper.copyFile(DB_PATH, OLD_DB_PATH);
                copyDataBase();
                SQLiteDatabase old_db = SQLiteDatabase.openDatabase(OLD_DB_PATH, null, SQLiteDatabase.OPEN_READWRITE);
                SQLiteDatabase new_db = SQLiteDatabase.openDatabase(DB_PATH,null, SQLiteDatabase.OPEN_READWRITE);
                /*
                 * Add code to load data into the new database from the old
                 * database and then delete the old database from internal
                 * storage after all data has been transferred.
                 */
            } catch (IOException e) {
                throw new Error("Error copying database");
            }
        }

    }

    /**
     * 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 {
        /*
         * Close SQLiteOpenHelper so it will commit the created empty database
         * to internal storage.
         */
        close();

        /*
         * Open the database in the assets folder as the input stream.
         */
        InputStream myInput = myContext.getAssets().open(DB_NAME);

        /*
         * Open the empty db in interal storage as the output stream.
         */
        OutputStream myOutput = new FileOutputStream(DB_PATH);

        /*
         * Copy over the empty db in internal storage with the database in the
         * assets folder.
         */
        FileHelper.copyFile(myInput, myOutput);

        /*
         * Access the copied database so SQLiteHelper will cache it and mark it
         * as created.
         */
        getWritableDatabase().close();
    }

    /*
     * This is where the creation of tables and the initial population of the
     * tables should happen, if a database is being created from scratch instead
     * of being copied from the application package assets. Copying a database
     * from the application package assets to internal storage inside this
     * method will result in a corrupted database.
     * <P>
     * NOTE: This method is normally only called when a database has not already
     * been created. When the database has been copied, then this method is
     * called the first time a reference to the database is retrieved after the
     * database is copied since the database last cached by SQLiteOpenHelper is
     * different than the database in internal storage.
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        /*
         * Signal that a new database needs to be copied. The copy process must
         * be performed after the database in the cache has been closed causing
         * it to be committed to internal storage. Otherwise the database in
         * internal storage will not have the same creation timestamp as the one
         * in the cache causing the database in internal storage to be marked as
         * corrupted.
         */
        createDatabase = true;

        /*
         * This will create by reading a sql file and executing the commands in
         * it.
         */
            // try {
            // InputStream is = myContext.getResources().getAssets().open(
            // "create_database.sql");
            //
            // String[] statements = FileHelper.parseSqlFile(is);
            //
            // for (String statement : statements) {
            // db.execSQL(statement);
            // }
            // } catch (Exception ex) {
            // ex.printStackTrace();
            // }
    }

    /**
     * Called only if version number was changed and the database has already
     * been created. Copying a database from the application package assets to
     * the internal data system inside this method will result in a corrupted
     * database in the internal data system.
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        /*
         * Signal that the database needs to be upgraded for the copy method of
         * creation. The copy process must be performed after the database has
         * been opened or the database will be corrupted.
         */
        upgradeDatabase = true;

        /*
         * Code to update the database via execution of sql statements goes
         * here.
         */

        /*
         * This will upgrade by reading a sql file and executing the commands in
         * it.
         */
        // try {
        // InputStream is = myContext.getResources().getAssets().open(
        // "upgrade_database.sql");
        //
        // String[] statements = FileHelper.parseSqlFile(is);
        //
        // for (String statement : statements) {
        // db.execSQL(statement);
        // }
        // } catch (Exception ex) {
        // ex.printStackTrace();
        // }
    }

    /**
     * Called everytime the database is opened by getReadableDatabase or
     * getWritableDatabase. This is called after onCreate or onUpgrade is
     * called.
     */
    @Override
    public void onOpen(SQLiteDatabase db) {
        super.onOpen(db);
    }

    /*
     * Add your public helper methods to access and get content from the
     * database. You could return cursors by doing
     * "return myDataBase.query(....)" so it'd be easy to you to create adapters
     * for your views.
     */

}

Ось клас FileHelper, який містить способи копіювання файлів потоку байтів та розбору файлів sql.

package android.example;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.nio.channels.FileChannel;

/**
 * @author Danny Remington - MacroSolve
 * 
 *         Helper class for common tasks using files.
 * 
 */
public class FileHelper {
    /**
     * Creates the specified <i><b>toFile</b></i> that is a byte for byte a copy
     * of <i><b>fromFile</b></i>. If <i><b>toFile</b></i> already existed, then
     * it will be replaced with a copy of <i><b>fromFile</b></i>. The name and
     * path of <i><b>toFile</b></i> will be that of <i><b>toFile</b></i>. Both
     * <i><b>fromFile</b></i> and <i><b>toFile</b></i> will be closed by this
     * operation.
     * 
     * @param fromFile
     *            - InputStream for the file to copy from.
     * @param toFile
     *            - InputStream for the file to copy to.
     */
    public static void copyFile(InputStream fromFile, OutputStream toFile) throws IOException {
        // transfer bytes from the inputfile to the outputfile
        byte[] buffer = new byte[1024];
        int length;

        try {
            while ((length = fromFile.read(buffer)) > 0) {
                toFile.write(buffer, 0, length);
            }
        }
        // Close the streams
        finally {
            try {
                if (toFile != null) {
                    try {
                        toFile.flush();
                    } finally {
                        toFile.close();
                    }
            }
            } finally {
                if (fromFile != null) {
                    fromFile.close();
                }
            }
        }
    }

    /**
     * Creates the specified <i><b>toFile</b></i> that is a byte for byte a copy
     * of <i><b>fromFile</b></i>. If <i><b>toFile</b></i> already existed, then
     * it will be replaced with a copy of <i><b>fromFile</b></i>. The name and
     * path of <i><b>toFile</b></i> will be that of <i><b>toFile</b></i>. Both
     * <i><b>fromFile</b></i> and <i><b>toFile</b></i> will be closed by this
     * operation.
     * 
     * @param fromFile
     *            - String specifying the path of the file to copy from.
     * @param toFile
     *            - String specifying the path of the file to copy to.
     */
    public static void copyFile(String fromFile, String toFile) throws IOException {
        copyFile(new FileInputStream(fromFile), new FileOutputStream(toFile));
    }

    /**
     * Creates the specified <i><b>toFile</b></i> that is a byte for byte a copy
     * of <i><b>fromFile</b></i>. If <i><b>toFile</b></i> already existed, then
     * it will be replaced with a copy of <i><b>fromFile</b></i>. The name and
     * path of <i><b>toFile</b></i> will be that of <i><b>toFile</b></i>. Both
     * <i><b>fromFile</b></i> and <i><b>toFile</b></i> will be closed by this
     * operation.
     * 
     * @param fromFile
     *            - File for the file to copy from.
     * @param toFile
     *            - File for the file to copy to.
     */
    public static void copyFile(File fromFile, File toFile) throws IOException {
        copyFile(new FileInputStream(fromFile), new FileOutputStream(toFile));
    }

    /**
     * Creates the specified <i><b>toFile</b></i> that is a byte for byte a copy
     * of <i><b>fromFile</b></i>. If <i><b>toFile</b></i> already existed, then
     * it will be replaced with a copy of <i><b>fromFile</b></i>. The name and
     * path of <i><b>toFile</b></i> will be that of <i><b>toFile</b></i>. Both
     * <i><b>fromFile</b></i> and <i><b>toFile</b></i> will be closed by this
     * operation.
     * 
     * @param fromFile
     *            - FileInputStream for the file to copy from.
     * @param toFile
     *            - FileInputStream for the file to copy to.
     */
    public static void copyFile(FileInputStream fromFile, FileOutputStream toFile) throws IOException {
        FileChannel fromChannel = fromFile.getChannel();
        FileChannel toChannel = toFile.getChannel();

        try {
            fromChannel.transferTo(0, fromChannel.size(), toChannel);
        } finally {
            try {
                if (fromChannel != null) {
                    fromChannel.close();
                }
            } finally {
                if (toChannel != null) {
                    toChannel.close();
                }
            }
        }
    }

    /**
     * Parses a file containing sql statements into a String array that contains
     * only the sql statements. Comments and white spaces in the file are not
     * parsed into the String array. Note the file must not contained malformed
     * comments and all sql statements must end with a semi-colon ";" in order
     * for the file to be parsed correctly. The sql statements in the String
     * array will not end with a semi-colon ";".
     * 
     * @param sqlFile
     *            - String containing the path for the file that contains sql
     *            statements.
     * 
     * @return String array containing the sql statements.
     */
    public static String[] parseSqlFile(String sqlFile) throws IOException {
        return parseSqlFile(new BufferedReader(new FileReader(sqlFile)));
    }

    /**
     * Parses a file containing sql statements into a String array that contains
     * only the sql statements. Comments and white spaces in the file are not
     * parsed into the String array. Note the file must not contained malformed
     * comments and all sql statements must end with a semi-colon ";" in order
     * for the file to be parsed correctly. The sql statements in the String
     * array will not end with a semi-colon ";".
     * 
     * @param sqlFile
     *            - InputStream for the file that contains sql statements.
     * 
     * @return String array containing the sql statements.
     */
    public static String[] parseSqlFile(InputStream sqlFile) throws IOException {
        return parseSqlFile(new BufferedReader(new InputStreamReader(sqlFile)));
    }

    /**
     * Parses a file containing sql statements into a String array that contains
     * only the sql statements. Comments and white spaces in the file are not
     * parsed into the String array. Note the file must not contained malformed
     * comments and all sql statements must end with a semi-colon ";" in order
     * for the file to be parsed correctly. The sql statements in the String
     * array will not end with a semi-colon ";".
     * 
     * @param sqlFile
     *            - Reader for the file that contains sql statements.
     * 
     * @return String array containing the sql statements.
     */
    public static String[] parseSqlFile(Reader sqlFile) throws IOException {
        return parseSqlFile(new BufferedReader(sqlFile));
    }

    /**
     * Parses a file containing sql statements into a String array that contains
     * only the sql statements. Comments and white spaces in the file are not
     * parsed into the String array. Note the file must not contained malformed
     * comments and all sql statements must end with a semi-colon ";" in order
     * for the file to be parsed correctly. The sql statements in the String
     * array will not end with a semi-colon ";".
     * 
     * @param sqlFile
     *            - BufferedReader for the file that contains sql statements.
     * 
     * @return String array containing the sql statements.
     */
    public static String[] parseSqlFile(BufferedReader sqlFile) throws IOException {
        String line;
        StringBuilder sql = new StringBuilder();
        String multiLineComment = null;

        while ((line = sqlFile.readLine()) != null) {
            line = line.trim();

            // Check for start of multi-line comment
            if (multiLineComment == null) {
                // Check for first multi-line comment type
                if (line.startsWith("/*")) {
                    if (!line.endsWith("}")) {
                        multiLineComment = "/*";
                    }
                // Check for second multi-line comment type
                } else if (line.startsWith("{")) {
                    if (!line.endsWith("}")) {
                        multiLineComment = "{";
                }
                // Append line if line is not empty or a single line comment
                } else if (!line.startsWith("--") && !line.equals("")) {
                    sql.append(line);
                } // Check for matching end comment
            } else if (multiLineComment.equals("/*")) {
                if (line.endsWith("*/")) {
                    multiLineComment = null;
                }
            // Check for matching end comment
            } else if (multiLineComment.equals("{")) {
                if (line.endsWith("}")) {
                    multiLineComment = null;
                }
            }

        }

        sqlFile.close();

        return sql.toString().split(";");
    }

}

Я використав вищевказаний код для оновлення мого db "upgrade_database.sql містить оператор вставлення. Деякі значення мають напівкольон, як вставка у значення_a_a_sl '(' ss ',' ddd ',' aaaa; aaa ');" коли я запускаю Я помітив вище згадування вставки не отримують esecse через півкола у значеннях будь-яких ідей, як це виправити.
Сем

5
Є третій варіант - скопіюйте db з Інтернету. Я зробив це, і це йде досить швидко за 4 Мб. Він також вирішує проблему з 2.3, для якого перше рішення (копія db) не працює.
Джек БеНімбл

2
Денні та Остін - Ваше рішення було ідеальним. У мене були проблеми з домашнім розчином і натрапили на ваше. Це дійсно потрапило на місце. Дякуємо, що знайшли час для її надання.
Джордж Бейкер

4
Я дуже віддаю перевагу цій відповіді проти голосуючих та прийнятих. У ньому є вся інформація в одному місці (не дивіться частини цього посилання) і згадуються деякі особливості Android, про які я не мав уявлення (наприклад, СТВОРИТИ ТАБЛИЦЮ "android_metadata"). Також приклади написані дуже докладно, що є плюсом. Це майже рішення для копіювання пасти, яке не завжди добре, але пояснення між кодом чудові.
Ігор Чордаш

Я використовую той самий метод, але я стикаюся з однією проблемою. Як ми можемо скопіювати всі існуючі дані зі старого в новий db-файл більш простим способом.
Панкай

130

SQLiteAssetHelperБібліотека робить цю задачу дуже просто.

Це легко додати як залежність від ступеня (але Jar також доступний для Ant / Eclipse), і разом з документацією його можна знайти за посиланням:
https://github.com/jgilfelt/android-sqlite-asset-helper

Примітка. Цей проект більше не підтримується, як зазначено вище на посилання Github.

Як пояснено в документації:

  1. Додайте залежність у файл збірки gradle модуля:

    dependencies {
        compile 'com.readystatesoftware.sqliteasset:sqliteassethelper:+'
    }
  2. Скопіюйте базу даних у каталог активів у підкаталог, який називається assets/databases. Наприклад:
    assets/databases/my_database.db

    (За бажанням, ви можете стиснути базу даних у zip-файлі, наприклад assets/databases/my_database.zip. Це не потрібно, оскільки APK вже стиснуто в цілому.)

  3. Створіть клас, наприклад:

    public class MyDatabase extends SQLiteAssetHelper {
    
        private static final String DATABASE_NAME = "my_database.db";
        private static final int DATABASE_VERSION = 1;
    
        public MyDatabase(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }
    }

Для завантаження андроїд-sqlite-asset-helper.jar потрібні дані?
Pr38y

1
Якщо ви використовуєте gradle, то ви просто додаєте залежність.
Сурагч

Як ви отримуєте дані з БД?
Мачадо

Це ще простіше з Android Studio та gradle. Перевірте посилання!
bendaf

5
Зауважте, що ця бібліотека покинута, останнє оновлення - 4 роки тому.
зменшення активності

13

Моє рішення не використовує жодної сторонньої бібліотеки і не примушує вас викликати спеціальні методи SQLiteOpenHelperпідкласу для ініціалізації бази даних про створення. Він також піклується про оновлення бази даних. Все, що потрібно зробити - це підклас SQLiteOpenHelper.

Необхідна умова:

  1. База даних, яку ви хочете поставити разом із додатком. Він повинен містити таблицю 1x1 android_metadataз атрибутом, що localeмає значення en_USна додаток до таблиць, унікальних для вашої програми.

Підкласифікація SQLiteOpenHelper:

  1. Підклас SQLiteOpenHelper.
  2. Створіть privateметод у межах SQLiteOpenHelperпідкласу. Цей метод містить логіку копіювання вмісту бази даних з файлу бази даних у папці "Активи" в базу даних, створену в контексті пакета додатків.
  3. Override onCreate, onUpgrade і onOpen методи SQLiteOpenHelper.

Достатньо сказано. Тут йде SQLiteOpenHelperпідклас:

public class PlanDetailsSQLiteOpenHelper extends SQLiteOpenHelper {
    private static final String TAG = "SQLiteOpenHelper";

    private final Context context;
    private static final int DATABASE_VERSION = 1;
    private static final String DATABASE_NAME = "my_custom_db";

    private boolean createDb = false, upgradeDb = false;

    public PlanDetailsSQLiteOpenHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        this.context = context;
    }

    /**
     * Copy packaged database from assets folder to the database created in the
     * application package context.
     * 
     * @param db
     *            The target database in the application package context.
     */
    private void copyDatabaseFromAssets(SQLiteDatabase db) {
        Log.i(TAG, "copyDatabase");
        InputStream myInput = null;
        OutputStream myOutput = null;
        try {
            // Open db packaged as asset as the input stream
            myInput = context.getAssets().open("path/to/shipped/db/file");

            // Open the db in the application package context:
            myOutput = new FileOutputStream(db.getPath());

            // Transfer db file contents:
            byte[] buffer = new byte[1024];
            int length;
            while ((length = myInput.read(buffer)) > 0) {
                myOutput.write(buffer, 0, length);
            }
            myOutput.flush();

            // Set the version of the copied database to the current
            // version:
            SQLiteDatabase copiedDb = context.openOrCreateDatabase(
                DATABASE_NAME, 0, null);
            copiedDb.execSQL("PRAGMA user_version = " + DATABASE_VERSION);
            copiedDb.close();

        } catch (IOException e) {
            e.printStackTrace();
            throw new Error(TAG + " Error copying database");
        } finally {
            // Close the streams
            try {
                if (myOutput != null) {
                    myOutput.close();
                }
                if (myInput != null) {
                    myInput.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
                throw new Error(TAG + " Error closing streams");
            }
        }
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.i(TAG, "onCreate db");
        createDb = true;
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.i(TAG, "onUpgrade db");
        upgradeDb = true;
    }

    @Override
    public void onOpen(SQLiteDatabase db) {
        Log.i(TAG, "onOpen db");
        if (createDb) {// The db in the application package
            // context is being created.
            // So copy the contents from the db
            // file packaged in the assets
            // folder:
            createDb = false;
            copyDatabaseFromAssets(db);

        }
        if (upgradeDb) {// The db in the application package
            // context is being upgraded from a lower to a higher version.
            upgradeDb = false;
            // Your db upgrade logic here:
        }
    }
}

Нарешті, щоб встановити з'єднання з базою даних, просто зателефонуйте getReadableDatabase()або getWritableDatabase()на SQLiteOpenHelperпідклас, і він подбає про створення db, копіювання вмісту db із зазначеного файлу у папці "активи", якщо база даних не існує.

Коротше кажучи, ви можете використовувати SQLiteOpenHelperпідклас для доступу до db, що надходить у папку активів так само, як ви використовували б для бази даних, яка ініціалізується за допомогою SQL-запитів у onCreate()методі.


2
Це найелегантніше рішення, використовуючи стандартні API для Android, не потребуючи зовнішніх бібліотек. Як зауваження, я не включив таблицю android_metadata, і вона працює, новіші версії Android можуть додавати її автоматично.
goetzc

12

Доставка програми з файлом бази даних в Android Studio 3.0

Доставка програми з файлом бази даних - це гарна ідея для мене. Перевага полягає в тому, що вам не потрібно робити складну ініціалізацію, яка іноді коштує багато часу, якщо ваш набір даних величезний.

Крок 1: Підготуйте файл бази даних

Підготуйте файл вашої бази даних Це може бути або .db-файл, або .sqlite-файл. Якщо ви використовуєте .sqlite файл, все, що вам потрібно зробити, - це змінити імена розширень файлів. Етапи однакові.

У цьому прикладі я підготував файл під назвою testDB.db. У ній є одна таблиця і деякі вибіркові дані введіть тут опис зображення

Крок 2. Імпортуйте файл у свій проект

Створіть папку активів, якщо у вас її не було. Потім скопіюйте та вставте файл бази даних у цю папку

введіть тут опис зображення

Крок 3. Скопіюйте файл у папку даних програми

Для подальшої взаємодії з ним потрібно скопіювати файл бази даних у папку даних програми. Це разова дія (ініціалізація) для копіювання файлу бази даних. Якщо ви зателефонуєте за цим кодом кілька разів, файл бази даних у папці даних буде замінено файлом у папці активів. Цей процес перезапису корисний, коли ви хочете оновити базу даних у майбутньому під час оновлення програми.

Зауважте, що під час оновлення програми цей файл бази даних не буде змінено у папці даних програми. Лише видалення видалить його.

Файл бази даних потрібно скопіювати в /databasesпапку. Відкрийте Провідник файлів пристроїв. Введіть data/data/<YourAppName>/місцезнаходження. Це згадана вище папка даних за замовчуванням. І за замовчуванням файл бази даних буде розміщений в іншій папці під назвою баз даних під цим каталогом

введіть тут опис зображення

Тепер процес копіювання файлів дуже схожий на те, що робить Java. Використовуйте наступний код, щоб зробити папку для копіювання. Це код ініціації. Він також може бути використаний для оновлення (перезапису) файлу бази даних у майбутньому.

//get context by calling "this" in activity or getActivity() in fragment
//call this if API level is lower than 17  String appDataPath = "/data/data/" + context.getPackageName() + "/databases/"
String appDataPath = context.getApplicationInfo().dataDir;

File dbFolder = new File(appDataPath + "/databases");//Make sure the /databases folder exists
dbFolder.mkdir();//This can be called multiple times.

File dbFilePath = new File(appDataPath + "/databases/testDB.db");

try {
    InputStream inputStream = context.getAssets().open("testDB.db");
    OutputStream outputStream = new FileOutputStream(dbFilePath);
    byte[] buffer = new byte[1024];
    int length;
    while ((length = inputStream.read(buffer))>0)
    {
        outputStream.write(buffer, 0, length);
    }
    outputStream.flush();
    outputStream.close();
    inputStream.close();
} catch (IOException e){
    //handle
}

Потім оновіть папку, щоб перевірити процес копіювання

введіть тут опис зображення

Крок 4: Створення помічника відкритої бази даних

Створіть підклас для SQLiteOpenHelper, за допомогою підключення, закриття, шляху тощо. Я його назвавDatabaseOpenHelper

import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DatabaseOpenHelper extends SQLiteOpenHelper {
    public static final String DB_NAME = "testDB.db";
    public static final String DB_SUB_PATH = "/databases/" + DB_NAME;
    private static String APP_DATA_PATH = "";
    private SQLiteDatabase dataBase;
    private final Context context;

    public DatabaseOpenHelper(Context context){
        super(context, DB_NAME, null, 1);
        APP_DATA_PATH = context.getApplicationInfo().dataDir;
        this.context = context;
    }

    public boolean openDataBase() throws SQLException{
        String mPath = APP_DATA_PATH + DB_SUB_PATH;
        //Note that this method assumes that the db file is already copied in place
        dataBase = SQLiteDatabase.openDatabase(mPath, null, SQLiteDatabase.OPEN_READWRITE);
        return dataBase != null;
    }

    @Override
    public synchronized void close(){
        if(dataBase != null) {dataBase.close();}
        super.close();
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}

Крок 5: Створіть клас вищого рівня для взаємодії з базою даних

Це буде клас, який читає та записує файл вашої бази даних. Також є зразок запиту для друку значень у базі даних.

import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

public class Database {
    private final Context context;
    private SQLiteDatabase database;
    private DatabaseOpenHelper dbHelper;

    public Database(Context context){
        this.context = context;
        dbHelper = new DatabaseOpenHelper(context);
    }

    public Database open() throws SQLException
    {
        dbHelper.openDataBase();
        dbHelper.close();
        database = dbHelper.getReadableDatabase();
        return this;
    }

    public void close()
    {
        dbHelper.close();
    }

    public void test(){
        try{
            String query ="SELECT value FROM test1";
            Cursor cursor = database.rawQuery(query, null);
            if (cursor.moveToFirst()){
                do{
                    String value = cursor.getString(0);
                    Log.d("db", value);
                }while (cursor.moveToNext());
            }
            cursor.close();
        } catch (SQLException e) {
            //handle
        }
    }
}

Крок 6: Випробування на виконання

Перевірте код, виконавши наступні рядки кодів.

Database db = new Database(context);
db.open();
db.test();
db.close();

Натисніть кнопку запуску та розвеселіть

введіть тут опис зображення


1
коли слід зробити ініціалізацію? Яку стратегію ви пропонуєте?
Даніеле Б

8

У листопаді 2017 року Google випустив Бібліотеку наполегливості кімнати .

З документації:

Бібліотека стійкості кімнати забезпечує рівень абстракції над сильним текстом Lite, щоб забезпечити вільний доступ до бази даних, використовуючи повну потужність SQLite .

Бібліотека допомагає створити кеш даних вашої програми на пристрої, на якому працює ваш додаток. Цей кеш, який служить єдиним джерелом істини вашого додатка, дозволяє користувачам переглядати послідовну копію ключової інформації у вашому додатку, незалежно від того, чи мають користувачі Інтернет.

База даних кімнати має зворотний виклик, коли база даних вперше створена або відкрита. Ви можете використовувати зворотний виклик створення для заповнення вашої бази даних.

Room.databaseBuilder(context.applicationContext,
        DataDatabase::class.java, "Sample.db")
        // prepopulate the database after onCreate was called
        .addCallback(object : Callback() {
            override fun onCreate(db: SupportSQLiteDatabase) {
                super.onCreate(db)
                // moving to a new thread
                ioThread {
                    getInstance(context).dataDao()
                                        .insert(PREPOPULATE_DATA)
                }
            }
        })
        .build()

Код з цієї публікації в блозі .


Дякую, це працювало для мене. Приклад Java тут
Джеррі Ша

1
Якщо ви хочете відправити APK з уже існуючим SQLite, ви можете додати його до папки активів і використовувати цей пакет github.com/humazed/RoomAsset для виконання міграції, яка завантажить дані файлу SQLite в нову. Таким чином, ви можете зберегти заповнення даних за допомогою існуючої БД.
xarlymg89

6

З того, що я бачив, ви повинні відправляти базу даних, у якій вже встановлені таблиці та дані. Однак якщо ви хочете (і залежно від типу програми), ви можете дозволити "опцію оновлення бази даних". Тоді ви завантажуєте останню версію sqlite, отримуєте останню Вставку / Створення висловлювань текстового файлу, розміщеного в Інтернеті, виконайте оператори та виконайте передачу даних зі старого DB на нову.


6
> З того, що я бачив, ви повинні відправляти базу даних, у якій вже встановлені таблиці та дані. Так, але як це зробити?
Рорі

5

Нарешті я це зробив !! Я використав цю допомогу за посиланням Використання власної бази даних SQLite в додатках для Android , але довелося її трохи змінити.

  1. Якщо у вас є багато пакетів, слід вказати ім'я головного пакета:

    private static String DB_PATH = "data/data/masterPakageName/databases";

  2. Я змінив метод, який копіює базу даних з локальної папки в папку емулятора! Була певна проблема, коли ця папка не існувала. Отже, перш за все, він повинен перевірити шлях, і якщо його там немає, він повинен створити папку.

  3. У попередньому коді copyDatabaseметод ніколи не викликався, коли база даних не існувала і checkDataBaseметод викликав виняток. тому я трохи змінив код.

  4. Якщо у вашій базі даних немає розширення файлу, не використовуйте ім'я файлу з одним.

це працює добре для мене, я сподіваюся, що це буде корисно і для вас

    package farhangsarasIntroduction;


import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;

import android.content.Context;
import android.database.Cursor;

import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;

import android.util.Log;


    public class DataBaseHelper extends SQLiteOpenHelper{

    //The Android's default system path of your application database.
    private static String DB_PATH = "data/data/com.example.sample/databases";

    private static String DB_NAME = "farhangsaraDb";

    private SQLiteDatabase myDataBase;

    private final Context myContext;

    /**
      * 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, 1);
            this.myContext = context;

    }   

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

        boolean dbExist;
        try {

             dbExist = checkDataBase();


        } catch (SQLiteException e) {

            e.printStackTrace();
            throw new Error("database dose not exist");

        }

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

            try {

                copyDataBase();


            } catch (IOException e) {

                e.printStackTrace();
                throw new Error("Error copying database");

            }
    //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();


    }

    }

    /**
      * 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;

    try{
        String myPath = DB_PATH +"/"+ DB_NAME;

        checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
    }catch(SQLiteException e){

    //database does't exist yet.
        throw new Error("database does't exist yet.");

    }

    if(checkDB != null){

    checkDB.close();

    }

    return checkDB != null ? true : 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{



            //copyDataBase();
            //Open your local db as the input stream
            InputStream myInput = myContext.getAssets().open(DB_NAME);

            // Path to the just created empty db
            String outFileName = DB_PATH +"/"+ DB_NAME;
            File databaseFile = new File( DB_PATH);
             // check if databases folder exists, if not create one and its subfolders
            if (!databaseFile.exists()){
                databaseFile.mkdir();
            }

            //Open the empty db as the output stream
            OutputStream myOutput = new FileOutputStream(outFileName);

            //transfer bytes from the inputfile to the outputfile
            byte[] buffer = new byte[1024];
            int length;
            while ((length = myInput.read(buffer))>0){
            myOutput.write(buffer, 0, length);
            }

            //Close the streams
            myOutput.flush();
            myOutput.close();
            myInput.close();



    }



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

    }

     you to create adapters for your views.

}

Ви можете, будь ласка, дайте мені знати, як оновити db, якщо я хочу замінити стару базу даних на нову, як я можу видалити старий db
Erum

Мені не потрібно робити це до цих пір, але якщо встановлено нову програму, новий db також замінить
афсайд

як видалити стару базу даних, тому що я додаю новий db у папку активів, то як я видалю старий db із зазначеної папки, інакше він принесе вміст старого db
Erum,

Я сподіваюся , що це буде корисна stackoverflow.com/questions/9109438 / ...
afsane

Ідеально, дякую! Лише один коментар, викидання виключення під час перевірки бази даних призводить до закриття програми, оскільки БД не буде там на початку, а метод не продовжується після скидання винятку. Я просто прокоментував нову помилку викидання ("доза бази даних не існує"); і зараз все працює ідеально.
Гріннер

4

В даний час немає можливості попередньо створити базу даних SQLite для доставки з вашим apk. Найкраще, що ви можете зробити, це зберегти відповідний SQL як ресурс і запустити їх зі своєї програми. Так, це призводить до дублювання даних (така ж інформація існує як у перегрупуванні, так і у базі даних), але іншого шляху зараз немає. Єдиним пом’якшувальним фактором є стиснення файлу apk. Мій досвід - 908 КБ стискається до менш ніж 268 КБ.

Нитка нижче має найкраще обговорення / рішення, яке я знайшов із хорошим зразком коду.

http://groups.google.com/group/android-developers/msg/9f455ae93a1cf152

Я зберігав свій оператор CREATE як рядовий ресурс, який слід читати з Context.getString (), і запускав його з SQLiteDatabse.execSQL ().

Я зберігав дані для своїх вставок у res / raw / insertts.sql (я створив файл sql, 7000+ рядків). Використовуючи техніку із посилання вище, я ввів цикл, прочитав файл за рядком і змістив дані на "ВСТАВЛЯЙТЬСЯ в tbl VALUE" і зробив ще один SQLiteDatabase.execSQL (). Немає сенсу економити 7000 "ВСТАВЛЯЙТЬСЯ в tbl VALUE", коли їх можна просто занести.

На емуляторі йде близько двадцяти секунд, я не знаю, скільки часу це займе на реальному телефоні, але це відбувається лише один раз, коли користувач вперше запустить додаток.


3
Як щодо витягування сценарію SQL з Інтернету при першому запуску? Таким чином, немає необхідності дублювати дані.
Тамас Цінеге

1
Так, але пристрій потрібно буде підключити до Інтернету. Це серйозний недолік у деяких додатках.
Джунейт

Не робіть 7000+ вставок, робіть пакетні вставки 100 або приблизно так - INSERT INTO table VALUES(...) VALUES(...) VALUES(...) ...(1 рядок вставки повинен мати 100 ЦІННОСТЕЙ). Це буде набагато ефективніше і скоротить час запуску з 20 секунд до 2 або 3 сек.
Mohit Atray

4

Додавання бази даних всередині apk, а потім її копіювання /data/data/...вдвічі збільшить розмір бази даних (1 в apk, 1 in data/data/...) і збільшить розмір apk (звичайно). Отже, ваша база даних не повинна бути занадто великою.


2
Це дещо збільшує розмір apk, але не подвоює його. Коли він знаходиться в активах, він стискається і так набагато менше. Після копіювання в папку бази даних вона не стискається.
Сурагч

3

Android вже пропонує підхід до управління базами даних, що обізнаний з версіями. Цей підхід застосовується в рамках програми BARACUS для додатків Android.

Це дозволяє вам керувати базою даних протягом усього життєвого циклу версії програми, маючи можливість оновити базу даних sqlite від будь-якої попередньої версії до поточної.

Крім того, це дозволяє запускати резервні копії та гаряче відновлення SQLite.

Я не впевнений на 100%, але швидке відновлення для конкретного пристрою може надати вам можливість відправляти підготовлену базу даних у вашому додатку. Але я не впевнений у двійковому форматі бази даних, який може бути специфічним для певних пристроїв, постачальників чи поколінь пристроїв.

Оскільки матеріал є ліцензією Apache 2, сміливо використовуйте будь-яку частину коду, яку можна знайти в github

Редагувати:

Якщо ви хочете лише надсилати дані, ви можете розглянути можливість інстанціювання та збереження POJO під час першого запуску програм. BARACUS отримав вбудовану підтримку цього (Вбудований сховище ключів для інформації про конфігурацію, наприклад, "APP_FIRST_RUN" плюс гак після завантаження після контексту для запуску операцій після запуску в контексті). Це дозволяє вам мати щільно поєднані дані, що постачаються разом із вашим додатком; в більшості випадків це підходило до моїх випадків використання.


3

Якщо потрібні дані не надто великі (обмеження, які я не знаю, залежало б від багатьох речей), ви також можете завантажити дані (у XML, JSON, будь-що інше) з веб-сайту / webapp. Після отримання, виконайте оператори SQL, використовуючи отримані дані, створюючи ваші таблиці та вставляючи дані.

Якщо ваш мобільний додаток містить велику кількість даних, згодом може бути простіше оновити дані в встановлених програмах з точнішими даними або змінами.


3

Я змінив клас та відповіді на запитання та написав клас, який дозволяє оновлювати базу даних через DB_VERSION.

public class DatabaseHelper extends SQLiteOpenHelper {
    private static String DB_NAME = "info.db";
    private static String DB_PATH = "";
    private static final int DB_VERSION = 1;

    private SQLiteDatabase mDataBase;
    private final Context mContext;
    private boolean mNeedUpdate = false;

    public DatabaseHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
        if (android.os.Build.VERSION.SDK_INT >= 17)
            DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
        else
            DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
        this.mContext = context;

        copyDataBase();

        this.getReadableDatabase();
    }

    public void updateDataBase() throws IOException {
        if (mNeedUpdate) {
            File dbFile = new File(DB_PATH + DB_NAME);
            if (dbFile.exists())
                dbFile.delete();

            copyDataBase();

            mNeedUpdate = false;
        }
    }

    private boolean checkDataBase() {
        File dbFile = new File(DB_PATH + DB_NAME);
        return dbFile.exists();
    }

    private void copyDataBase() {
        if (!checkDataBase()) {
            this.getReadableDatabase();
            this.close();
            try {
                copyDBFile();
            } catch (IOException mIOException) {
                throw new Error("ErrorCopyingDataBase");
            }
        }
    }

    private void copyDBFile() throws IOException {
        InputStream mInput = mContext.getAssets().open(DB_NAME);
        //InputStream mInput = mContext.getResources().openRawResource(R.raw.info);
        OutputStream mOutput = new FileOutputStream(DB_PATH + DB_NAME);
        byte[] mBuffer = new byte[1024];
        int mLength;
        while ((mLength = mInput.read(mBuffer)) > 0)
            mOutput.write(mBuffer, 0, mLength);
        mOutput.flush();
        mOutput.close();
        mInput.close();
    }

    public boolean openDataBase() throws SQLException {
        mDataBase = SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.CREATE_IF_NECESSARY);
        return mDataBase != null;
    }

    @Override
    public synchronized void close() {
        if (mDataBase != null)
            mDataBase.close();
        super.close();
    }

    @Override
    public void onCreate(SQLiteDatabase db) {

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        if (newVersion > oldVersion)
            mNeedUpdate = true;
    }
}

Використання класу.

У класі активності оголосіть змінні.

private DatabaseHelper mDBHelper;
private SQLiteDatabase mDb;

У методі onCreate введіть наступний код.

mDBHelper = new DatabaseHelper(this);

try {
    mDBHelper.updateDataBase();
} catch (IOException mIOException) {
    throw new Error("UnableToUpdateDatabase");
}

try {
    mDb = mDBHelper.getWritableDatabase();
} catch (SQLException mSQLException) {
    throw mSQLException;
}

Якщо ви додасте файл бази даних до папки res / raw, використовуйте наступну модифікацію класу.

public class DatabaseHelper extends SQLiteOpenHelper {
    private static String DB_NAME = "info.db";
    private static String DB_PATH = "";
    private static final int DB_VERSION = 1;

    private SQLiteDatabase mDataBase;
    private final Context mContext;
    private boolean mNeedUpdate = false;

    public DatabaseHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
        if (android.os.Build.VERSION.SDK_INT >= 17)
            DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
        else
            DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
        this.mContext = context;

        copyDataBase();

        this.getReadableDatabase();
    }

    public void updateDataBase() throws IOException {
        if (mNeedUpdate) {
            File dbFile = new File(DB_PATH + DB_NAME);
            if (dbFile.exists())
                dbFile.delete();

            copyDataBase();

            mNeedUpdate = false;
        }
    }

    private boolean checkDataBase() {
        File dbFile = new File(DB_PATH + DB_NAME);
        return dbFile.exists();
    }

    private void copyDataBase() {
        if (!checkDataBase()) {
            this.getReadableDatabase();
            this.close();
            try {
                copyDBFile();
            } catch (IOException mIOException) {
                throw new Error("ErrorCopyingDataBase");
            }
        }
    }

    private void copyDBFile() throws IOException {
        //InputStream mInput = mContext.getAssets().open(DB_NAME);
        InputStream mInput = mContext.getResources().openRawResource(R.raw.info);
        OutputStream mOutput = new FileOutputStream(DB_PATH + DB_NAME);
        byte[] mBuffer = new byte[1024];
        int mLength;
        while ((mLength = mInput.read(mBuffer)) > 0)
            mOutput.write(mBuffer, 0, mLength);
        mOutput.flush();
        mOutput.close();
        mInput.close();
    }

    public boolean openDataBase() throws SQLException {
        mDataBase = SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.CREATE_IF_NECESSARY);
        return mDataBase != null;
    }

    @Override
    public synchronized void close() {
        if (mDataBase != null)
            mDataBase.close();
        super.close();
    }

    @Override
    public void onCreate(SQLiteDatabase db) {

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        if (newVersion > oldVersion)
            mNeedUpdate = true;
    }
}

http://blog.harrix.org/article/6784


2

Я написав бібліотеку, щоб спростити цей процес.

dataBase = new DataBase.Builder(context, "myDb").
//        setAssetsPath(). // default "databases"
//        setDatabaseErrorHandler().
//        setCursorFactory().
//        setUpgradeCallback()
//        setVersion(). // default 1
build();

Це створить базу даних з assets/databases/myDb.dbфайлу. Крім того, ви отримаєте всі ці функції:

  • Завантажте базу даних з файлу
  • Синхронізований доступ до бази даних
  • Використання sqlite-android за запитом, розповсюдження ОС Android для останніх версій SQLite.

Клоніруйте його з github .


2

Я використовую ORMLite і нижче код працював для мене

public class DatabaseProvider extends OrmLiteSqliteOpenHelper {
    private static final String DatabaseName = "DatabaseName";
    private static final int DatabaseVersion = 1;
    private final Context ProvidedContext;

    public DatabaseProvider(Context context) {
        super(context, DatabaseName, null, DatabaseVersion);
        this.ProvidedContext= context;
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        boolean databaseCopied = preferences.getBoolean("DatabaseCopied", false);
        if (databaseCopied) {
            //Do Nothing
        } else {
            CopyDatabase();
            SharedPreferences.Editor editor = preferences.edit();
            editor.putBoolean("DatabaseCopied", true);
            editor.commit();
        }
    }

    private String DatabasePath() {
        return "/data/data/" + ProvidedContext.getPackageName() + "/databases/";
    }

    private void CopyDatabase() {
        try {
            CopyDatabaseInternal();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private File ExtractAssetsZip(String zipFileName) {
        InputStream inputStream;
        ZipInputStream zipInputStream;
        File tempFolder;
        do {
            tempFolder = null;
            tempFolder = new File(ProvidedContext.getCacheDir() + "/extracted-" + System.currentTimeMillis() + "/");
        } while (tempFolder.exists());

        tempFolder.mkdirs();

        try {
            String filename;
            inputStream = ProvidedContext.getAssets().open(zipFileName);
            zipInputStream = new ZipInputStream(new BufferedInputStream(inputStream));
            ZipEntry zipEntry;
            byte[] buffer = new byte[1024];
            int count;

            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                filename = zipEntry.getName();
                if (zipEntry.isDirectory()) {
                    File fmd = new File(tempFolder.getAbsolutePath() + "/" + filename);
                    fmd.mkdirs();
                    continue;
                }

                FileOutputStream fileOutputStream = new FileOutputStream(tempFolder.getAbsolutePath() + "/" + filename);
                while ((count = zipInputStream.read(buffer)) != -1) {
                    fileOutputStream.write(buffer, 0, count);
                }

                fileOutputStream.close();
                zipInputStream.closeEntry();
            }

            zipInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

        return tempFolder;
    }

    private void CopyDatabaseInternal() throws IOException {

        File extractedPath = ExtractAssetsZip(DatabaseName + ".zip");
        String databaseFile = "";
        for (File innerFile : extractedPath.listFiles()) {
            databaseFile = innerFile.getAbsolutePath();
            break;
        }
        if (databaseFile == null || databaseFile.length() ==0 )
            throw new RuntimeException("databaseFile is empty");

        InputStream inputStream = new FileInputStream(databaseFile);

        String outFileName = DatabasePath() + DatabaseName;

        File destinationPath = new File(DatabasePath());
        if (!destinationPath.exists())
            destinationPath.mkdirs();

        File destinationFile = new File(outFileName);
        if (!destinationFile.exists())
            destinationFile.createNewFile();

        OutputStream myOutput = new FileOutputStream(outFileName);

        byte[] buffer = new byte[1024];
        int length;
        while ((length = inputStream.read(buffer)) > 0) {
            myOutput.write(buffer, 0, length);
        }

        myOutput.flush();
        myOutput.close();
        inputStream.close();
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase, ConnectionSource connectionSource) {
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, ConnectionSource connectionSource, int fromVersion, int toVersion) {

    }
}

Зверніть увагу: Код витягує файл бази даних з zip-файлу в активах

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.