Static object has separate instance in BroadCastReceiver execution? - android

I have a static, singleton instance of a SQLiteOpenHelper implementation.
public class MyDbHelper extends SQLiteOpenHelper {
public static final int DATABASE_VERSION = 5;
public static final String DATABASE_NAME = "myapp.db";
public static SQL_CREATE_MY_TABLE ="some correct table creation sql";
public static SQL_DELETE_MY_TABLE="some correct table delete sql";
...
public MyDbHelper (Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_MY_TABLE);
db.execSQL(SQL_CREATE_OTHER_TABLE);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(SQL_DELETE_MY_TABLE);
db.execSQL(SQL_DELETE_OTHER_TABLE);
onCreate(db);
}
}
I have another wrapper over the helper as:
public class MyAppDb {
private static MyDbHelper mydbHelper;
public static MyDbHelper getDbHelper(){
if(null == mydbHelper){
mydbHelper= new MyDbHelper(ctx);
return mydbHelper;
}else{
return mydbHelper;
}
}
}
I am using the mydbHelper from this getDbHelper() in my main Ui code(at various places), as well as in a BroadcastReceiver of an Alarmmanager that executes every 5 mins, and in another system BroadcastReceiver.
Sample usage:
SQLiteDatabase db = MyAppDb.getDbHelper().getReadableDatabase();
Intermittently, I get SQLiteDatabaseLockedException and SQLiteException on the the db implementations from the above mydbHelper.
It seems as though although static, there are two different instances of the MyDbHelper occuring at the same time.
What is happening? Can a static object have a separate instance created from BroadCastReceiver?
Or I am doing it wrong?

Related

SQLite database problems

I have veritabani.java and i create database in this class. Then i create object in mainactivity.java. But when i run app. the program dont move database.java so i cant create database how i can solve this problem.
veritabani.java
public class veritabani extends SQLiteOpenHelper {
private static final String VERİTABANİ_ADİ="kayit";
public veritabani(Context c)
{
super(c,VERİTABANİ_ADİ,null,2);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE kayit(ilacadi TEXT);");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXIST kayit");
onCreate(db);
}
}
mainactivity.java
public class MainActivity extends Activity {
private veritabani v1;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.home);
v1=new veritabani(this);
}
v1=new veritabani(this) doesnt work.
Try this code
public class DBAdapter
{
private static final String DATABASE_NAME = "GSDATA.db";
private static final int DATABASE_VERSION = 2;
private static final String CREATE_COVERPHOTO_TABLE = "CREATE TABLE IF NOT EXISTS COVERPHOTO (path Text,date DATE);";
private final Context context;
public String group;
private DatabaseHelper DBHelper;
private static SQLiteDatabase db;
public DBAdapter(Context ctx)
{
this.context = ctx;
DBHelper = new DatabaseHelper(context);
}
private class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db)
{
db.execSQL(CREATE_COVERPHOTO_TABLE);
System.out.println("The Database is Created Here :");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// db.execSQL("DROP TABLE IF EXISTS calSimpleNote");
onCreate(db);
}
} // database helper class complete
// ---opens the database---
public DBAdapter open() throws SQLException {
db = DBHelper.getWritableDatabase();
return this;
}
// ---closes the database---
public void close() {
DBHelper.close();
db.close();
}
// and write below line in main activity
DBAdapter adapter = new DBAdapter(MainActivity.this);
I'm not sure what you mean by "the program dont move database.java" but i had issues with databases using SQLiteOpenHelper.
Actually, SQLiteOpenHelper calls " public void onCreate(SQLiteDatabase db)" only once, so if you change your tables between 2 launch, it won't be updated.
To solve this you have to manually delete the database by going into parameters / applications / [your_app] / erase data (or something like this) and try again.

SQLite Connection leaked although everything closed

I found many stuff like close the connection and close the cursor, but I do all this stuff. Still the SQLite connection leaks and I get a warning like this:
A SQLiteConnection object for database was leaked!
I have a database manager this, which I call in my activities with the following code:
DatabaseManager dbm = new DatabaseManager(this);
The code of my database manager class follows now:
public class DatabaseManager {
private static final int DATABASE_VERSION = 9;
private static final String DATABASE_NAME = "MyApp";
private Context context = null;
private DatabaseHelper dbHelper = null;
private SQLiteDatabase db = null;
public static class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
//create database tables
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//destroy and recreate them
}
}
public DatabaseManager(Context ctx) {
this.context = ctx;
}
private DatabaseManager open() throws SQLException {
dbHelper = new DatabaseHelper(context);
db = dbHelper.getWritableDatabase();
if (!db.isReadOnly()) {
db.execSQL("PRAGMA foreign_keys = ON;");
}
return this;
}
private void close() {
dbHelper.close();
}
}
When I call a database method, I do the following thing:
public Object getData() {
open();
//... database operations take place ...
close();
return data;
}
But as I said, I still get this SQLite connection leaked warning.
What am I doing wrong?
The bolded font in the citation corresponds to this part in your code:
private DatabaseManager open() throws SQLException {
dbHelper = new DatabaseHelper(context);
db = dbHelper.getWritableDatabase();
from: http://www.androiddesignpatterns.com/2012/05/correctly-managing-your-sqlite-database.html
Approach #1: Use an Abstract Factory to Instantiate the
SQLiteOpenHelper
Declare your database helper as a static instance variable and use the
Abstract Factory pattern to guarantee the singleton property. The
sample code below should give you a good idea on how to go about
designing the DatabaseHelper class correctly.
The static factory getInstance method ensures that only one
DatabaseHelper will ever exist at any given time. If the mInstance
object has not been initialized, one will be created. If one has
already been created then it will simply be returned.
You should
not initialize your helper object using with new DatabaseHelper(context).
Instead, always use
DatabaseHelper.getInstance(context), as it guarantees that only one
database helper will exist across the entire application's lifecycle.
public static class DatabaseHelper extends SQLiteOpenHelper {
private static DatabaseHelper mInstance = null;
private static final String DATABASE_NAME = "database_name";
private static final String DATABASE_TABLE = "table_name";
private static final int DATABASE_VERSION = 1;
public static DatabaseHelper getInstance(Context ctx) {
// Use the application context, which will ensure that you
// don't accidentally leak an Activity's context.
// See this article for more information: http://bit.ly/6LRzfx
if (mInstance == null) {
mInstance = new DatabaseHelper(ctx.getApplicationContext());
}
return mInstance;
}
/**
* Constructor should be private to prevent direct instantiation.
* make call to static factory method "getInstance()" instead.
*/
private DatabaseHelper(Context ctx) {
super(ctx, DATABASE_NAME, null, DATABASE_VERSION);
}
}
The complete example of the above-accepted answer:
It may help someone.
Helper Class:
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "sample.db";
private static final int DATABASE_VERSION = 1;
private static DatabaseHelper mInstance;
private DatabaseHelper(#Nullable Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public static synchronized DatabaseHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new DatabaseHelper(context.getApplicationContext());
}
return mInstance;
}
#Override
public void onCreate(SQLiteDatabase db) {
// create table stuff
}
#Override
public void onUpgrade(SQLiteDatabase db, int i, int i1) {
// drop table stuff
onCreate(db);
}
}
Activity:
SQLiteDatabase database = DatabaseHelper.getInstance(getApplicationContext()).getWritableDatabase();
Cursor cursor = database.query("query");
if (cursor != null) {
while (cursor.moveToNext()) {
// stuff
}
cursor.close();
database.close();
}
private void method() {
Cursor cursor = query();
if (flag == false) { // WRONG: return before close()
return;
}
cursor.close();
}
Good practice should be like this:
private void method() {
Cursor cursor = null;
try {
cursor = query();
} finally {
if (cursor != null)
cursor.close(); // RIGHT: ensure resource is always recovered
}
}

Database initialization error in static method

I have database class. The class and its constructor are shown below.
public class LatLogDBAdapter {
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
}
I want to use the database in the static method. So that I declare as private static LatLogDBAdapter dbHelper;. Then when i initialize, i have problem. dbHelper = new LatLogDBAdapter(this); dbHelper = new LatLogDBAdapter(DetailMapView.this); make compile error. How can I use this in static method?
If you want to create static method that returns your dbhelper i suggest you to create normal subclass of SQLiteOpenHelper and in this class create public static method that will return new instance. This also is sounds like good reason to use design pattern Singleton
Update:
I mean I want to use this database class inside another java class.
That class has static method and use the database.
Here i create for you basic snippet of code:
public class AdapterWrapper {
private static SQLiteOpenHelper instance;
public static SQLiteOpenHelper getInstance(Context c) {
if (instance == null) {
instance = new DatabaseHelper(c);
}
return instance;
}
private static class DatabaseHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "Example";
private static final int DB_START_VERSION = 1;
public DatabaseHelper(Context cntx) {
super(cntx, DB_NAME, null, DB_START_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
// creating tables
}
#Override
public void onUpgrade(SQLiteDatabase db, int old, int new) {
/// drop an upgrading db
}
}
}

Create SQLite DB in Android library

I've seen a lot of ties between the onCreate and onOpen methods and SQLite database management in Android.
I am an iOS developer and I'm trying to "translate" (so to speak) my cocoa library so it could be used on Android. I need to create an SQLite database at runtime. I don't have an activity - since this is a library I'm creating. It seems I can't create a DB without an activity, is this correct ?
To create sqlite db, you don't basically need an activity in the library.it needs a context!!,
You can have a method in library/class which basically take a context in input/parameter and create database.
This context can be passed from application activity or service or receiver.
I don't see why you should not be able to open a database without an activity. You need to extend SQLiteOpenHelper.
public class MyDatabase {
private final DatabaseHelper databaseHelper;
private SQLiteDatabase db;
private static final String DATABASE_NAME = "com.my.db";
private static final int DATABASE_VERSION = 1;
public MyDatabase(Context context) {
databaseHelper = new DatabaseHelper(context);
}
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
//use db.execSQL to create the database
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// use db.execSQL to update (modify) the database
}
}
public SQLiteDatabase open() throws SQLException {
db = databaseHelper.getWritableDatabase();
return db;
}
}

passing context from non-activity

i yet really grasp this whole context thing we found a lot in android programming. so i tried creating a function to drop all my tables, and here's a my partial code:
public class DBAdapter {
private static class DbHelper extends SQLiteOpenHelper {
private boolean databaseCreated = false;
public DbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public void deleteTables(){
Log.d("DBAdapter","dlm drop tables pre");
this.sqlDatabase.execSQL("DROP TABLE IF EXISTS ["+TABLE_TV+"];");
this.sqlDatabase.execSQL("DROP TABLE IF EXISTS ["+TABLE_CAMERA+"];");
this.sqlDatabase.execSQL("DROP TABLE IF EXISTS ["+TABLE_GPS+"];");
}
}
}
and the part where i'm going to call the function deleteTables
public class UpdateDatabase {
public void updateTable(String table,JSONObject jsonObject){
DBAdapter db = new DBAdapter(this);
db.deleteTables();
}
}
but of course it will return an error, since DBAdapter expects a context. public class UpdateDatabase is not an activity class. Calling DbAdapter db = new DBAdapter(this) from activity class will work just find. So how do I find any fix for this problem?
thanks
You can add a constructor to UpdateDatabase that takes a Context and stores it so that it is available to be used by updateTable. Something like this:
public class UpdateDatabase {
private final Context mContext;
public UpdateDatabase(Context context){
mContext = context;
}
public void updateTable(String table,JSONObject jsonObject){
DBAdapter db = new DBAdapter(mContext);
db.deleteTables();
}
}
Now, whenever you do new UpdateDatabase() you will need to do new UpdateDatabase(..context..) instead. If you are doing this from an Activity, then you can do new UpdateDatabase(this).
hi look this code..
public class DbManager
{
// the Activity or Application that is creating an object from this class.
Context context;
CustomSQLiteOpenHelper helper;
// a reference to the database used by this application/object
protected SQLiteDatabase db;
private static DbManager INSTANCE;
// These constants are specific to the database.
protected final String DB_NAME = "yourDB";
protected final int DB_VERSION = 1;
public DbManager(Context context)
{
this.context = context;
// create or open the database
helper = new CustomSQLiteOpenHelper(context);
this.db = helper.getWritableDatabase();
}
public static DbManager getInstance(Context context){
if(INSTANCE == null)INSTANCE = new DbManager(context);
return INSTANCE;
}
public void db_Close()
{
if(helper!=null){
helper.close();
}
this.db.close();
}
private class CustomSQLiteOpenHelper extends SQLiteOpenHelper
{
public CustomSQLiteOpenHelper(Context context)
{
super(context, DB_NAME, null, DB_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db)
{
// This string is used to create the database.
// execute the query string to the database.
//db.execSQL(newTableQueryString);
Log.i("DataBaseManager", "Create Table");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
// NOTHING TO DO HERE. THIS IS THE ORIGINAL DATABASE VERSION.
// OTHERWISE, YOU WOULD SPECIFIY HOW TO UPGRADE THE DATABASE.
}
}
}
// Inherit the DbManager Class
public class DataCollection extends DbManager {
public DataCollection(Context context){
super(context);
}
public void deleteTable(String TABLE_NAME){
try {db.execSQL("DROP TABLE "+TABLE_NAME);}//.delete(TABLE_NAME, null, null);}
catch (Exception e){
Log.e("DB ERROR", e.toString());
e.printStackTrace();
}
}

Categories

Resources