I'm using an extension of the SQLiteOpenHelper. My understanding is that onCreate only runs when the requested database does not exist. onOpen should run every time a database is opened.
This seems to work between activities within my app - I need to instantiate a new instance of the database helper in each activity, and onOpen is run but not onCreate. However each time I restart the app, onCreate is being called. Am I misunderstanding how this should work or did I simply implement it wrong?
Here's my helper class:
public class DBWrapper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "MyTest.db";
private static final int DATABASE_VERSION = 2;
public DBWrapper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
Log.d("SQLite DBWrapper","OnCreate run");
ver1(db);
ver2(db);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.d("SQLite DBWrapper","OnUpgrade run; oldVer: " + oldVersion + "; newVer: " + newVersion);
if (oldVersion < 2) {ver2(db);}
}
#Override
public void onOpen(SQLiteDatabase db) {
Log.d("SQLite DBWrapper","OnOpen run");
}
private void ver1(SQLiteDatabase db) {
Log.d("SQLite Wrapper","Creating new Version 1");
db.execSQL("create table UserList (ID integer primary key, Name String, State String, Email String, Status String);");
db.execSQL("create table Contacts (ContactID integer, Display_Name String, Email_Address String, IsPrimary integer);");
}
private void ver2 (SQLiteDatabase db) {
Log.d("SQLite Wrapper","Updating to Version 2");
db.execSQL("create table ActivityRecord (UserID String, ActID String, ActDate date, Rating REAL, Comment String, RateDate date, primary key(UserID,ActID));");
}
//Other methods for inserting and retrieving data
}
This is how I create an instance of the helper in each activity:
private DBWrapper DBHelper;
private SQLiteDatabase db;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
DBHelper = new DBWrapper(this);
db = DBHelper.getWritableDatabase();
}
My logcat is indicating every time I restart my app (in debug mode at least) the onCreate is being called (along with ver1 and ver2). What have I done wrong?
UPDATE: I added more logging and found that A) This is happening on both release and debug variants; B) when I logged db.getVersion() in onCreate, it reported "0". So that either means it forgot the version number when I closed and reopened the app or the db was deleted when the app closed.
Dont create instance of DBWrapper everytime you launch an activity.Just create it once when your application instance is created and use the same instance across all activities of app.See if you still notice the problem.
I doubt multiple instances of DBWrapper are being created in your application(Although multiple instances should have worked logically).
Refer code below:
public class MyApplication extends Application {
DBWrapper mDbwrapper;
#Override
public void onCreate() {
super.onCreate();
mDbwrapper=new DBWrapper();//Share this object with all the activities of the class
}
}
Add this line to manifest:
<application android:icon="#drawable/icon" android:label="#string/app_name" android:name="MyApplication">
Related
when I extend my DatabaseClass with SQLiteOpenHelper class I have to implement constructor which must contains Context in its parameter. If I have to use this databases with my Other classes context maybe changed. What changes are done when I provide different context.
public class DatabaseClass extends SQLiteOpenHelper {
static String TABLE_NAME = "hammad";
static String DATABASE_NAME = "databases.db";
SQLiteDatabase database;
public DatabaseClass(Context context) {
super(context, DATABASE_NAME, null, 1);
Log.i("xcv", "Constructor called");
this.database = this.getWritableDatabase();
}
#Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
Log.i("xcv", "OnCreate");
try {
sqLiteDatabase.execSQL("create table student (id integer primary key autoincrement,name varchar)");
Log.i("xcv", "On Create query Table created");
} catch (Exception ffff) {
Log.i("xcv", "2:"+ffff.getMessage());
}
}
StartPage.java
public class StartPage extends AppCompatActivity {
DatabaseClass database;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start_page);
setLoginBtn(); // Set Login Btn
database=new DatabaseClass(this);
}
}
Class2.java
public class Class2 extends AppCompatActivity {
DatabaseClass database;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start_page);
setLoginBtn(); // Set Login Btn
database=new DatabaseClass(this);
}
}
"Context may be changed" You should be first clear about this line... Yes context will be changed every time you create new instance of database by calling from different class and it has to change.... Bcoz context is the one that states this activity has the permision to access the database.... So when you pass "this" of xyz activity then that xyz has permission to access data and modify data in the database... It is like showing an ID card to database before taking control over its resources....
Also you can access your database from any class by passing the context, you can retrieve data, modify data and close connection...
Scenario : Its like single fridge in a home you can open n only see whats in it.. You can take out something and eat it... Or you can place in something... And samething can be done by any of the family members... While "this" or "context" is the individual person
SQLiteOpenHelper uses the Context passed in to find your application package-private data directory where the database files are located. The package is the package declared in your app's AndroidManifest.xml, not the Java package of your class files.
All Contexts in your application have the same package-private data directory and the database will work just fine with any valid Context.
I looked up different tutorials about databases and saw, that it was mostly the same approach.
What I don't understand: As I know, onCreate() can ONLY be called automatically by the start of an activity (startActivity(new Intent(this)).
But in the following example, the class that extends SQLiteOpenHelper is not an activity but includes the onCreate() method, that never get called manually. How does this work and especially WHEN is its startpoint? Will this be called when you call the constructor? I tried to look this up with logcat and I never got a message, that onCreate() has been called.
I have a class like this:
public class MySQLiteHelper extends SQLiteOpenHelper {
// Database Version
private static final int DATABASE_VERSION = 1;
// Database Name
private static final String DATABASE_NAME = "BookDB";
public MySQLiteHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
// SQL statement to create book table
String CREATE_BOOK_TABLE = "CREATE TABLE books ( " +
"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"title TEXT, "+
"author TEXT )";
// create books table
db.execSQL(CREATE_BOOK_TABLE);
}
And an external Activity, that handles this class:
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
MySQLiteHelper db = new MySQLiteHelper(this);
// add Books
db.addBook(new Book("Android Application Development Cookbook", "Wei Meng Lee"));
db.addBook(new Book("Android Programming: The Big Nerd Ranch Guide", "Bill Phillips and Brian Hardy"));
db.addBook(new Book("Learn Android App Development", "Wallace Jackson"));
// get all books
List<Book> list = db.getAllBooks();
}
}
As I know, onCreate() can ONLY be called automatically by the start of an activity (startActivity(new Intent(this)).
There are a variety of places in Android where onCreate() methods appear, including Activity, Service, ContentProvider, and SQLiteOpenHelper.
How does this work
onCreate() of a SQLiteOpenHelper will be called in response to an getReadableDatabase() or getWriteableDatabase() call, if and only if the database does not already exist.
The fact that both of the classes have a function with the same name doesn't mean that they have something in common.
onCreate in SQLiteOpenHelper is called when you ask for the database for the first time (with getReadeableDatabase() or getWritableDatabase())
I have the following code below.
I am creating a database in my application that uses SQLiteOpenHelper.
I have couple of concerns and would appreciate some consults.
Direct answers for these were not found on stack overflow as they might be subjective.
1 - I will be using this database from several activities. However I am not planning on making this a singleton to avoid leaks, but rather I will be getting the getWritableDatabase() and getReadableDatabase() inside each method. I plan on doing a db.close() inside each activity's onDestroy() .Is this advisable ? given my app has couple of activites and is not a huge app.
2 - I am not following and DAO model, nor I am using a different class for every table.
The way I see it, I don't need to. Do I ?
3 - (A question rather than consult)
In the code below, I am not creating a database of the form
private SQLiteDatabase database;
So all the references to the database (from my activities) are being done via the methods in the same subclassed SQLiteOpenHelper, therefore I am referencing the physically created database directly via getWritableDatabase and getReadableDatabase.
Do I need to create an instance of SQLiteDatabase and use it ? Even inside the subclass of SQLiteOpenHelper ?
Below is the code.
public class DbHelper extends SQLiteOpenHelper
{
private static final String DATABASE_NAME = "myDbName";
private static final String DATABASE_TABLE = "myTable";
private static final int DATABASE_VERSION = 1;
private Context ctx;
public DbHelper(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.ctx = context;
}
#Override
public void onCreate(SQLiteDatabase db)
{
db.execSQL("CREATE TABLE myTable(_id INTEGER PRIMARY KEY, title TEXT);");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
//nothing here now. maybe later.
}
public void insertTitle(String title)
{
ContentValues titleCV = new ContentValues();
titleCV .put("title", title);
getWritableDatabase().insert(DATABASE_TABLE, null, titleCV );
}
public void getTitles()
{
Cursor result = getReadableDatabase().rawQuery("SELECT _id, title FROM myTable", null);
while (result.moveToNext())
{
int id = result.getInt(0);
String titleGotten= result.getString(1);
}
result.close();
}
Q1
If you have a scenario within your app that have two parallel threads accessing the database, use a single instance of the SQLiteOpenHelper (singleton or member in the Application or whatever). If not you don't need to.
about calling db.close(), if it is in the onDestroy(), then it's fine.
Q2
a DAO is an abstraction layer to ease maintaining and scaling your project. If you are not going to scale or maintain your code (upcoming releases or something), then I suppose you don't need one.
Q3
You don't need to create an instance of SQLiteDatabse. when you call getReadableDatabase() or getWritableDatabase(), SQLiteOpenHelper creates and maintains an instance. The same instance is used the next time you call getReadable\WritableDatabase().
let me know if you still have questions.
step 1: make a staic instace of SqliteOpenHelper
step 2: you never close conexion to database, sqlite manage itself the sequencial access to write or read :)
private static ControladorBBDD instancia;
my class: public class ControladorBBDD extends SQLiteOpenHelper {
default :
private ControladorBBDD(Context ctx_p) throws Exception {
super(ctx_p, DB_NAME, null, DATABASE_VERSION);
try {
ControladorBBDD.ctx = ctx_p;
DB_PATH = ctx.getDatabasePath(DB_NAME).getAbsolutePath();
String myPath = DB_PATH;// + DB_NAME;
this.createDataBase();
db = SQLiteDatabase.openDatabase(myPath, null,
SQLiteDatabase.OPEN_READWRITE);
} catch (SQLiteException ex) {
Conexiones.escribirLog(Log.getStackTraceString(ex),
ctx.getString(R.string.versionReal));
db.close();
}
}
and my way to implement a conexion to database:
public static synchronized ControladorBBDD getBBDD(Context ctx_p)
throws Exception {
if (instancia == null) {
instancia = new ControladorBBDD(ctx_p);
}
return instancia;
}
and to call it from activities:
dblectura = ControladorBBDD.getBBDD(getApplicationContext());
where private ControladorBBDD dblectura;
i hope that it helps, important thing is that you use applicationContext, no Activity context ;))
well if i were u i would create a class and the dbhelper as a subclass then i would use a open and a close function for main class and also the insert
whenever i want to use database i do it like this
mainclass mc=new mainclass(this);
mc.open();
mc.insert();
mc.close();
When using same database name for multiple ContentProviders, query fails with exception thrown as 'no such table'.
I researched the reference, and books, the Internet discussions, but could not find resolution.
I noticed that all the ContentProviders fail except the one ContentProvider declared first in the manifest. So I gave unique database name and the exception goes away. It works but it's weird to have multiple single-table databases.
I want to figure out why the problem occurs if possible. Below is my implementation in essence.
All ContentProviders have separate SQLiteOpenHelper defined as inner private class. DATABASE_NAME and DATABASE_VERSION are all the same.
public class TheFirstProvider extends ContentProvider {
private static final String DATABASE_NAME = "dbname.db";
private static final int DATABASE_VERSION = 1;
private SQLiteOpenHelper dbHelper;
#Override
public boolean onCreate(){
mContext = getContext();
dbHelper = new FirstDbHelper(mContext, DATABASE_NAME, null, DATABASE_VERSION);
}
private class FirstDbHelper extends SQLiteOpenHelper {
...
private static final String DATABASE_CREATE_FIRST = ... ;
#Override
public void onCreate(SQLiteDatabase db){
db.execSQL(DATABASE_CREATE_FIRST);
}
}
Check your Create table statement and verify if it was correctly executed and see if the table you are using on the query has the exact same name as the one created. Sometimes a little mistake on the DDL (create statement) lead to problems like this that happens silently.
I also suggest you to install this eclipse plugin to visualize the database on your emulator so you can see the tables you have created and check if it's what you've expected.
private class FirstDbHelper extends SQLiteOpenHelper{
public FirstDbHelper(Context context) {
super(context,DATABASE_NAME,null,DATABASE_VERSION);
// TODO Auto-generated constructor stub
}
#Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
String query="Your Query";
db.execSQL(query);
}
Set your Code as below.It will Work.
Exception:
CREATE TABLE android_metadata failed
Failed to setLocale() when constructing, closing the database
android.database.sqlite.SQLiteException: database is locked
My app works fine and has no db issues, except when onUpgrade() is called.
When onUpgrade is automatically called, it tries to use the CarManager class below to do data manipulation required for the upgrade. This fails because the db is locked.
Because this seems like it should be a normal thing to do, it seems that I must not be structuring the following code correctly (two classes follow, a helper and a table manager):
public class DbHelper extends SQLiteOpenHelper {
private Context context;
//Required constructor
public DbAdapter(Context context)
{
super(context, "my_db_name", null, NEWER_DB_VERSION);
this.context = context;
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
overrideDB = db;
CarManager.migrateDataForOnUpgrade(context);
}
}
public class CarManager {
DbHelper dbHelper;
public CarManager(Context context)
{
dbHelper = new DbHelper(context);
}
public void addCar(String make, String model)
{
ContentValues contentValues = new ContentValues();
contentValues.put("make", make);
contentValues.put("model", model);
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.insert("car", null, contentValues);
db.close();
}
public static void migrateDataForOnUpgrade()
{
//Code here that migrates data when onUpgrade() is called
//Db lock happens here
}
}
Any ideas?
Do people set up table manager (ex: dao) differently than this?
edit: I talked to the google team # android developer hours, and they said onUpgrade3 was never meant to do anything like structural changes (alters). So yes, it seems like there are some hacks that must be used in many instances right now.
I use the following model by extending the Application class. I maintain a single static instance of my db helper which all other app components use...
public class MyApp extends Application {
protected static MyAppHelper appHelper = null;
protected static MyDbHelper dbHelper = null;
#Override
protected void onCreate() {
super.onCreate();
...
appHelper = new MyAppHelper(this);
dbHelper = MyAppHelper.createDbHelper();
dbHelper.getReadableDatabase(); // Trigger creation or upgrading of the database
...
}
}
From then on any class which needs to use the db helper simply does the following...
if (MyApp.dbHelper == null)
MyApp.appHelper.createDbHelper(...);
// Code here to use MyApp.dbHelper