Veritabanıyla uygulama gönderme


959

Uygulamanız bir veritabanı gerektiriyorsa ve bu veriler yerleşik verilerle birlikte geliyorsa, bu uygulamayı göndermenin en iyi yolu nedir? Yapmalımıyım:

  1. SQLite veritabanını hazırlayın ve .apk?

  2. Uygulamaya SQL komutlarını ekleyin ve veritabanını oluşturup ilk kullanımda veri eklemesini sağlayın?

Gördüğüm sakıncalar:

  1. Olası SQLite sürümü uyuşmazlıkları sorunlara neden olabilir ve şu anda veritabanının nereye gitmesi gerektiğini ve ona nasıl erişileceğini bilmiyorum.

  2. Veritabanının cihazda oluşturulması ve doldurulması çok uzun sürebilir.

Herhangi bir öneri? Herhangi bir konuyla ilgili belgelere işaret etmek büyük beğeni toplayacaktır.



Yanıtlar:


199

Veri tabanı oluşturmak ve güncellemek için iki seçenek vardır.

Birincisi harici olarak bir veritabanı oluşturmak, daha sonra projenin varlıklar klasörüne yerleştirmek ve daha sonra tüm veritabanını oradan kopyalamaktır. Veritabanında çok sayıda tablo ve diğer bileşenler varsa bu çok daha hızlıdır. Yükseltmeler, res / değerleri / strings.xml dosyasındaki veritabanı sürüm numarası değiştirilerek tetiklenir. Yükseltmeler daha sonra harici olarak yeni bir veritabanı oluşturarak, varlıklar klasöründeki eski veritabanını yeni veritabanı ile değiştirerek, eski veritabanını başka bir adla dahili depolamaya kaydederek, yeni veritabanını varlıklar klasöründen dahili depolamaya kopyalayarak, (daha önce yeniden adlandırılmış olan) eski veritabanındaki verilerin yeni veritabanına aktarılması ve son olarak eski veritabanının silinmesi. Başlangıçta kullanarak bir veritabanı oluşturabilirsiniz.SQLite Manager FireFox eklentisi oluşturma sql deyimlerinizi yürütmek için.

Diğer seçenek, bir sql dosyasından dahili bir veritabanı oluşturmaktır. Bu kadar hızlı değil, ancak veritabanında sadece birkaç tablo varsa gecikme muhtemelen kullanıcılar tarafından fark edilmeyecektir. Yükseltmeler, res / değerleri / strings.xml dosyasındaki veritabanı sürüm numarası değiştirilerek tetiklenir. Yükseltmeler daha sonra yükseltme sql dosyası işlenerek gerçekleştirilebilir. Veritabanındaki veriler, kapsayıcısının kaldırılması, örneğin bir tablonun düşürülmesi durumu dışında değişmeden kalacaktır.

Aşağıdaki örnek her iki yöntemin nasıl kullanılacağını gösterir.

Örnek bir create_database.sql dosyası. Dahili yöntem için projenin varlıklar klasörüne yerleştirilecek veya harici yöntem için veritabanı oluşturmak üzere SQLite Manager'ın "SQL Yürütme" dosyasına kopyalanacaktır. (NOT: Android için gereken tablo hakkındaki yoruma dikkat edin.)

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

İşte örnek bir update_database.sql dosyası. Dahili yöntem için projenin varlıklar klasörüne yerleştirilecek veya harici yöntem için veritabanı oluşturmak üzere SQLite Manager'ın "SQL Yürüt "üne kopyalanacaktır. (NOT: Üç SQL yorumu türünün de yok sayılacağına dikkat edin bu örnekte bulunan sql ayrıştırıcısı tarafından.)

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

Veritabanı sürüm numarası için /res/values/strings.xml dosyasına eklenecek bir girdi.

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

İşte veritabanına erişen ve onu kullanan bir etkinlik. ( Not: Çok fazla kaynak kullanıyorsa veritabanı kodunu ayrı bir iş parçacığında çalıştırmak isteyebilirsiniz. )

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

    }
}

Gerekirse veritabanının oluşturulduğu veya güncellendiği veritabanı yardımcısı sınıfı. (NOT: Android, bir Sqlite veritabanıyla çalışmak için SQLiteOpenHelper'ı genişleten bir sınıf oluşturmanızı gerektirir.)

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

}

İşte byte stream kopyalama dosyaları ve sql dosyalarını ayrıştırma yöntemleri içeren FileHelper sınıfı.

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

}

i db yükseltmek için yukarıdaki kodu kullandım "upgrade_database.sql insert deyimi içerir. değerlerin bazıları tablo_a değerlerine ('ss', 'ddd', 'aaaa; aaa') eklemek gibi yarıiletken var; i bahsettiğim yukarıda eklemek değerlerin semicoln nedeniyle herhangi bir ides nasıl düzeltmek için esecute alma söz ettim.
Sam

5
Üçüncü bir seçenek var - db'yi web'den kopyalayın. Bunu yaptım ve 4 megdb için oldukça hızlı gidiyor. Ayrıca, ilk çözümün (kopya db) çalışmadığı 2.3 ile sorunu çözer.
Jack BeNimble

2
Danny And Austyn - Çözümünüz mükemmeldi. Ev yapımı çözümümde sorun yaşıyordum ve sizinkine rastladım. Gerçekten isabetli. Sağlamak için zaman ayırdığınız için teşekkür ederiz.
George Baker

4
Bu cevabı en çok oylanan ve kabul edilene karşı tercih ederim. Tek bir yerde tüm bilgilere sahiptir (bu bağlantı parçalarına bakın) ve hiçbir fikrim yoktu bazı Android özelliklerinden bahsetti (CREATE TABLE "android_metadata" gibi). Ayrıca örnekler bir artı olan ayrıntılı olarak yazılmıştır. Neredeyse her zaman iyi olmayan bir kopyala yapıştır çözümü ancak kod arasındaki açıklamalar harika.
Igor Čordaš

Aynı yöntemi kullanıyorum ama bir sorunla karşı karşıyayım.Ve eski verilerin tümünden yeni db dosyasına daha kolay bir şekilde kopyalayabiliriz.
Pankaj

130

SQLiteAssetHelperKütüphane bu görevi gerçekten basit hale getirir.

Bir dereceye bağımlılık olarak eklemek kolaydır (ancak Ant / Eclipse için bir Kavanoz da mevcuttur) ve belgelerle birlikte şu adreste bulunabilir:
https://github.com/jgilfelt/android-sqlite-asset-helper

Not: Bu proje artık yukarıdaki Github bağlantısında belirtildiği gibi korunmamaktadır.

Belgelerde açıklandığı gibi:

  1. Bağımlılığı modülünüzün sınıf oluşturma dosyasına ekleyin:

    dependencies {
        compile 'com.readystatesoftware.sqliteasset:sqliteassethelper:+'
    }
  2. Veritabanını, adlandırılan bir alt dizinde varlıklar dizinine kopyalayın assets/databases. Örneğin:
    assets/databases/my_database.db

    (İsteğe bağlı olarak, veritabanını gibi bir zip dosyasında assets/databases/my_database.zipsıkıştırabilirsiniz. APK zaten bir bütün olarak sıkıştırıldığı için buna gerek yoktur.)

  3. Bir sınıf oluşturun, örneğin:

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

android-sqlite-asset-helper.jar indirme hangi kimlik bilgilerini gerektirir?
Pr38y

1
Gradle kullanıyorsanız, bağımlılığı ekleyin.
Suragch

Veritabanından nasıl veri alırsınız?
Machado

Android Studio ve gradle ile daha da kolay. Bağlantıyı kontrol edin!
bendaf

5
Bu kitaplığın son güncelleme ile 4 yıl önce terk edildiğini unutmayın.
etkinliği 17:

13

Çözümüm, herhangi bir üçüncü taraf kitaplığı kullanmaz veya SQLiteOpenHelperveritabanını oluşturma sırasında başlatmak için alt sınıfta özel yöntemleri çağırmaya zorlamaz. Ayrıca veritabanı yükseltmeleriyle de ilgilenir. Yapılması gereken tek şey alt sınıftır SQLiteOpenHelper.

Önkoşul:

  1. Uygulaması ile gemi istediğiniz veritabanı. Uygulamanıza özgü tablolara ek olarak, değere sahip bir özniteliğe sahip 1x1 tablo içermelidir .android_metadatalocaleen_US

Alt sınıflandırma SQLiteOpenHelper:

  1. Alt sınıf SQLiteOpenHelper.
  2. Alt sınıf privateiçinde bir yöntem oluşturun SQLiteOpenHelper. Bu yöntem, 'içerikler' klasöründeki veritabanı dosyasından veritabanı içeriğini uygulama paketi bağlamında oluşturulan veritabanına kopyalamak için mantık içerir.
  3. Geçersiz kılma onCreate, onUpgrade ve onOpen yöntemleri SQLiteOpenHelper.

Yeterince söylendi. İşte SQLiteOpenHelperalt sınıf:

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

Son olarak, bir veritabanı bağlantısı elde etmek için, sadece getReadableDatabase()veya alt sınıfta arayın ve veritabanı yoksa getWritableDatabase(), SQLiteOpenHelperdb içeriğini 'varlıklar' klasöründeki belirtilen dosyadan kopyalayarak db oluşturmaya özen gösterir.

Kısacası, SQLiteOpenHelpervarlıklar klasöründe gönderilen db'ye, tıpkı onCreate()yöntemdeki SQL sorguları kullanılarak başlatılan bir veritabanı için kullandığınız gibi erişmek için alt sınıfı kullanabilirsiniz .


2
Bu, harici kütüphanelere ihtiyaç duymadan standart Android API'larını kullanan en şık çözümdür. Not olarak, android_metadata tablosunu dahil etmedim ve işe yarıyor, yeni Android sürümleri otomatik olarak ekleyebilir.
goetzc

12

Uygulamayı Android Studio 3.0'da bir veritabanı dosyasıyla gönderme

Uygulamayı bir veritabanı dosyasıyla göndermek benim için iyi bir fikir. Avantajı, veri kümeniz büyükse, bazen çok zaman alan karmaşık bir başlatma yapmanız gerekmemesidir.

Adım 1: Veritabanı dosyasını hazırlayın

Veritabanı dosyanızı hazırlayın. Bir .db dosyası veya .sqlite dosyası olabilir. Bir .sqlite dosyası kullanırsanız, tek yapmanız gereken dosya uzantısı adlarını değiştirmektir. Adımlar aynı.

Bu örnekte testDB.db adlı bir dosya hazırladım. Bir tablo ve bunun gibi bazı örnek veriler var resim açıklamasını buraya girin

Adım 2: Dosyayı projenize aktarın

Eğer yoksa, varlıklar klasörünü oluşturun. Sonra veritabanı dosyasını kopyalayıp bu klasöre yapıştırın

resim açıklamasını buraya girin

3. Adım: Dosyayı uygulamanın veri klasörüne kopyalayın

Daha fazla etkileşim için veritabanı dosyasını uygulamanın veri klasörüne kopyalamanız gerekir. Bu, veritabanı dosyasını kopyalamak için tek seferlik bir eylemdir (başlatma). Bu kodu birden çok kez çağırırsanız, veri klasöründeki veritabanı dosyasının varlıklar klasöründeki veri dosyası üzerine yazılır. Bu üzerine yazma işlemi, uygulama güncellemesi sırasında ileride veritabanını güncellemek istediğinizde yararlıdır.

Uygulama güncellemesi sırasında, bu veritabanı dosyasının uygulamanın veri klasöründe değiştirilmeyeceğini unutmayın. Yalnızca kaldırma işlemi siler.

Veritabanı dosyasının /databasesklasöre kopyalanması gerekir . Aygıt Dosya Gezgini'ni açın. data/data/<YourAppName>/Konumu girin . Bu, uygulamanın yukarıda belirtilen varsayılan veri klasörüdür. Ve varsayılan olarak, veritabanı dosyası bu dizinin altındaki veritabanları adı verilen başka bir klasöre yerleştirilir

resim açıklamasını buraya girin

Şimdi, kopyalama dosyası işlemi hemen hemen Java'nın yaptığı gibi. Kopyalama yapıştırmasını yapmak için aşağıdaki kodu kullanın. Bu başlatma kodudur. Gelecekte veritabanı dosyasını güncellemek (üzerine yazarak) için de kullanılabilir.

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

Ardından kopyalama işlemini doğrulamak için klasörü yenileyin

resim açıklamasını buraya girin

Adım 4: Veritabanı açık yardımcısı oluşturma

SQLiteOpenHelperBağlan, kapat, yol vb. İle bir alt sınıf oluştur .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. Adım: Veritabanıyla etkileşim kurmak için üst düzey sınıf oluşturun

Bu, veritabanı dosyanızı okuyan ve yazacak olan sınıf olacaktır. Ayrıca, veritabanındaki değeri yazdırmak için örnek bir sorgu vardır.

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. Adım: Test çalıştırması

Aşağıdaki kod satırlarını çalıştırarak kodu test edin.

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

Çalıştır düğmesine basın ve tezahürat yapın!

resim açıklamasını buraya girin


1
başlatma ne zaman yapılmalıdır? Önerdiğiniz strateji nedir?
Daniele B

8

Kasım 2017'de Google, Oda Kalıcılığı Kütüphanesini yayınladı .

Belgelerden:

Oda kalıcılık kütüphanesi SQ üzerinde bir soyutlama katmanı sağlar güçlü metin tam gücünü ise akıcı veritabanı erişimine izin vermek için Lite SQLite'ta .

Kütüphane, uygulamanızı çalıştıran bir cihazda uygulamanızın verilerinin önbelleğini oluşturmanıza yardımcı olur. Uygulamanızın tek gerçek kaynağı olarak hizmet veren bu önbellek, kullanıcıların internet bağlantısına sahip olup olmadıklarına bakılmaksızın kullanıcıların uygulamanızdaki önemli bilgilerin tutarlı bir kopyasını görüntülemelerini sağlar.

Room veritabanı ilk oluşturulduğunda veya açıldığında bir geri çağrı vardır. Veritabanınızı doldurmak için geri arama oluşturma özelliğini kullanabilirsiniz.

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

Bu blog gönderisinden kod .


Teşekkürler, Bu benim için çalıştı. Java örneği burada
Jerry Sha

1
Zaten var olan bir SQLite ile bir APK göndermek istiyorsanız, varlıklar klasörüne ekleyebilir ve SQLite dosya verilerini yenisine yükleyecek bir taşıma gerçekleştirmek için github.com/humazed/RoomAsset paketini kullanabilirsiniz . Bu şekilde, mevcut bir DB ile verilerin doldurulmasını kaydedebilirsiniz.
xarlymg89

6

Gördüğüm kadarıyla zaten tablolar kurulum ve veri olan bir veritabanı nakliye olmalıdır. Ancak isterseniz (ve sahip olduğunuz uygulamanın türüne bağlı olarak) "veritabanı yükseltme seçeneğine" izin verebilirsiniz. Sonra yaptığınız en son sqlite sürümünü indirmek, çevrimiçi barındırılan bir textfile en son Ekle / Oluştur ifadeleri almak, ifadeleri yürütmek ve eski db yenisine veri aktarımı yapmak.


6
> Gördüğüm kadarıyla zaten tablo kurulumu ve verileri olan bir veritabanı gönderiyor olmalısınız. Evet ama bunu nasıl yapıyorsun?
Rory

5

Sonunda yaptım!! Bu bağlantı yardımını kullandım Android uygulamalarında kendi SQLite veritabanınızı kullanma , ancak biraz değiştirmek zorunda kaldım.

  1. Çok sayıda paketiniz varsa, ana paket adını buraya koymalısınız:

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

  2. Veritabanını yerel klasörden emülatör klasörüne kopyalayan yöntemi değiştirdim! Bu klasör mevcut olmadığında bir sorun vardı. Her şeyden önce, yolu kontrol etmeli ve orada değilse, klasörü oluşturmalıdır.

  3. Önceki kodda, copyDatabaseveritabanı bulunmadığında ve checkDataBaseyöntem kural dışı duruma neden olduğunda yöntem hiçbir zaman çağrılmadı . bu yüzden kodu biraz değiştirdim.

  4. Veritabanınızın dosya uzantısı yoksa, dosya adını biriyle kullanmayın.

benim için iyi çalışıyor, umarım senin için de yararlı olur

    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.

}

u eski veritabanını yenisiyle değiştirmek isterseniz bana db'yi nasıl yükseltebileceğimi lütfen bana bildirebilir miyim
db'yi

Şimdiye kadar bunu yapmam gerekmiyor, ancak yeni uygulama yüklendiyse, yeni db de değiştirilir
afsane

ben varlıklar klasöründe yeni db ekliyorum çünkü eski veritabanı silmek için nasıl belirtilen klasörden eski db silerim aksi takdirde eski db içeriğini getirecektir
Erum


Mükemmel, teşekkürler! Sadece bir yorum, veritabanını kontrol etmek için istisnayı atmak uygulamanın kapanmasına neden olur, çünkü DB başlangıçta orada olmaz ve istisna atıldıktan sonra yöntem devam etmez. Ben sadece yeni hata atmak yorumladı ("veritabanı dozu mevcut değil"); ve şimdi her şey mükemmel çalışıyor.
Grinner

4

Şu anda apk ile birlikte bir SQLite veritabanı oluşturmanın bir yolu yok. Yapabileceğiniz en iyi şey uygun SQL'i kaynak olarak kaydetmek ve uygulamanızdan çalıştırmaktır. Evet, bu verilerin çoğaltılmasına yol açar (aynı bilgiler yeniden oluşturma ve veritabanı olarak bulunur) ancak şu anda başka bir yol yoktur. Azaltıcı tek faktör apk dosyasının sıkıştırılmış olmasıdır. Benim tecrübelerim 908KB 268KB daha az sıkıştırır.

Aşağıdaki iş parçacığı iyi örnek kodu ile bulduğum en iyi tartışma / çözüm var.

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

CREATE deyimimi Context.getString () ile okunacak bir dize kaynağı olarak sakladım ve SQLiteDatabse.execSQL () ile çalıştırdım.

Eklerim için verileri res / raw / inserts.sql'de sakladım (sql dosyasını 7000+ satır oluşturdum). Yukarıdaki bağlantıdan tekniği kullanarak bir döngü girdim, dosyayı satır satır okuyun ve verileri "INTO tbl VALUE" üzerine ekledim ve başka bir SQLiteDatabase.execSQL () yaptım. Sadece kapatılabilecekleri zaman 7000 "Tbl VALUE'U EKLE" yi kaydetmenin anlamı yok.

Emülatörde yaklaşık yirmi saniye sürer, bunun gerçek bir telefonda ne kadar süreceğini bilmiyorum, ancak kullanıcı uygulamayı ilk başlattığında sadece bir kez olur.


3
SQL komut dosyasını ilk çalıştırmada web'den çekmeye ne dersiniz? Bu şekilde verilerin kopyalanmasına gerek kalmaz.
Tamas Czinege

1
Evet, ancak cihazın internete bağlı olması gerekir. Bu, bazı uygulamalarda ciddi bir dezavantaj.
Dzhuneyt

7000+ INSERT INTO table VALUES(...) VALUES(...) VALUES(...) ...kesici uç yapmayın, 100 veya benzeri toplu kesici uçlar yapmayın - (1 kesici uç çizgisinde 100 DEĞER olmalıdır). Çok daha verimli olacak ve başlangıç ​​zamanınızı 20 saniyeden 2 veya 3 saniyeye düşürecektir.
Mohit Atray

4

Veritabanının apk içinde gönderilmesi ve daha sonra kopyalanması /data/data/..., veritabanının boyutunu iki katına çıkarır (apk 1, 1 in data/data/...) ve apk boyutunu artıracaktır (elbette). Yani veritabanınız çok büyük olmamalıdır.


2
APK boyutunu biraz arttırır, ancak iki katına çıkarmaz. Varlıklardayken sıkıştırılır ve bu yüzden çok daha küçüktür. Veritabanı klasörüne kopyaladıktan sonra sıkıştırılmamış hale gelir.
Suragch

3

Android zaten veritabanı yönetimine yönelik sürüm duyarlı bir yaklaşım sunuyor. Bu yaklaşım, Android uygulamaları için BARACUS çerçevesinde kullanılmıştır.

Bir uygulamanın tüm sürüm yaşam döngüsü boyunca veritabanını yönetmenizi sağlar, sqlite veritabanını önceki herhangi bir sürümden geçerli olana güncelleyebilir.

Ayrıca, SQLite'nin sıcak yedeklemelerini ve sıcak kurtarma işlemlerini çalıştırmanıza izin verir.

% 100 emin değilim, ancak belirli bir cihaz için bir sıcak kurtarma , uygulamanızda hazırlanmış bir veritabanını göndermenizi sağlayabilir. Ancak, belirli aygıtlara, satıcılara veya aygıt nesillerine özgü olabilecek veritabanı ikili biçiminden emin değilim.

Malzeme Apache Lisansı 2 olduğundan, kodun github'da bulunan herhangi bir bölümünü tekrar kullanmaktan çekinmeyin

DÜZENLE :

Yalnızca veri göndermek istiyorsanız, uygulamaların başlangıcında POJO'ları başlatmayı ve sürdürmeyi düşünebilirsiniz. BARACUS bu konuda yerleşik bir destek aldı (Konfigürasyon bilgileri için yerleşik anahtar değeri deposu, örneğin "APP_FIRST_RUN" artı bağlam sonrası başlatma işlemlerini çalıştırmak için bağlam sonrası bir bootstrap kancası). Bu, uygulamanızla birlikte sıkı veri gönderilmesini sağlar; çoğu durumda bu benim kullanım durumlarıma uyuyordu.


3

Gerekli veriler çok büyük değilse (bilmediğim sınırlar, birçok şeye bağlı olacaktır), verileri bir web sitesinden / web uygulamasından da indirebilirsiniz (XML, JSON, her neyse). AAldıktan sonra, tablolarınızı oluşturan ve verileri ekleyerek alınan verileri kullanarak SQL ifadelerini yürütün.

Mobil uygulamanız çok fazla veri içeriyorsa, yüklü uygulamalardaki verileri daha doğru veriler veya değişikliklerle güncellemek daha sonra daha kolay olabilir.


3

Sınıf ve sorunun yanıtlarını değiştirdim ve veritabanını DB_VERSION üzerinden güncellemeye izin veren bir sınıf yazdım.

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

Sınıf kullanma.

Activity sınıfında değişkenleri bildiriniz.

private DatabaseHelper mDBHelper;
private SQLiteDatabase mDb;

OnCreate yönteminde aşağıdaki kodu yazın.

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 klasörüne bir veritabanı dosyası eklerseniz, sınıfın aşağıdaki değişikliğini kullanın.

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

Bu işlemi basitleştirmek için bir kütüphane yazdım .

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

Dosyadan bir dataBase oluşturur assets/databases/myDb.db. Buna ek olarak, tüm bu işlevleri alacaksınız:

  • Veritabanından dosya yükle
  • Veritabanına senkronize erişim
  • Sqlite-android kullanarak sorgulama, SQLite en son sürümlerinin Android özel dağıtım.

Github'dan klonlayın .


2

ORMLite kullanıyorum ve aşağıdaki kod benim için çalıştı

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

    }
}

Lütfen kodun varlıklardaki bir zip dosyasından veritabanı dosyasını ayıklar

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.