1004 Stimmen

Lieferung einer Anwendung mit einer Datenbank

Wenn für Ihre Anwendung eine Datenbank erforderlich ist und diese bereits über integrierte Daten verfügt, wie kann ich diese Anwendung am besten ausliefern? Sollte ich:

  1. Erstellen Sie die SQLite-Datenbank vor und fügen Sie sie in die Datei .apk ?

  2. Die SQL-Befehle in die Anwendung einbinden und dafür sorgen, dass die Datenbank erstellt und die Daten bei der ersten Verwendung eingefügt werden?

Die Nachteile, die ich sehe, sind:

  1. Mögliche SQLite-Versionsunterschiede könnten Probleme verursachen, und ich weiß derzeit nicht, wo die Datenbank gespeichert werden soll und wie man auf sie zugreift.

  2. Es kann sehr lange dauern, bis die Datenbank auf dem Gerät erstellt und aufgefüllt ist.

Irgendwelche Vorschläge? Für Hinweise auf die Dokumentation zu etwaigen Problemen wären wir Ihnen sehr dankbar.

6voto

masfenix Punkte 7196

Nach dem, was ich gesehen habe, sollten Sie eine Datenbank liefern, in der die Tabellen und Daten bereits eingerichtet sind. Wenn Sie jedoch möchten (und je nach Art der Anwendung, die Sie haben) können Sie "Upgrade-Datenbank-Option" zu ermöglichen. Dann laden Sie die neueste Sqlite-Version herunter, holen sich die neuesten Insert/Create-Anweisungen aus einer online gehosteten Textdatei, führen die Anweisungen aus und führen einen Datentransfer von der alten Datenbank zur neuen durch.

6voto

Will Punkte 18909

Derzeit gibt es keine Möglichkeit, eine SQLite-Datenbank zu erstellen, die mit Ihrer App ausgeliefert wird. Das Beste, was Sie tun können, ist, die entsprechende SQL als Ressource zu speichern und sie von Ihrer Anwendung aus auszuführen. Ja, dies führt zu einer Duplizierung von Daten (dieselben Informationen sind als Ressource und als Datenbank vorhanden), aber es gibt im Moment keine andere Möglichkeit. Der einzige mildernde Faktor ist, dass die apk-Datei komprimiert ist. Meine Erfahrung ist, dass 908KB auf weniger als 268KB komprimiert werden.

Der folgende Thread enthält die beste Diskussion/Lösung, die ich gefunden habe, mit gutem Beispielcode.

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

Ich habe meine CREATE-Anweisung als String-Ressource gespeichert, die mit Context.getString() gelesen werden kann, und sie mit SQLiteDatabse.execSQL() ausgeführt.

Ich habe die Daten für meine Einfügungen in res/raw/inserts.sql gespeichert (ich habe die sql-Datei erstellt, über 7000 Zeilen). Mit der Technik aus dem obigen Link bin ich in eine Schleife gegangen, habe die Datei Zeile für Zeile gelesen und die Daten mit "INSERT INTO tbl VALUE" konkaktiert und ein weiteres SQLiteDatabase.execSQL() ausgeführt. Es macht keinen Sinn, 7000 "INSERT INTO tbl VALUE "s zu speichern, wenn man sie einfach weiter konkaktieren kann.

Auf dem Emulator dauert es etwa zwanzig Sekunden, ich weiß nicht, wie lange das auf einem echten Telefon dauern würde, aber es passiert nur einmal, wenn der Benutzer die Anwendung zum ersten Mal startet.

5voto

afsane Punkte 1849

Endlich habe ich es geschafft!! Ich habe diesen Link benutzt Hilfe Verwenden Sie Ihre eigene SQLite-Datenbank in Android-Anwendungen aber ich musste es ein wenig ändern.

  1. Wenn Sie viele Pakete haben, sollten Sie hier den Namen des Hauptpakets angeben:

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

  2. Ich habe die Methode geändert, die die Datenbank vom lokalen Ordner in den Emulatorordner kopiert! Es gab ein Problem, wenn dieser Ordner nicht existierte. Zuerst sollte der Pfad überprüft werden und wenn er nicht vorhanden ist, sollte der Ordner erstellt werden.

  3. Im vorherigen Code wurde die copyDatabase Methode wurde nie aufgerufen, wenn die Datenbank nicht existierte und die checkDataBase Methode verursachte eine Ausnahme. Also habe ich den Code ein wenig geändert.

  4. Wenn Ihre Datenbank keine Dateierweiterung hat, verwenden Sie den Dateinamen nicht mit einer Erweiterung.

Es funktioniert gut für mich, ich hoffe, dass es auch für Sie nützlich sein wird.

    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.

}

5voto

Harrix Punkte 537

Ich habe die Klasse und die Antworten auf die Frage geändert und eine Klasse geschrieben, die die Aktualisierung der Datenbank über DB_VERSION ermöglicht.

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

Verwendung einer Klasse.

Deklarieren Sie in der Aktivitätsklasse Variablen.

private DatabaseHelper mDBHelper;
private SQLiteDatabase mDb;

Schreiben Sie in der onCreate-Methode den folgenden Code.

mDBHelper = new DatabaseHelper(this);

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

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

Wenn Sie eine Datenbankdatei in den Ordner res/raw hinzufügen, verwenden Sie die folgende Änderung der Klasse.

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

4voto

Hiep Punkte 2283

Versand der Datenbank innerhalb der apk und anschließendes Kopieren nach /data/data/... wird die Größe der Datenbank verdoppelt (1 in apk, 1 in data/data/... ) und wird die apk-Größe (natürlich) erhöhen. Ihre Datenbank sollte also nicht zu groß sein.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X