Expédier une application avec une firebase database

Si votre application nécessite une firebase database et qu’elle contient des données intégrées, quelle est la meilleure façon d’envoyer cette application? Devrais-je:

  1. Pré-créer la firebase database SQLite et l’inclure dans le .apk ?

  2. Inclure les commandes SQL avec l’application et créer la firebase database et insérer les données lors de la première utilisation?

Les inconvénients que je vois sont:

  1. La non-concordance possible des versions de SQLite peut causer des problèmes et je ne connais pas actuellement l’emplacement de la firebase database et la manière d’y accéder.

  2. La création et le remplissage de la firebase database sur le périphérique peut prendre beaucoup de temps.

Aucune suggestion? Les pointeurs vers la documentation concernant tout problème seraient grandement appréciés.

Je viens de trouver un moyen de le faire dans le blog ReignDesign dans un article intitulé Utiliser votre propre firebase database SQLite dans les applications Android . Fondamentalement, vous pré-créez votre firebase database, placez-la dans votre répertoire de ressources dans votre apk et, lors de la première utilisation, copiez-la dans le répertoire “/ data / data / YOUR_PACKAGE / databases /”.

Il existe deux options pour créer et mettre à jour des bases de données.

L’une consiste à créer une firebase database en externe, puis à la placer dans le dossier des ressources du projet, puis à copier l’intégralité de la firebase database. C’est beaucoup plus rapide si la firebase database contient beaucoup de tables et d’autres composants. Les mises à niveau sont déclenchées en modifiant le numéro de version de la firebase database dans le fichier res / values ​​/ ssortingngs.xml. Les mises à niveau seraient alors réalisées en créant une nouvelle firebase database en externe, en remplaçant l’ancienne firebase database dans le dossier assets par la nouvelle base, en sauvegardant l’ancienne firebase database sous un autre nom, en copiant la nouvelle base des données de l’ancienne firebase database (qui a été renommée précédemment) dans la nouvelle firebase database et enfin la suppression de l’ancienne firebase database. Vous pouvez créer une firebase database à l’origine en utilisant le plug-in SQLite Manager FireFox pour exécuter vos instructions SQL de création.

L’autre option consiste à créer une firebase database en interne à partir d’un fichier SQL. Ce n’est pas aussi rapide mais le délai serait probablement invisible pour les utilisateurs si la firebase database ne contient que quelques tables. Les mises à niveau sont déclenchées en modifiant le numéro de version de la firebase database dans le fichier res / values ​​/ ssortingngs.xml. Les mises à niveau seraient alors effectuées en traitant un fichier sql de mise à niveau. Les données de la firebase database restront inchangées, sauf si leur conteneur est supprimé, par exemple en supprimant une table.

L’exemple ci-dessous montre comment utiliser l’une ou l’autre méthode.

Voici un exemple de fichier create_database.sql. Il doit être placé dans le dossier assets du projet pour la méthode interne ou copié dans le fichier “Execute SQL” de SQLite Manager pour créer la firebase database pour la méthode externe (REMARQUE: notez le commentaire concernant la table requirejse par 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"; 

Voici un exemple de fichier update_database.sql. Il doit être placé dans le dossier assets du projet pour la méthode interne ou copié dans le fichier “Execute SQL” du gestionnaire SQLite pour créer la firebase database pour la méthode externe (REMARQUE: les trois types de commentaires SQL seront ignorés). par l’parsingur SQL inclus dans cet exemple.)

 --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'); 

Voici une entrée à append au fichier /res/values/ssortingngs.xml pour le numéro de version de la firebase database.

 1 

Voici une activité qui accède à la firebase database et l’utilise ensuite. ( Remarque: vous souhaiterez peut-être exécuter le code de firebase database dans un thread distinct s’il utilise beaucoup de ressources. )

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

Voici la classe d’assistance de firebase database où la firebase database est créée ou mise à jour si nécessaire. (REMARQUE: Android exige que vous créez une classe qui étend SQLiteOpenHelper afin de fonctionner avec une firebase database 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 Ssortingng DB_DIR = "/data/data/android.example/databases/"; private static Ssortingng DB_NAME = "database.sqlite"; private static Ssortingng DB_PATH = DB_DIR + DB_NAME; private static Ssortingng 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.ssortingng.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. * 

* 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 resortingeved 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"); // // Ssortingng[] statements = FileHelper.parseSqlFile(is); // // for (Ssortingng 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"); // // Ssortingng[] statements = FileHelper.parseSqlFile(is); // // for (Ssortingng 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. */ }

Voici la classe FileHelper qui contient des méthodes pour copier des fichiers dans le stream d’octets et parsingr des fichiers 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 toFile that is a byte for byte a copy * of fromFile. If toFile already existed, then * it will be replaced with a copy of fromFile. The name and * path of toFile will be that of toFile. Both * fromFile and toFile 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 toFile that is a byte for byte a copy * of fromFile. If toFile already existed, then * it will be replaced with a copy of fromFile. The name and * path of toFile will be that of toFile. Both * fromFile and toFile will be closed by this * operation. * * @param fromFile * - Ssortingng specifying the path of the file to copy from. * @param toFile * - Ssortingng specifying the path of the file to copy to. */ public static void copyFile(Ssortingng fromFile, Ssortingng toFile) throws IOException { copyFile(new FileInputStream(fromFile), new FileOutputStream(toFile)); } /** * Creates the specified toFile that is a byte for byte a copy * of fromFile. If toFile already existed, then * it will be replaced with a copy of fromFile. The name and * path of toFile will be that of toFile. Both * fromFile and toFile 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 toFile that is a byte for byte a copy * of fromFile. If toFile already existed, then * it will be replaced with a copy of fromFile. The name and * path of toFile will be that of toFile. Both * fromFile and toFile 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 Ssortingng array that contains * only the sql statements. Comments and white spaces in the file are not * parsed into the Ssortingng 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 Ssortingng * array will not end with a semi-colon ";". * * @param sqlFile * - Ssortingng containing the path for the file that contains sql * statements. * * @return Ssortingng array containing the sql statements. */ public static Ssortingng[] parseSqlFile(Ssortingng sqlFile) throws IOException { return parseSqlFile(new BufferedReader(new FileReader(sqlFile))); } /** * Parses a file containing sql statements into a Ssortingng array that contains * only the sql statements. Comments and white spaces in the file are not * parsed into the Ssortingng 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 Ssortingng * array will not end with a semi-colon ";". * * @param sqlFile * - InputStream for the file that contains sql statements. * * @return Ssortingng array containing the sql statements. */ public static Ssortingng[] parseSqlFile(InputStream sqlFile) throws IOException { return parseSqlFile(new BufferedReader(new InputStreamReader(sqlFile))); } /** * Parses a file containing sql statements into a Ssortingng array that contains * only the sql statements. Comments and white spaces in the file are not * parsed into the Ssortingng 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 Ssortingng * array will not end with a semi-colon ";". * * @param sqlFile * - Reader for the file that contains sql statements. * * @return Ssortingng array containing the sql statements. */ public static Ssortingng[] parseSqlFile(Reader sqlFile) throws IOException { return parseSqlFile(new BufferedReader(sqlFile)); } /** * Parses a file containing sql statements into a Ssortingng array that contains * only the sql statements. Comments and white spaces in the file are not * parsed into the Ssortingng 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 Ssortingng * array will not end with a semi-colon ";". * * @param sqlFile * - BufferedReader for the file that contains sql statements. * * @return Ssortingng array containing the sql statements. */ public static Ssortingng[] parseSqlFile(BufferedReader sqlFile) throws IOException { Ssortingng line; SsortingngBuilder sql = new SsortingngBuilder(); Ssortingng multiLineComment = null; while ((line = sqlFile.readLine()) != null) { line = line.sortingm(); // 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.toSsortingng().split(";"); } } 

La bibliothèque SQLiteAssetHelper rend cette tâche très simple.

Il est facile d’append une dépendance progressive (mais un Jar est également disponible pour Ant / Eclipse) et, avec la documentation, il peut être trouvé à l’adresse suivante:
https://github.com/jgilfelt/android-sqlite-asset-helper

Comme expliqué dans la documentation:

  1. Ajoutez la dépendance au fichier de construction graduel de votre module:

     dependencies { comstack 'com.readystatesoftware.sqliteasset:sqliteassethelper:+' } 
  2. Copiez la firebase database dans le répertoire assets, dans un sous-répertoire appelé assets/databases . Par exemple:
    assets/databases/my_database.db

    (Éventuellement, vous pouvez compresser la firebase database dans un fichier zip tel que assets/databases/my_database.zip . Cela n’est pas nécessaire, car l’APK est déjà compressé dans son ensemble.)

  3. Créez une classe, par exemple:

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

J’imagine que la meilleure et la plus récente façon d’utiliser jusqu’à maintenant utilise la classe SQLiteAssetHelper .

Ce tutoriel vous guide parfaitement à travers l’ importation et l’utilisation de la firebase database externe dans Android

La bibliothèque Android SQLiteAssetHelper vous permet de créer votre SQLite données SQLite sur votre ordinateur de bureau, de l’importer et de l’utiliser dans votre application Android. Créons une application simple pour démontrer l’application de cette bibliothèque.

Etape 1 : Créez une firebase database quotes.db à l’aide de votre application de firebase database SQLite préférée (DB Browser for SQLite est un logiciel gratuit multi-plateforme, qui peut être utilisé pour créer et éditer des bases de données SQLite). Créez une table “quotes” avec une seule colonne “quote”. Insérez des guillemets aléatoires dans la table ‘quotes’.

Etape 2 : La firebase database peut être imscope dans le projet directement comme tel ou sous forme de fichier compressé. Le fichier compressé est recommandé si votre firebase database est trop volumineuse. Vous pouvez créer une compression ZIP ou une compression GZ .

Le nom de fichier du fichier db compressé doit être quotes.db.zip , si vous utilisez la compression ZIP ou quotes.db.gz , si vous utilisez la compression GZ.

Étape 3 : Créer une nouvelle application External Database Demo avec un nom de package com.javahelps.com.javahelps.externaldatabasedemo .

Étape 4 : Ouvrez le build.gradle (Module: app) et ajoutez la dépendance suivante.

 dependencies { comstack 'com.readystatesoftware.sqliteasset:sqliteassethelper:+' } 

Une fois que vous avez enregistré le fichier build.gradle , cliquez sur le lien “Synchroniser maintenant” pour mettre à jour le projet. Vous pouvez synchroniser le build.gradle en cliquant avec le bouton droit sur le fichier build.gradle et en sélectionnant Synchronize build.gradle option Synchronize build.gradle .

Étape 5 : Cliquez avec le bouton droit sur le dossier de l’application et créez un nouveau dossier de ressources.

Étape 6 : Créez un nouveau dossier “databases” dans le dossier assets.

Étape 7 : Copiez et collez le fichier quotes.db.zip dans le dossier assets/databases .

Étape 8 : Créer une nouvelle classe DatabaseOpenHelper

 package com.javahelps.externaldatabasedemo; import android.content.Context; import com.readystatesoftware.sqliteasset.SQLiteAssetHelper; public class DatabaseOpenHelper extends SQLiteAssetHelper { private static final Ssortingng DATABASE_NAME = "quotes.db"; private static final int DATABASE_VERSION = 1; public DatabaseOpenHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } } Notice that rather than extending SQLiteOpenHelper, the DatabaseOpenHelper extends SQLiteAssetHelper class. 

Étape 9 : Créez une nouvelle classe DatabaseAccess et entrez le code comme indiqué ci-dessous. Plus de détails sur cette classe sont disponibles dans le didacticiel Advanced Android Database.

 package com.javahelps.externaldatabasedemo; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import java.util.ArrayList; import java.util.List; public class DatabaseAccess { private SQLiteOpenHelper openHelper; private SQLiteDatabase database; private static DatabaseAccess instance; /** * Private constructor to aboid object creation from outside classes. * * @param context */ private DatabaseAccess(Context context) { this.openHelper = new DatabaseOpenHelper(context); } /** * Return a singleton instance of DatabaseAccess. * * @param context the Context * @return the instance of DabaseAccess */ public static DatabaseAccess getInstance(Context context) { if (instance == null) { instance = new DatabaseAccess(context); } return instance; } /** * Open the database connection. */ public void open() { this.database = openHelper.getWritableDatabase(); } /** * Close the database connection. */ public void close() { if (database != null) { this.database.close(); } } /** * Read all quotes from the database. * * @return a List of quotes */ public List getQuotes() { List list = new ArrayList<>(); Cursor cursor = database.rawQuery("SELECT * FROM quotes", null); cursor.moveToFirst(); while (!cursor.isAfterLast()) { list.add(cursor.getString(0)); cursor.moveToNext(); } cursor.close(); return list; } } In this class only the `getQuotes` method is implemented to read the data from the database. You have the full freedom to insert, 

mettre à jour et supprimer les lignes de la firebase database comme d’habitude. Pour plus de détails, suivez ce lien Advanced Android Database.

Toutes les configurations liées à la firebase database sont terminées et nous devons maintenant créer une ListView pour afficher les guillemets.

Étape 10 : Ajoutez un ListView dans votre activity_main.xml .

    

Etape 11 : Recherchez l’object de ListView dans la méthode MainActivity de MainActivity et alimentez les guillemets lus dans la firebase database.

 package com.javahelps.externaldatabasedemo; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.widget.ArrayAdapter; import android.widget.ListView; import java.util.List; public class MainActivity extends ActionBarActivity { private ListView listView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); this.listView = (ListView) findViewById(R.id.listView); DatabaseAccess databaseAccess = DatabaseAccess.getInstance(this); databaseAccess.open(); List quotes = databaseAccess.getQuotes(); databaseAccess.close(); ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, quotes); this.listView.setAdapter(adapter); } } 

Étape 12 : Enregistrez toutes les modifications et exécutez l’application.

En plus de cet article, vous pouvez télécharger SQLiteAssetHelper ici

Ma solution n’utilise aucune bibliothèque tierce ni ne vous oblige à appeler des méthodes personnalisées sur la sous-classe SQLiteOpenHelper pour initialiser la firebase database lors de la création. Il prend également en charge les mises à niveau de la firebase database. Il SQLiteOpenHelper sous- SQLiteOpenHelper .

Prérequirejs:

  1. La firebase database que vous souhaitez expédier avec l’application. Il devrait contenir une table 1×1 nommée android_metadata avec un locale android_metadata d’atsortingbut ayant la valeur en_US en plus des tables uniques à votre application.

Sous- SQLiteOpenHelper :

  1. Sous-classe SQLiteOpenHelper .
  2. Créez une méthode private dans la sous-classe SQLiteOpenHelper . Cette méthode contient la logique permettant de copier le contenu de la firebase database du fichier de firebase database dans le dossier «assets» vers la firebase database créée dans le contexte du package d’application.
  3. Remplacez les onCreate , onUpgrade et onOpen de SQLiteOpenHelper .

Assez dit. Voici la sous-classe SQLiteOpenHelper :

 public class PlanDetailsSQLiteOpenHelper extends SQLiteOpenHelper { private static final Ssortingng TAG = "SQLiteOpenHelper"; private final Context context; private static final int DATABASE_VERSION = 1; private static final Ssortingng 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: } } } 

Finally, to get a database connection, just call getReadableDatabase() or getWritableDatabase() on the SQLiteOpenHelper subclass and it will take care of creating a db, copying db contents from the specified file in the ‘assets’ folder, if the database does not exist.

In short, you can use the SQLiteOpenHelper subclass to access the db shipped in the assets folder just as you would use for a database that is initialized using SQL queries in the onCreate() method.

Shipping the app with a database file, in Android Studio 3.0

Shipping the app with a database file is a good idea for me. The advantage is that you don’t need to do a complex initialization, which sometimes costs lots of time, if your data set is huge.

Step 1: Prepare database file

Have your database file ready. It can be either a .db file or a .sqlite file. If you use a .sqlite file, all you need to do is to change file extension names. The steps are the same.

In this example, I prepared a file called testDB.db. It has one table and some sample data in it like this entrer la description de l'image ici

Step 2: Import the file into your project

Create the assets folder if you haven’t had one. Then copy and paste the database file into this folder

entrer la description de l'image ici

Step 3: Copy the file to the app’s data folder

You need to copy the database file to the app’s data folder in order to do further interaction with it. This is a one time action (initialization) to copy the database file. If you call this code multiple times, the database file in data folder will be overwritten by the one in assets folder. This overwrite process is useful when you want to update the database in future during the app update.

Note that during app update, this database file will not be changed in the app’s data folder. Only uninstall will delete it.

The database file needs to be copied to /databases folder. Open Device File Explorer. Enter data/data// location. This is the app’s default data folder mentioned above. And by default, the database file will be place in another folder called databases under this directory

entrer la description de l'image ici

Now, the copy file process is pretty much like the what Java is doing. Use the following code to do the copy paste. This is the initiation code. It can also be used to update(by overwriting) the database file in future.

 //get context by calling "this" in activity or getActivity() in fragment //call this if API level is lower than 17 Ssortingng appDataPath = "/data/data/" + context.getPackageName() + "/databases/" Ssortingng 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 } 

Then refresh the folder to verify the copy process

entrer la description de l'image ici

Step 4: Create database open helper

Create a subclass for SQLiteOpenHelper , with connect, close, path, etc. I named it 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 Ssortingng DB_NAME = "testDB.db"; public static final Ssortingng DB_SUB_PATH = "/databases/" + DB_NAME; private static Ssortingng 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{ Ssortingng 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) { } } 

Step 5: Create top level class to interact with the database

This will be the class that read & write your database file. Also there is a sample query to print out the value in the database.

 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{ Ssortingng query ="SELECT value FROM test1"; Cursor cursor = database.rawQuery(query, null); if (cursor.moveToFirst()){ do{ Ssortingng value = cursor.getSsortingng(0); Log.d("db", value); }while (cursor.moveToNext()); } cursor.close(); } catch (SQLException e) { //handle } } } 

Step 6: Test running

Test the code by running the following lines of codes.

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

Hit the run button and cheer!

entrer la description de l'image ici

In November 2017 Google released the Room Persistence Library

De la documentation:

The Room persistence library provides an abstraction layer over SQLite to allow fluent database access while harnessing the full power of SQLite.

The library helps you create a cache of your app’s data on a device that’s running your app. This cache, which serves as your app’s single source of truth, allows users to view a consistent copy of key information within your app, regardless of whether users have an internet connection.

The Room database has a callback when the database is first created or opened. You can use the create callback to populate your database.

 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() 

Code from this blog post .

From what I’ve seen you should be be shipping a database that already has the tables setup and data. However if you want (and depending on the type of application you have) you can allow “upgrade database option”. Then what you do is download the latest sqlite version, get the latest Insert/Create statements of a textfile hosted online, execute the statements and do a data transfer from the old db to the new one.

Finally I did it!! I have used this link help Using your own SQLite database in Android applications , but had to change it a little bit.

  1. If you have many packages you should put the master package name here:

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

  2. I changed the method which copies the database from local folder to emulator folder! It had some problem when that folder didn’t exist. So first of all, it should check the path and if it’s not there, it should create the folder.

  3. In the previous code, the copyDatabase method was never called when the database didn’t exist and the checkDataBase method caused exception. so I changed the code a little bit.

  4. If your database does not have a file extension, don’t use the file name with one.

it works nice for me , i hope it whould be usefull for u too

  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 Ssortingng DB_PATH = "data/data/com.example.sample/databases"; private static Ssortingng 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{ Ssortingng 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 Ssortingng 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. } 

Currently there is no way to precreate an SQLite database to ship with your apk. The best you can do is save the appropriate SQL as a resource and run them from your application. Yes, this leads to duplication of data (same information exists as a resrouce and as a database) but there is no other way right now. The only mitigating factor is the apk file is compressed. My experience is 908KB compresses to less than 268KB.

The thread below has the best discussion/solution I have found with good sample code.

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

I stored my CREATE statement as a ssortingng resource to be read with Context.getSsortingng() and ran it with SQLiteDatabse.execSQL().

I stored the data for my inserts in res/raw/inserts.sql (I created the sql file, 7000+ lines). Using the technique from the link above I entered a loop, read the file line by line and concactenated the data onto “INSERT INTO tbl VALUE ” and did another SQLiteDatabase.execSQL(). No sense in saving 7000 “INSERT INTO tbl VALUE “s when they can just be concactenated on.

It takes about twenty seconds on the emulator, I do not know how long this would take on a real phone, but it only happens once, when the user first starts the application.

Shipping the database inside the apk and then copying it to /data/data/... will double the size of the database (1 in apk, 1 in data/data/... ), and will increase the apk size (of course). So your database should not be too big.

Android already provides a version-aware approach of database management. This approach has been leveraged in the BARACUS framework for Android applications.

It enables you to manage the database along the entire version lifecycle of an app, beeing able to update the sqlite database from any prior version to the current one.

Also, it allows you to run hot-backups and hot-recovery of the SQLite.

I am not 100% sure, but a hot-recovery for a specific device may enable you to ship a prepared database in your app. But I am not sure about the database binary format which might be specific to certain devices, vendors or device generations.

Since the stuff is Apache License 2, feel free to reuse any part of the code, which can be found on github

EDIT :

If you only want to ship data, you might consider instantiating and persisting POJOs at the applications first start. BARACUS got a built-in support to this (Built-in key value store for configuration infos, eg “APP_FIRST_RUN” plus a after-context-bootstrap hook in order to run post-launch operations on the context). This enables you to have tight coupled data shipped with your app; in most cases this fitted to my use cases.

If the required data is not too large (limits I don´t know, would depend on a lot of things), you might also download the data (in XML, JSON, whatever) from a website/webapp. AFter receiving, execute the SQL statements using the received data creating your tables and inserting the data.

If your mobile app contains lots of data, it might be easier later on to update the data in the installed apps with more accurate data or changes.

I wrote a library to simplify this process.

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

It will create a dataBase from assets/databases/myDb.db file. In addition you will get all those functionality:

  • Load database from file
  • Synchronized access to the database
  • Using sqlite-android by requery, Android specific dissortingbution of the latest versions of SQLite.

Clone it from github .

I’m using ORMLite and below code worked for me

 public class DatabaseProvider extends OrmLiteSqliteOpenHelper { private static final Ssortingng 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 Ssortingng DatabasePath() { return "/data/data/" + ProvidedContext.getPackageName() + "/databases/"; } private void CopyDatabase() { try { CopyDatabaseInternal(); } catch (IOException e) { e.printStackTrace(); } } private File ExtractAssetsZip(Ssortingng zipFileName) { InputStream inputStream; ZipInputStream zipInputStream; File tempFolder; do { tempFolder = null; tempFolder = new File(ProvidedContext.getCacheDir() + "/extracted-" + System.currentTimeMillis() + "/"); } while (tempFolder.exists()); tempFolder.mkdirs(); try { Ssortingng 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"); Ssortingng 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); Ssortingng 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) { } } 

Please note, The code extracts database file from a zip file in assets

I modified the class and the answers to the question and wrote a class that allows updating the database via DB_VERSION.

 public class DatabaseHelper extends SQLiteOpenHelper { private static Ssortingng DB_NAME = "info.db"; private static Ssortingng 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; } } 

Using a class.

In the activity class, declare variables.

 private DatabaseHelper mDBHelper; private SQLiteDatabase mDb; 

In the onCreate method, write the following code.

 mDBHelper = new DatabaseHelper(this); try { mDBHelper.updateDataBase(); } catch (IOException mIOException) { throw new Error("UnableToUpdateDatabase"); } try { mDb = mDBHelper.getWritableDatabase(); } catch (SQLException mSQLException) { throw mSQLException; } 

If you add a database file to the folder res/raw then use the following modification of the class.

 public class DatabaseHelper extends SQLiteOpenHelper { private static Ssortingng DB_NAME = "info.db"; private static Ssortingng 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