This question already has answers here:
Simple export and import of a SQLite database on Android
(5 answers)
Closed 9 years ago.
It is possible to use an already created database sqlite in android? I already created database in sqlite in mozilla ad-ons. How should I use it in my android application? Anyone can help me??
First, to use a database, in general, in android, you should extend the SQLiteOpenHelper class. This class is the one responsible for creating your database (and upgrading) when needed from a sql script you provide in your implementation.
So the trick is, you need to override the behavior of the SQLiteOpenHelper to copy your database file from the assets folder instead of create your database.
in this blog post, i explain in details the process of overriding this behavior. but here is the final code.
use the Repository class as you would use SQLiteOpenHelper normally.
public class Repository extends SQLiteOpenHelper {
private static final int VERSION = 1;
private static final String DATABASE_NAME = "data.sqlite";
private static File DATABASE_FILE;
// This is an indicator if we need to copy the
// database file.
private boolean mInvalidDatabaseFile = false;
private boolean mIsUpgraded = false;
private Context mContext;
/**
* number of users of the database connection.
* */
private int mOpenConnections = 0;
private static Repository mInstance;
synchronized static public Repository getInstance(Context context) {
if (mInstance == null) {
mInstance = new Repository(context.getApplicationContext());
}
return mInstance;
}
private Repository(Context context) {
super(context, DATABASE_NAME, null, VERSION);
this.mContext = context;
SQLiteDatabase db = null;
try {
db = getReadableDatabase();
if (db != null) {
db.close();
}
DATABASE_FILE = context.getDatabasePath(DATABASE_NAME);
if (mInvalidDatabaseFile) {
copyDatabase();
}
if (mIsUpgraded) {
doUpgrade();
}
} catch (SQLiteException e) {
} finally {
if (db != null && db.isOpen()) {
db.close();
}
}
}
#Override
public void onCreate(SQLiteDatabase db) {
mInvalidDatabaseFile = true;
}
#Override
public void onUpgrade(SQLiteDatabase database,
int old_version, int new_version) {
mInvalidDatabaseFile = true;
mIsUpgraded = true;
}
/**
* called if a database upgrade is needed
*/
private void doUpgrade() {
// implement the database upgrade here.
}
#Override
public synchronized void onOpen(SQLiteDatabase db) {
super.onOpen(db);
// increment the number of users of the database connection.
mOpenConnections++;
if (!db.isReadOnly()) {
// Enable foreign key constraints
db.execSQL("PRAGMA foreign_keys=ON;");
}
}
/**
* implementation to avoid closing the database connection while it is in
* use by others.
*/
#Override
public synchronized void close() {
mOpenConnections--;
if (mOpenConnections == 0) {
super.close();
}
}
private void copyDatabase() {
AssetManager assetManager = mContext.getResources().getAssets();
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(DATABASE_NAME);
out = new FileOutputStream(DATABASE_FILE);
byte[] buffer = new byte[1024];
int read = 0;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
} catch (IOException e) {
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {}
}
}
setDatabaseVersion();
mInvalidDatabaseFile = false;
}
private void setDatabaseVersion() {
SQLiteDatabase db = null;
try {
db = SQLiteDatabase.openDatabase(DATABASE_FILE.getAbsolutePath(), null,
SQLiteDatabase.OPEN_READWRITE);
db.execSQL("PRAGMA user_version = " + VERSION);
} catch (SQLiteException e ) {
} finally {
if (db != null && db.isOpen()) {
db.close();
}
}
}
}
All you need to do is put the sqlite database in your assets folder, then when your app starts the first time, copy the database over to the SDCard.
Here is a great description of how to do this.
Android uses internal databases for SQLite. If you want to use an external SQLite database (or any other external database) you're going to need to use something like an HHTP proxy. Here's a link that provides more info: https://stackoverflow.com/a/4124829/1852466
Related
How is it that some dictionaries such as merriam dictionary (Offline dictionary) when the application was installed , the words are there instantly, and time is not required to insert a list of words and definition into the database? I am a beginner and is currently developing an android application that consist of about 30K words and it will take around 15+ minutes for it to insert all the data into the database before the user can search for that particular data. And I am looking for a method that can fix this. Could someone please tell me a way to do it ?
Thank you
My guess is that these apps are using an already SQLite database with all the data they need already populated.
You can import populated databases to your app with something like this :
public class DataBaseAdapter {
String DB_NAME = "DBNAME.db";
String DIR = "/data/data/packageName/databases/";
String DB_PATH = DIR + DB_NAME;
private DataBaseHelper mDbHelper;
private SQLiteDatabase db;
private Context context;
public DataBaseAdapter(Context context) {
this.context = context;
mDbHelper = new DataBaseHelper(this.context);
}
class DataBaseHelper extends SQLiteOpenHelper {
private boolean createDatabase = false;
#SuppressWarnings("unused")
private boolean upgradeDatabase = false;
Context context;
public DataBaseHelper(Context context) {
super(context, DB_NAME, null, 1);
this.context = context;
}
public void initializeDataBase() {
getWritableDatabase();
if (createDatabase) {
try {
copyDataBase();
} catch (IOException e) {
throw new Error("Error copying database");
}
}
}
private void copyDataBase() throws IOException {
InputStream input = context.getAssets().open(DB_NAME);
OutputStream output = new FileOutputStream(DB_PATH);
byte[] buffer = new byte[1024];
int length;
try {
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
}
finally {
try {
if (output != null) {
try {
output.flush();
} finally {
output.close();
}
}
} finally {
if (input != null) {
input.close();
}
}
}
getWritableDatabase().close();
}
public void onCreate(SQLiteDatabase db) {
createDatabase = true;
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
upgradeDatabase = true;
}
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
}
}
public DataBaseAdapter open() {
mDbHelper.initializeDataBase();
if (db == null)
db = mDbHelper.getWritableDatabase();
return this;
}
public void close() {
db.close();
}
}
you can then add methods to get data from database and this class can be used in your activity by calling open then the method to get data then close.
Your application should include a pre-populated database for offline access with it's install. That will avoid each user having to run the INSERT step on their device.
Is there a particular reason you need to run the INSERTS post-install?
I have problem which many have and I think, that I tried all solutions, but I have not found the right solution yet.
My existing database "base.sqlite3" is in "assets" folder, contains three tables.
When I want to do query, appears error, that table is not there.
(In code are possible syntax errors, cause I translated code)
public class Sqlite extends SQLiteOpenHelper {
private final Context myContext;
public SQLiteDatabase base;
private static String path ="/data/data/" + "com.example.myexample" + "/databases/";
private static String name = "base.sqlite3";
private static String p = path + name;
public Sqlite(Context context){
super(context, ime, null, 1);
this.myContext = context;
createDatabase();
}
#Override
public void onCreate(SQLiteDatabase base) {}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
#Override
public synchronized void close()
{
if(base != null)
base.close();
super.close();
}
public void createDatabase()
{
boolean exist1 = checkDatabase();
if(exist1){}
else
{
base = this.getReadableDatabase();
base.close();
copyDatabase();
}
}
private boolean checkDatabase()
{
SQLiteDatabase check = null;
try
{
check = SQLiteDatabase.openDatabase(p, null, SQLiteDatabase.OPEN_READONLY);
}
catch(SQLiteException e)
{ }
if(check != null)
{
check.close();
}
return check != null ? true : false;
}
private void copyDatabase()
{
InputStream dat = null;
try {
dat = myContext.getAssets().open(name);
} catch (IOException e) {
e.printStackTrace();
}
OutputStream dat2 = null;
try {
dat2 = new FileOutputStream(p);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
byte[] buffer = new byte[1024];
int length;
try {
while ((length = dat.read(buffer))>0)
{
dat2.write(buffer, 0, length);
}
} catch (IOException e) {
e.printStackTrace();
}
try {
dat2.flush();
dat2.close();
dat.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void openDatabase()
{
base = SQLiteDatabase.openDatabase(p, null, SQLiteDatabase.OPEN_READONLY);
}
public Cursor SelectSomething(String sql)
{
base = SQLiteDatabase.openDatabase(p, null, SQLiteDatabase.OPEN_READONLY);
Cursor cursor = base.rawQuery(sql,null);
return cursor;
}
}
Thank you so much for all help!
As already was stated in the comment to this answer, the code from
this article is
" old, outdated, dreadful (concatenation to create file paths?), and problematic",
and it appears you are not the first to encounter problems with it.
Also, in the same comment to the same answer, it is proposed to use SQLiteAssetHelper. Consider trying it.
This is my file dataSqliteHelper and when I run the first time, the data file is created but I don't know where is it to get it and open it with a tool and view the file.
public class DataSQLiteHelper extends OrmLiteSqliteOpenHelper {
public static final String DATABASE_NAME = "ventasdb.db";
private static final int DATABASE_VERSION = 1;
private Context mContext;
private Dao<Customer, Integer> customerDao;
public DataSQLiteHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db, ConnectionSource conections) {
try {
TableUtils.createTable(connectionSource, Customer.class);
} catch (Exception e) {
Log.e(DataSQLiteHelper.class.getName(), "Can't create database", e);
throw new RuntimeException(e);
}
}
#Override
public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource,
int oldVersion, int newVersion) {
try {
TableUtils.dropTable(connectionSource, Customer.class, true);
} catch (SQLException e) {
throw new RuntimeException(e);
} catch (java.sql.SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Returns the Database Access Object (DAO) for our UserData class. It will
* create it or just give the cached value.
*/
public Dao<Customer, Integer> getCustomerDao() {
if (customerDao == null) {
try {
customerDao = getDao(Customer.class);
} catch (java.sql.SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return customerDao;
}
public boolean updateCustomer(Customer p) {
boolean ret = false;
if (customerDao != null) {
try {
customerDao = getDao(Customer.class);
UpdateBuilder<Customer, Integer> updateBuilder = customerDao
.updateBuilder();
updateBuilder.updateColumnValue("name", "PIRIPIPI"); // p.getName());
updateBuilder.updateColumnValue("cel", p.getCel());
updateBuilder.updateColumnValue("email", p.getEmail());
updateBuilder.updateColumnValue("address", p.getAddress());
updateBuilder.updateColumnValue("City", p.getCity());
// but only update the rows where the description is some value
updateBuilder.where().eq("customerID", 0);
// actually perform the update
customerDao.update(p);
customerDao.refresh(p);
} catch (Exception e) {
ret = false;
e.printStackTrace();
}
}
return ret;
}
/**
* Close the database connections and clear any cached DAOs.
*/
#Override
public void close() {
super.close();
}
}
with this line I know that I give the file name
super(context, DATABASE_NAME, null, DATABASE_VERSION);
but where is it in the storage of the device?
By the way , can I change the path to store the file in the sd card ?
it will be stored at
/data/data/[package name]/databases
But unless your phone is rooted you cannot browse to it using file explorer or adb shell
It is saved here (as nandeesh says)
/data/data/[package name]/databases
You can only access it on a phone if it is rooted. Or you can install the app on an emulator, start up the DDMS tool and view the database file there.
I'm developing an android 3.1 application.
This question is not specific for Android, it is about how to design a class that access a database. I asked here because my code is for Android.
I have a class, DBManager, to work with Sqlite database. This is a part of its implementation:
public class DBManager
{
// Variable to hold the database instance
private SQLiteDatabase db;
// Database open/upgrade helper
private DatabaseHelper dbHelper;
public DBManager(Context _context)
{
Log.v("DBManager", "constructor");
dbHelper = new DatabaseHelper(_context, SqlConstants.DATABASE_NAME, null, SqlConstants.DATABASE_VERSION);
}
public DBManager open() throws SQLException
{
Log.v("DBManager", "open");
db = dbHelper.getWritableDatabase();
return this;
}
public void close()
{
Log.v("DBManager", "close");
db.close();
}
...
/**
* Query all forms available locally.
* #return A list with all forms (form.name and form.FormId) available on local db
* or null if there was a problem.
*/
public ArrayList<Form> getAllForms()
{
Log.v("DBManager", "getAllForms");
ArrayList<Form> list = null;
Cursor c = null;
try
{
c = this.getAllFormsCursor();
if (c != null)
{
int formNameIndex = c.getColumnIndex(SqlConstants.COLUMN_FORM_NAME);
int formIdIndex = c.getColumnIndex(SqlConstants.COLUMN_FORM_ID);
c.moveToFirst();
if (c.getCount() > 0)
{
list = new ArrayList<Form>(c.getCount());
do
{
Form f = new Form();
f.Name = c.getString(formNameIndex);
f.FormId = c.getString(formIdIndex);
list.add(f);
}
while (c.moveToNext());
}
}
}
catch (Exception e)
{
e.printStackTrace();
list = null;
}
finally
{
if (c != null)
c.close();
}
return list;
}
private Cursor getAllFormsCursor()
{
Log.v("DBManager", "getAllFormsCursor");
return db.query(SqlConstants.TABLE_FORM,
new String[] {
SqlConstants.COLUMN_FORM_ID,
SqlConstants.COLUMN_FORM_NAME}, null, null, null, null, null);
}
}
And this is an AsyncTask that uses DBManager:
private class DbFormListAsyncTask extends AsyncTask<Void, Void, ArrayList<Form>>
{
private Context mContext;
private ProgressDialog loadingDialog;
private DBManager dbMan;
DbFormListAsyncTask(Context context)
{
this.mContext = context;
loadingDialog = new ProgressDialog(mContext);
loadingDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
loadingDialog.setMessage("Retriving forms. Please wait...");
loadingDialog.setCancelable(false);
loadingDialog.show();
}
#Override
protected ArrayList<Form> doInBackground(Void... arg0)
{
dbMan = new DBManager(mContext);
dbMan.open();
return dbMan.getAllForms();
}
protected void onPostExecute(ArrayList<Form> forms)
{
if (forms != null)
{
ListActivity act = (ListActivity) mContext;
act.setListAdapter(new AvaFormAdapter(act, R.layout.ava_list_item, forms));
}
else
{
TextView errorMsg = (TextView)
((FormsListActivity) mContext).findViewById(R.id.formErrorMsg);
errorMsg.setText("Problem getting forms. Please try again later.");
}
loadingDialog.dismiss();
if (dbMan != null)
dbMan.close();
}
}
As you can see I have to:
Create DBManager instance.
Open database with dbMan.open()
Call dbMan.getAllForms()
Close database with dbMan.close() on onPostExecute.
I thought that I could add db.open() and db.close() on dbMan.getAllForms() to avoid calling it every time I use dbMan.getAllForms().
What do you think about this? What is the best approach?
I would put it inside getAllForms() or do something like that
protected ArrayList<Form> doInBackground(Void... arg0)
{
dbMan = new DBManager(mContext);
dbMan.open();
ArrayList<Form> resutl = dbMan.getAllForms();
dbMan.close();
return result;
}
Since you don't need the db connection after you have the result you can close it right away.
Edit: if you run that AsyncTask several times then opening/closing will introduce unnecessary overhead. In that case you may want to instanciate the dbManager from your Activity (maybe open() in the constructor of DbManager) and close it once you leave your activity. Then pass Dbmanager to the AsyncTask.
Make your database helper class a singleton, and don't explicitly close the SQLiteDatabase. It will be closed and flushed when your app's process exits.
I have a problem with my Android application. I'm using code bellow to opening SQLite database in AsyncTask. Everything works fine but when I try to close database in onStop() or onDestroy method, it's never closed.
Code for creating and opening database:
public class SQLiteDB extends SQLiteOpenHelper{
private final Context context;
private SQLiteDatabase sqliteDatabase = null;
public SQLiteDB(Context context, String DBName) {
super(context, DBConstant.DB_NAME, null, context.getResources().getInteger(ppredota.android.navigation.view.activities.R.string.database_version));
this.context = context;
}
public void createDB() throws IOException{
if(existDB()){
this.getReadableDatabase();
this.close();
}
else {
this.getWritableDatabase();
try {
copyDB();
this.close();
}
catch (Exception e) {
throw new Error("Chyba pri kopirovani databaze");
}
}
}
private boolean existDB() {
SQLiteDatabase checkDatabase = null;
try{
String fullPath = DBConstant.DB_PATH + DBConstant.DB_NAME;
checkDatabase = SQLiteDatabase.openDatabase(fullPath, null, SQLiteDatabase.OPEN_READWRITE);
}
catch (SQLiteException sqle) {
Log.i("existDB()", "Databaze nelze otevrit, neexistuje");
}
if(checkDatabase == null){
Log.i("existDB", "Databaze jeste neexistuje...");
return false;
}
else{
Log.i("existDB", "Databaze uz existuje...");
checkDatabase.close();
return true;
}
}
private void copyDB() throws IOException {
InputStream inDBStream = context.getAssets().open(DBConstant.DB_NAME);
String newDBPath = DBConstant.DB_PATH + DBConstant.DB_NAME;
OutputStream outDBStream = new FileOutputStream(newDBPath);
Log.i("copyDB", "Otevren outputstream s cestou k nove databazi");
byte[] buffer = new byte[1024];
int length;
while ((length = inDBStream.read(buffer))>0){
outDBStream.write(buffer, 0, length);
}
outDBStream.flush();
outDBStream.close();
inDBStream.close();
}
public void openDB() throws SQLException {
String fullPath = DBConstant.DB_PATH + DBConstant.DB_NAME;
if(sqliteDatabase!=null){
if(sqliteDatabase.isOpen()){
Log.i("openDB()", "Databaze je jiz otevrena");
}
else{
sqliteDatabase = SQLiteDatabase.openDatabase(fullPath, null, SQLiteDatabase.OPEN_READONLY);
Log.i("openDB()", "Databaze" + sqliteDatabase.getPath() + "otevrena");
}
}
else{
sqliteDatabase = SQLiteDatabase.openDatabase(fullPath, null, SQLiteDatabase.OPEN_READONLY);
if(sqliteDatabase.isOpen()){
Log.i("openDB()", "Databaze otevrena");
}
}
}
#Override
public void close() {
if(sqliteDatabase!=null){
sqliteDatabase.close();
Log.i("close()", "Databaze zavrena");
}
super.close();
}
public SQLiteDatabase getSQLiteDatabase() {
if(sqliteDatabase==null){
Log.i("getSQLiteDatabase()","Problem, vraci sqliteDatabase = null");
}
else{
Log.i("getSQLiteDatabase()","instance sqliteDatabase vracena bez problemu");
}
return sqliteDatabase;
}
AssyncTask class:
public class OpenDatabaseTask extends AsyncTask {
private Context context;
private SQLiteDB sqliteDB;
public OpenDatabaseTask(Context context,SQLiteDB sqliteDB) {
this.context = context;
this.sqliteDB = sqliteDB;
}
#Override
protected Void doInBackground(Void... params) {
publishProgress();
try {
sqliteDB.createDB();
} catch (IOException e) {
e.printStackTrace();
}
sqliteDB.openDB();
return null;
}
#Override
protected void onProgressUpdate(Void...unused){
Log.i(OpenDatabaseTask.class.toString(), "Spusteno vlakno");
}
}
and Activity (only important part):
private SQLiteDB sqliteDB;
private SQLiteData sqliteData;
private OpenDatabaseTask openDatabaseTask;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.navigatemenu);
sqliteDB = new SQLiteDB(getApplicationContext(), sourceDatabaseName);
openDatabaseTask = new OpenDatabaseTask(getApplicationContext(), sqliteDB);
openDatabaseTask.execute();
protected void onDestroy(){
super.onDestroy();
Log.i("onDestroy()", "Pokus o zavreni databaze");
//here is the problem, database never closed
sqliteDB.close();
}
protected void onStop(){
super.onStop();
Log.i("onStop()", "Pokus o zavreni databaze");
//here is the problem, database never closed
sqliteDB.close();
}
protected void onPause(){
super.onPause();
}
protected void onResume(){
super.onResume();
//Log.i("onResume()", "Pokus o otevreni databaze");
}
}
So when I try use a close() method to closing database, sqliteDatabase is always null and database is never closed. So database is still opened and after calling onDestroy exception occurs.
Thank you for your time and sorry for my english, I'm czech :)
Just a guess (assuming you want to close on destroy)
close the database before calling the super
protected void onDestroy(){
// close befor super is called
sqliteDB.close();
super.onDestroy();
Log.i("onDestroy()", "Pokus o zavreni databaze");
// sqliteDB.close(); // super.onDestroy may already has destroyed the DB
}
Note:
Assuming that the database only exists and is open while the activity is visible you should open the database in onResume() and close it in onPause().
If the database should be open when the code is loaded into memory create it in onCreate and close it in onDestroy
In your example you open it in onCreate and close it in onStop. Problem: when the activity becomes visible for the 2nd time the db is closed.
For details see android activity documentation and look into the Application-Lifecycle at the button.
I have an app with heavy db interaction. I didnt user helper. My db is opened lots of times, in UI thread and in background thread too, but never ever closed. Had no problems so far, dont know if it is the right way to do...