如果您的应用程序需要一个数据库,并且它带有内置数据,那么交付该应用程序的最佳方式是什么?我应该:

预创建SQLite数据库,并将其包含在。apk? 在应用程序中包含SQL命令,并让它在第一次使用时创建数据库并插入数据?

我所看到的缺点是:

可能的SQLite版本不匹配可能会导致问题,我目前不知道数据库应该去哪里以及如何访问它。 在设备上创建和填充数据库可能需要很长时间。

有什么建议吗?关于任何问题的文档指针将非常感激。


当前回答

我写了一个库来简化这个过程。

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

它将从assets/databases/myDb.db文件创建一个dataBase。 此外,你会得到所有这些功能:

从文件加载数据库 同步访问数据库 使用SQLite - Android通过requery, Android特定分发最新版本的SQLite。

从github克隆。

其他回答

如果所需的数据不是很大(限制我不知道,将取决于很多东西),你也可以从网站/网络应用下载数据(XML, JSON,无论什么)。接收到数据后,使用接收到的数据执行SQL语句,创建表并插入数据。

如果你的移动应用程序包含大量数据,稍后用更准确的数据或更改更新已安装的应用程序中的数据可能会更容易。

从我所看到的,你应该是一个已经有表设置和数据的数据库。然而,如果你愿意(取决于你拥有的应用程序类型),你可以允许“升级数据库选项”。然后你要做的就是下载最新的sqlite版本,获得在线托管的文本文件的最新Insert/Create语句,执行这些语句,并从旧的db进行数据传输到新的db。

SQLiteAssetHelper库使得这个任务非常简单。

作为gradle依赖项添加它很容易(但Jar也可用于Ant/Eclipse),它的文档可以在以下地址找到: https://github.com/jgilfelt/android-sqlite-asset-helper

注意:这个项目不再维护如上所述的Github链接。

如文档中所述:

Add the dependency to your module's gradle build file: dependencies { compile 'com.readystatesoftware.sqliteasset:sqliteassethelper:+' } Copy the database into the assets directory, in a subdirectory called assets/databases. For instance: assets/databases/my_database.db (Optionally, you may compress the database in a zip file such as assets/databases/my_database.zip. This isn't needed, since the APK is compressed as a whole already.) Create a class, for example: 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); } }

我的解决方案既不使用任何第三方库,也不强迫您在SQLiteOpenHelper子类上调用自定义方法来在创建时初始化数据库。它还负责数据库升级。所有需要做的就是子类化SQLiteOpenHelper。

先决条件:

你希望与应用一起发布的数据库。它应该包含一个名为android_metadata的1x1表,其属性locale值为en_US,此外还有应用特有的表。

子类化SQLiteOpenHelper:

子类SQLiteOpenHelper。 在SQLiteOpenHelper子类中创建一个私有方法。此方法包含将数据库内容从“assets”文件夹中的数据库文件复制到在应用程序包上下文中创建的数据库的逻辑。 重写SQLiteOpenHelper的onCreate, onUpgrade和onOpen方法。

足够的说。下面是SQLiteOpenHelper子类:

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

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

    private boolean createDb = false, upgradeDb = false;

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

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

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

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

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

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

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

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

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

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

最后,要获得一个数据库连接,只需在SQLiteOpenHelper子类上调用getReadableDatabase()或getWritableDatabase(),它将负责创建一个db,如果数据库不存在,则从'assets'文件夹中的指定文件复制db内容。

简而言之,您可以使用SQLiteOpenHelper子类来访问资产文件夹中附带的db,就像您在onCreate()方法中使用SQL查询初始化数据库一样。

我终于做到了!!我已经使用这个链接帮助在Android应用程序中使用自己的SQLite数据库,但必须稍微改变一下。

If you have many packages you should put the master package name here: private static String DB_PATH = "data/data/masterPakageName/databases"; 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. 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. If your database does not have a file extension, don't use the file name with one.

它对我很有用,我希望它对你也有用

    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.

}