inserting data without getWritableDatabase()? - android

I'm practicing android, I was able to insert using db.insert() without the use of getWritableDatabase() why is that? I thought we need db = getWritableDatabase(); before we can insert to the database
private SQLiteDatabase db;
#Override
public void onCreate(SQLiteDatabase db) {
this.db = db;
//some table creation
db.execSQL(TABLE);
fillQuestionsTable();
}
private void insertQuestion(Question question){
ContentValues cv = new ContentValues();
//some code
db.insert(QuestionsTable.TABLE_NAME, null, cv);
}
I thought it should be like this?
private void insertQuestion(Question question){
db = getWritableDatabase();
ContentValues cv = new ContentValues();
//some code
db.insert(QuestionsTable.TABLE_NAME, null, cv);
}
here's my implementation:
private void fillQuestionsTable(){
Question q1 = new Question("Programming, Easy: A is correct", "A", "B", "C",
1, Question.DIFFICULTY_EASY, Category.PROGRAMMING);
insertQuestion(q1);
}

your code works, because you are storing reference to db object in onCreate and then re-using this reference further. that should work in most of common cases, but getWritableDatabase() and getReadableDatabase() methods are there for a reason - you should use them in your insert/update/remove methods just like you posted. For safer, more reliable access in future app releases when there may/probably will be more code, more tables and more complicated lifecycle of app. and get rid of private SQLiteDatabase db; declaration on top of your SQLiteOpenHelper, use only locally fetched (with above methods) database object

Related

getWritableDatabase() instance throughout the application lifecycle

I have made Singelton object to make queries to SQLiteOpenHelper in which I have saved instance of getWriteableDatabase(). Throughout the application lifecycle, for all select and insert/update queries I am using that instance from multiple IntentServices. I have read Write-ahead Logging (WAL) which supports concurrent execution of queries. I am using the above instance with WAL disabled. Actually at a point the database does not return data, I was wondering if SQLite file can get corrupted because I am using getWritableabledatabse for reading/writing from multiple intent services.
Can a deadlock occur with this approach?
As per my findings, WAL should be enabled if you are accessing database from multiple threads.
EDIT
DatabaseAdapter.java
public class DatabaseAdapter {
private Context mContext;
private SQLiteDatabase mSqLiteDatabase;
private DatabaseHelper mDbHelper;
private static DatabaseAdapter adapter;
public static DatabaseAdapter getInstance() {
if(adapter == null) {
synchronized (DatabaseAdapter.class) {
if(adapter == null)
adapter = new DatabaseAdapter(MyApp.getInstance());
}
}
return adapter;
}
public DatabaseHelper getDatabaseHelper() {
return mDbHelper;
}
private DatabaseAdapter(Context c) {
mContext = c;
mDbHelper = new DatabaseHelper(mContext);
mSqLiteDatabase = mDbHelper.getWritableDatabase();
}
private long insert(String tableName, ContentValues contentValues) throws Exception {
this.open();
long id = mSqLiteDatabase.insert(tableName, null, contentValues);
this.close();
return id;
}
private int update(String tableName, ContentValues contentValues, int pk_id) throws Exception {
this.open();
String whereClause = mDbHelper.pk_id + " = " + pk_id;
int n = mSqLiteDatabase.update(tableName, contentValues, whereClause, null);
this.close();
return n;
}
private ArrayList<MyObject> selectChallans(String whereClause, String orderby) throws Exception {
try {
ArrayList<MyObject> arrayListObjects = new ArrayList<MyObject>();
Cursor queryCursor = mSqLiteDatabase.query(tableName, null, whereClause, null, null, null, orderby, null);
if (queryCursor == null) {
return null;
}
while (queryCursor.moveToNext()) {
MyObject myobject = getMyObject(queryCursor);
if(myobject != null)
arrayListObjects.add(myobject);
}
queryCursor.close();
return arrayListObjects;
} catch (Exception e) {
e.printStackTrace();
this.forceClose();
throw e;
}
}
}
I am using this Adapter singleton instance through the application for insert/update and select queries. I was concerned about mSqLiteDatabase instance. These functions are being called from multiple IntentServices.
AFAIK, the best practice is calling getWritableabledatabse only once with one SQLiteOpenHelper. After that, you can use the returned database for all thread without any issue. You have to make sure that you are using one database connection. You can check this Good Answer for more detail.
The SqliteOpenHelper object holds on to one database connection. It appears to offer you a read and write connection, but it really doesn't. Call the read-only, and you'll get the write database connection regardless.
So, one helper instance, one db connection. Even if you use it from multiple threads, one connection at a time. The SqliteDatabase object uses java locks to keep access serialized. So, if 100 threads have one db instance, calls to the actual on-disk database are serialized.
So, one helper, one db connection, which is serialized in java code. One thread, 1000 threads, if you use one helper instance shared between them, all of your db access code is serial. And life is good (ish).
For me, I usually create and open the SQLiteOpenHelper in Application class, then I can use it everywhere in any thread in my app.

How to update a record in SQLite with Android?

How to update a record in SQLite with Android?
Hello.
I write because I am unfortunately stuck in my project and I hope you can help me.
How do I update a record in a database?
For example in a contact database. In this database of contacts, the following keys are used: name, phone, email and address; my problem is when I need to modify a record, what must I do to modify a record.
I hope you can help me. Thanks in advance.
This is the SQLite code to update the registry:
// Updating single contact
public int updateContact(Contact contact) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_NAME, contact.getName());
values.put(KEY_PH_NO, contact.getPhoneNumber());
// updating row
return db.update(TABLE_CONTACTS, values, KEY_ID + " = ?", new String[] { String.valueOf(contact.getID()) });
}
This same code I have found on many websites, but my problem is how to call the code from the MainActivity with Java.
1- create an instance from ur database in the main activity:
DBhelper db = new DBhelper(this);
2- call open:
db.open();
3- set the update method:
db.updateContact(name,phone);
4- close the database connection:
db.close();
5- open and close function in ur database helper class:
public DBhelper open() throws SQLException {
mDb = mDbHelper.getWritableDatabase();
return this;
}
public void close() {
mDbHelper.close();
}
6- also you gotta define those as global variables:
private DatabaseHelper mDbHelper;
private SQLiteDatabase mDb;
my advice to you is not to depend on written code you gotta learn to write it ur self specially database creation and usage it is really important so here is a good tutorial for you, you could benefit from it: http://www.tutorialspoint.com/android/android_sqlite_database.htm.
Good luck

Android 'simple' database scenario: Is it better to close using database.close() or databaseHelper.close()?

In an Android 'simple' database scenario, is there any benefit or reason to use database.close() and Not databaseHelper.close() ? Is there any benefit or reason to use databaseHelper.close() and Not database.close() ?
Is there a technical reason why both these close methods (shown below) exist?
Thanks,
James
MyDatabaseHelper databaseHelper = new MyDatabaseHelper(this);
SQLiteDatabase database = databaseHelper.getWritableDatabase();
ContentValues valuesToInsert = new ContentValues();
int id = 0;
valuesToInsert.put("_id", id);
valuesToInsert.put("name", "test");
database.insert("MyRecordsTable", null, valuesToInsert);
database.close();
OR
MyDatabaseHelper databaseHelper = new MyDatabaseHelper(this);
SQLiteDatabase database = databaseHelper.getWritableDatabase();
ContentValues valuesToInsert = new ContentValues();
int id = 0;
valuesToInsert.put("_id", id);
valuesToInsert.put("name", "test");
database.insert("MyRecordsTable", null, valuesToInsert);
databaseHelper.close();
There isn't really a huge difference. This is the whole definition of close() within SQLiteOpenHelper:
/**
* Close any open database object.
*/
public synchronized void close() {
if (mIsInitializing) throw new IllegalStateException("Closed during initialization");
if (mDatabase != null && mDatabase.isOpen()) {
mDatabase.close();
mDatabase = null;
}
}
The reason both exist, is that there may be instances where developers only use SQLiteOpenHelper for interfacing with their database and want the close() method as a convenience to directly access the DB, or vice versa if developers don't choose to use the OpenHelper at all.

delete vs execSQL commands android

So I have a database, SQLiteDatabase db I am writing a couple private methods in my manager class that will be called by a public method:
public void updateData (MakeabilityModel newData){
SQLiteDatabase db = this.getWritableDatabase();
db.beginTransaction();
try {
reWriteSVTable(db, list);
db.setTransactionSuccessful();
} catch (Exception e){
//TODO through rollback message?
e.printStackTrace();
} finally {
db.endTransaction();
}
}
//Private Methods
private void clearTable(SQLiteDatabase db, String table){
db.delete(table, null, null);
}
private void reWriteSVTable(SQLiteDatabase db, List<MakeabilityLens> lenses){
clearTable(db, singleVision);
ContentValues cv;
for(int i=0; i<lenses.size(); i++){
cv = new ContentValues();
cv.put(colScreenID, hsID);
cv.put(colIconID, id);
cv.put(colRank, hsTotal);
db.insert(isLookUp, colID, cv);
}
}
My question is this.. i want to be able to throw sql exceptions back to the public method so that if there is an exception, it will kill the transaction and rollback ALL data..
it appears that using delete() and insert() methods are cleaner than execSQL() but don't throw sqlExceptions. execSQL() on the other hand does? do i need to uses execSQL and how do I insure that should it throws an exception in any of the private methods that it will catch it and roll it back in the private method
first of all execSQL() throws an exception if the sql string is not valid. that is the exception is on the sql string syntax NOT the sql operation. that is, it will not throw an exception if the sql statement is valid but the operation failed (because of a constraint for example).
So ..
basically the only difference between execSQL() and delete() is that delete() returns the number of rows affected (in your case, the number of deleted rows), but execSQL() doesn't.
Note:
for delete() to return the number of rows affected, you have to pass any value other than null in the where clause parameter. In your case, pass "1".

Database unclosed cursor. Close it after insert method

Would you mind pointing out what's wrong with this peace of code. genresCursor contains "Application did not close the cursor or database object that was opened here" exception. How do I really close this cursor after inserting ?
Thanks.
UPD: It seems like there wasn't a problem at all. Even though it contains exception that's still possible to extract data. I must've been wrong in my real application and this exception led me to conclusion that's it had been the issue. Thanks everyone for participating.
public class DatabaseCursorActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
HashMap<Integer, String> _dummy = new HashMap<Integer, String>();
OpenDatabaseHelper helper = new OpenDatabaseHelper(this);
SQLiteDatabase db = helper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(OpenDatabaseHelper.GENRES_ID_KEY, 1);
values.put(OpenDatabaseHelper.GENRES_TITLE_KEY, "Test");
db.insert(OpenDatabaseHelper.GENRES_TABLE_NAME, null, values);
db.close();
helper.close();
db = helper.getReadableDatabase();
Cursor genresCursor = db.query(OpenDatabaseHelper.GENRES_TABLE_NAME, new String[]{OpenDatabaseHelper.GENRES_ID_KEY, OpenDatabaseHelper.GENRES_TITLE_KEY }, null, null, null, null, null);
int i = genresCursor.getColumnCount();
genresCursor.moveToFirst();
}
public class OpenDatabaseHelper extends SQLiteOpenHelper {
public static final String GENRES_TABLE_NAME = "genres";
public static final String GENRES_ID_KEY = "id";
public static final String GENRES_TITLE_KEY = "title";
public OpenDatabaseHelper(Context context) {
super(context, "ttt.db", null, 1);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + GENRES_TABLE_NAME + "( id integer primary key not null, title text);" );
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
}
You are opening the database first and after inserting you closed the database and then opened again to read the value.
First thing you don't need to close and open it again.You can do all of your operation and can close it as you are still in same block of code.
After doing the operation with your genresCursor close it by by genresCursor.close() and then close your db.Hopefully it will be fine.
I do not understand why you insert this code:
db = helper.getReadableDatabase();
Cursor genresCursor = db.query(OpenDatabaseHelper.GENRES_TABLE_NAME, new String[]{OpenDatabaseHelper.GENRES_ID_KEY, OpenDatabaseHelper.GENRES_TITLE_KEY }, null, null, null, null, null);
int i = genresCursor.getColumnCount();
genresCursor.moveToFirst();
The problem is in this part of code. If you just want to close cursor then call genresCursor.close(). But from the architecture point of view I do not understand why you need this code.
The Best Practice to work with cursor and database is that you should open it and close it in the same block of code. When I use to insert rows into database I use to open it at start and then insert many column and close it just before returning.
In API before Honeycomb you wont get any log message and performance issue regarding unclosed cursor but API before Honeycomb has a Cursor not closed detector which will log message about cursor not being closed.
Edit:
Close Database within same block of code. Cursor can be closed as per the scenario but must be closed before Context Deletion.

Categories

Resources