如果您的应用程序需要数据库并且它带有内置数据,那么运送该应用程序的最佳方式是什么?我是不是该:
预先创建SQLite数据库并将其包含在.apk
?
在应用程序中包含SQL命令并让它创建数据库并在首次使用时插入数据?
我看到的缺点是:
可能的SQLite版本不匹配可能会导致问题,我目前不知道数据库应该去哪里以及如何访问它.
在设备上创建和填充数据库可能需要很长时间.
有什么建议?关于任何问题的文档的指针将不胜感激.
创建和更新数据库有两种选择.
One is to create a database externally, then place it in the assets folder of the project and then copy the entire database from there. This is much quicker if the database has a lot of tables and other components. Upgrades are triggered by changing the database version number in the res/values/strings.xml file. Upgrades would then be accomplished by creating a new database externally, replacing the old database in the assets folder with the new database, saving the old database in internal storage under another name, copying the new database from the assets folder into internal storage, transferring all of the data from the old database (that was renamed earlier) into the new database and finally deleting the old database. You can create a database originally by using the SQLite Manager FireFox plugin to execute your creation sql statements.
The other option is to create a database internally from a sql file. This is not as quick but the delay would probably be unnoticeable to the users if the database has only a few tables. Upgrades are triggered by changing the database version number in the res/values/strings.xml file. Upgrades would then be accomplished by processing an upgrade sql file. The data in the database will remain unchanged except when its container is removed, for example dropping a table.
The example below demonstrates how to use either method.
Here is a sample create_database.sql file. It is to be placed in the assets folder of the project for the internal method or copied into the "Execute SQL' of SQLite Manager to create the database for the external method. (NOTE: Notice the comment about the table required by 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";
Here is a sample update_database.sql file. It is to be placed in the assets folder of the project for the internal method or copied into the "Execute SQL' of SQLite Manager to create the database for the external method. (NOTE: Notice that all three types of SQL comments will be ignored by the sql parser that is included in this example.)
--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');
Here is an entry to add to the /res/values/strings.xml file for the database version number.
- 1
Here is an activity that accesses the database and then uses it. (Note: You might want to run the database code in a separate thread if it uses a lot of resources.)
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(); } } } }
Here is the database helper class where the database is created or updated if necessary. (NOTE: Android requires that you create a class that extends SQLiteOpenHelper in order to work with a Sqlite database.)
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. ** 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. */ }
Here's the FileHelper class that contains methods for byte stream copying files and parsing sql files.
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 * - 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 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 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(";"); } }
该SQLiteAssetHelper
库使这项任务非常简单.
它很容易添加为gradle依赖项(但是一个Jar也可用于Ant/Eclipse),并且可以在以下文档中找到它们的文档:https:
//github.com/jgilfelt/android-sqlite-asset-helper
注意:此项目不再按照Github链接上的说明进行维护.
如文档中所述:
将依赖项添加到模块的gradle构建文件中:
dependencies { compile 'com.readystatesoftware.sqliteasset:sqliteassethelper:+' }
将数据库复制到assets目录中的一个子目录中assets/databases
.例如:
assets/databases/my_database.db
(可选地,您可以使用zip文件压缩数据库,例如assets/databases/my_database.zip
.这不是必需的,因为APK已经整体压缩了.)
创建一个类,例如:
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
.
您希望随应用程序一起提供的数据库.它应包含一个1x1表android_metadata
,该表以一个属性命名,该属性除了应用程序独有的表之外还locale
具有该值en_US
.
SQLiteOpenHelper
:子类SQLiteOpenHelper
.
private
在SQLiteOpenHelper
子类中创建方法.此方法包含将数据库内容从"assets"文件夹中的数据库文件复制到在应用程序包上下文中创建的数据库的逻辑.
覆盖onCreate
,onUpgrade
和 onOpen
方法SQLiteOpenHelper
.
说够了.这是SQLiteOpenHelper
子类:
public class PlanDetailsSQLiteOpenHelper extends SQLiteOpenHelper { private static final String TAG = "SQLiteOpenHelper"; private final Context context; private static final int DATABASE_VERSION = 1; private static final String DATABASE_NAME = "my_custom_db"; private boolean createDb = false, upgradeDb = false; public PlanDetailsSQLiteOpenHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); this.context = context; } /** * Copy packaged database from assets folder to the database created in the * application package context. * * @param db * The target database in the application package context. */ private void copyDatabaseFromAssets(SQLiteDatabase db) { Log.i(TAG, "copyDatabase"); InputStream myInput = null; OutputStream myOutput = null; try { // Open db packaged as asset as the input stream myInput = context.getAssets().open("path/to/shipped/db/file"); // Open the db in the application package context: myOutput = new FileOutputStream(db.getPath()); // Transfer db file contents: byte[] buffer = new byte[1024]; int length; while ((length = myInput.read(buffer)) > 0) { myOutput.write(buffer, 0, length); } myOutput.flush(); // Set the version of the copied database to the current // version: SQLiteDatabase copiedDb = context.openOrCreateDatabase( DATABASE_NAME, 0, null); copiedDb.execSQL("PRAGMA user_version = " + DATABASE_VERSION); copiedDb.close(); } catch (IOException e) { e.printStackTrace(); throw new Error(TAG + " Error copying database"); } finally { // Close the streams try { if (myOutput != null) { myOutput.close(); } if (myInput != null) { myInput.close(); } } catch (IOException e) { e.printStackTrace(); throw new Error(TAG + " Error closing streams"); } } } @Override public void onCreate(SQLiteDatabase db) { Log.i(TAG, "onCreate db"); createDb = true; } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.i(TAG, "onUpgrade db"); upgradeDb = true; } @Override public void onOpen(SQLiteDatabase db) { Log.i(TAG, "onOpen db"); if (createDb) {// The db in the application package // context is being created. // So copy the contents from the db // file packaged in the assets // folder: createDb = false; copyDatabaseFromAssets(db); } if (upgradeDb) {// The db in the application package // context is being upgraded from a lower to a higher version. upgradeDb = false; // Your db upgrade logic here: } } }
最后,要获取数据库连接,只需调用getReadableDatabase()
或getWritableDatabase()
在SQLiteOpenHelper
子类上,它将负责创建数据库,如果数据库不存在,则从"assets"文件夹中的指定文件复制数据库内容.
简而言之,您可以使用SQLiteOpenHelper
子类访问assets文件夹中提供的数据库,就像在onCreate()
方法中使用SQL查询初始化的数据库一样.
使用数据库文件运送应用程序对我来说是一个好主意.优点是您不需要进行复杂的初始化,如果您的数据集很大,有时会花费大量时间.
第1步:准备数据库文件
准备好您的数据库文件.它可以是.db文件或.sqlite文件.如果使用.sqlite文件,则只需更改文件扩展名即可.步骤是一样的.
在这个例子中,我准备了一个名为testDB.db的文件.它有一个表和一些样本数据
第2步:将文件导入项目
如果您还没有,请创建资产文件夹.然后将数据库文件复制并粘贴到此文件夹中
第3步:将文件复制到应用程序的数据文件夹
您需要将数据库文件复制到应用程序的数据文件夹,以便与其进行进一步的交互.这是复制数据库文件的一次性操作(初始化).如果多次调用此代码,数据文件夹中的数据库文件将被assets文件夹中的数据库文件覆盖.当您希望将来在应用更新期间更新数据库时,此覆盖过程非常有用.
请注意,在应用更新期间,不会在应用的数据文件夹中更改此数据库文件.只有卸载才能将其删除.
需要将数据库文件复制到/databases
文件夹.打开Device File Explorer.输入data/data/
位置.这是上面提到的应用程序的默认数据文件夹.默认情况下,数据库文件将放在此目录下名为databases的另一个文件夹中
现在,复制文件进程与Java正在做的非常相似.使用以下代码执行复制粘贴.这是启动代码.它还可以用于将来更新(通过覆盖)数据库文件.
//get context by calling "this" in activity or getActivity() in fragment //call this if API level is lower than 17 String appDataPath = "/data/data/" + context.getPackageName() + "/databases/" String appDataPath = context.getApplicationInfo().dataDir; File dbFolder = new File(appDataPath + "/databases");//Make sure the /databases folder exists dbFolder.mkdir();//This can be called multiple times. File dbFilePath = new File(appDataPath + "/databases/testDB.db"); try { InputStream inputStream = context.getAssets().open("testDB.db"); OutputStream outputStream = new FileOutputStream(dbFilePath); byte[] buffer = new byte[1024]; int length; while ((length = inputStream.read(buffer))>0) { outputStream.write(buffer, 0, length); } outputStream.flush(); outputStream.close(); inputStream.close(); } catch (IOException e){ //handle }
然后刷新文件夹以验证复制过程
第4步:创建数据库打开助手
SQLiteOpenHelper
使用connect,close,path等创建一个子类.我命名了它DatabaseOpenHelper
import android.content.Context; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class DatabaseOpenHelper extends SQLiteOpenHelper { public static final String DB_NAME = "testDB.db"; public static final String DB_SUB_PATH = "/databases/" + DB_NAME; private static String APP_DATA_PATH = ""; private SQLiteDatabase dataBase; private final Context context; public DatabaseOpenHelper(Context context){ super(context, DB_NAME, null, 1); APP_DATA_PATH = context.getApplicationInfo().dataDir; this.context = context; } public boolean openDataBase() throws SQLException{ String mPath = APP_DATA_PATH + DB_SUB_PATH; //Note that this method assumes that the db file is already copied in place dataBase = SQLiteDatabase.openDatabase(mPath, null, SQLiteDatabase.OPEN_READWRITE); return dataBase != null; } @Override public synchronized void close(){ if(dataBase != null) {dataBase.close();} super.close(); } @Override public void onCreate(SQLiteDatabase db) { } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
第5步:创建顶级类以与数据库交互
这将是读写数据库文件的类.还有一个示例查询可以打印出数据库中的值.
import android.content.Context; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.util.Log; public class Database { private final Context context; private SQLiteDatabase database; private DatabaseOpenHelper dbHelper; public Database(Context context){ this.context = context; dbHelper = new DatabaseOpenHelper(context); } public Database open() throws SQLException { dbHelper.openDataBase(); dbHelper.close(); database = dbHelper.getReadableDatabase(); return this; } public void close() { dbHelper.close(); } public void test(){ try{ String query ="SELECT value FROM test1"; Cursor cursor = database.rawQuery(query, null); if (cursor.moveToFirst()){ do{ String value = cursor.getString(0); Log.d("db", value); }while (cursor.moveToNext()); } cursor.close(); } catch (SQLException e) { //handle } } }
第6步:测试运行
通过运行以下代码行来测试代码.
Database db = new Database(context); db.open(); db.test(); db.close();
点击运行按钮并加油!
2017年11月,Google发布了Room Persistence Library
从文档:
Room persistence库提供了一个基于SQLite的抽象层,允许流畅的数据库访问,同时利用SQLite的全部功能.
该库可帮助您在运行应用程序的设备上创建应用程序数据的缓存.此缓存作为应用程序的唯一事实来源,允许用户在应用程序中查看关键信息的一致副本,无论用户是否具有Internet连接.
首次创建或打开数据库时,Room数据库具有回调功能.您可以使用create callback来填充数据库.
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()
来自此博客文章的代码.
从我所见,你应该运送一个已经有表设置和数据的数据库.但是,如果您需要(并且根据您拥有的应用程序类型),您可以允许"升级数据库选项".然后你要做的是下载最新的sqlite版本,获取在线托管的文本文件的最新插入/创建语句,执行语句并从旧数据库到新数据库进行数据传输.
最后我做到了!! 我已经使用过这个链接帮助在Android应用程序中使用自己的SQLite数据库,但必须稍微更改一下.
如果您有许多包,则应将主包名称放在此处:
private static String DB_PATH = "data/data/masterPakageName/databases";
我改变了将数据库从本地文件夹复制到模拟器文件夹的方法!当该文件夹不存在时,它有一些问题.首先,它应该检查路径,如果不存在,它应该创建文件夹.
在前面的代码中,copyDatabase
当数据库不存在且checkDataBase
方法导致异常时,从不调用该方法.所以我稍微改了一下代码.
如果您的数据库没有文件扩展名,请不要使用文件名.
它对我很好,我希望它对你也有用
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. }