This question already has answers here:
When does SQLiteOpenHelper onCreate() / onUpgrade() run?
(15 answers)
Closed 7 years ago.
I am very new to android programming. I want to use SQLiteOpenHelper class to do some database operations. Here is my SqliteController class that extends SQLiteOpenHelper:
public class SqliteController extends SQLiteOpenHelper {
Context context;
public SqliteController(Context context) {
super(context, "sectionsDB", null, 1);
this.context = context;
}
#Override
public void onCreate(SQLiteDatabase db) {
String query;
query = "CREATE TABLE Sections ( chapterName TEXT, sectionName TEXT, body TEXT)";
db.execSQL(query);
Log.i("tablecreation", "table created");
}
}
(I have just mentioned the part that I have problem with)
in my main activity I have created instance of above class in onCreate method of activity like this:
SqliteController controller = new SqliteController(this);
I want to populate database by reading from xml file once in onCreate method of SqliteController so after newing SqliteController in main activity I don't want to do any operation with database. If I add controller.getWritableDatabase(); it seems that I have some operations to do with it but all I do is in SqliteController class. Any suggestion?
You can add something like this:
SqliteController controller = new SqliteController(this);
controller.getWritableDatabase();
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())
If multiple activities within an app call the constructor of my SQLiteOpenHelper with themselves as the context argument, can I be sure that they will all access the same database?
For example, let's say I have:
package foo.bar;
public class Activity1 extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SQLiteDatabase db = new MySQLiteOpenHelper(this).getReadableDatabase();
:
}
}
and
package foo.bar.baz;
public class Activity2 extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SQLiteDatabase db = new MySQLiteOpenHelper(this).getReadableDatabase();
:
}
}
Here's in the skeleton of my SQLiteOpenHelper subclass:
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "comments.db";
private static final int DATABASE_VERSION = 1;
public MySQLiteOpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
:
}
I can't find anything in the documentation that guarantees that the two activities get the same database. On the other hand, I haven't seen any mentions of people getting different databases from contexts within a single application. Are the database paths guaranteed to be identical?
SQLiteOpenHelper has 2 constructors and the second parameter for both of them is the database file name.
If you used the same database file name when using SQLiteOpenHelper from different activities, you will get access to the same database.
This is usually taken care of in the constructor of the inheriting class you create - DATABASE_NAME is a constant:
public MySQLiteOpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
if you do it as the Android folks recommend (http://developer.android.com/guide/topics/data/data-storage.html#db)
Then yes, all activities within an app will see the same database
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();
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