04-11 05:05:17.837: W/SQLiteConnectionPool(6454): A SQLiteConnection object for database Please fix your application to end transactions in progress properly and to close the database when it is no longer needed.
this is an error return by my logcat ive searched for the possible solution for this error in here andhere saying you should close database but i have this code
#Override
protected void onPause() {
super.onPause();
if (db.isOpen()) {
db.close();
}
}
on all my ativity so im wondering why i get this error
public class DatabaseHelper extends SQLiteOpenHelper {
private static DatabaseHelper sInstance;
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 context) {
// 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 (sInstance == null) {
sInstance = new DatabaseHelper(context.getApplicationContext());
}
return sInstance;
}
/**
* Constructor should be private to prevent direct instantiation.
* make call to static factory method "getInstance()" instead.
*/
private DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
}
im currently doing the same thing im doing this tutorial if you want to try it you can you can find it here
Related
I am trying to better understand what it means to open an Sqlite database on a background thread in Android. Right now I am using a static/singleton pattern for my database via my class DatabaseHelper, so I only need to open it once, but I want to open it using good practice and understand why I shouldn't open it directly from within my Activity directly (or within the helper's constructor, for example).
My class:
public class DatabaseHelper extends SQLiteOpenHelper {
private static volatile SQLiteDatabase mDatabase;
private static DatabaseHelper mInstance = null;
private static Context mContext;
// ...
public static synchronized DatabaseHelper getInstance(Context context) {
/**
* use the application context as suggested by CommonsWare.
* this will ensure that you don't accidentally leak an Activity's
* context (see this article for more information:
* http://android-developers.blogspot.nl/2009/01/avoiding-memory-leaks.html)
*/
if (mInstance == null) {
mInstance = new DatabaseHelper(context.getApplicationContext());
}
return mInstance;
}
private DatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
mContext = context;
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DB_CREATE_SOME_TABLE); //some SQL expression
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(DB_ALTER);
}
public void open() throws SQLException {
mDatabase = getWritableDatabase();
}
public void close() {
mDatabase.close();
}
public boolean isOpen() {
return mDatabase.isOpen();
}
//below this would be various CRUD functions operating on mDatabase
// ...
// ...
}
Is it correct to say that you should do something like this:
DatabaseHelper mDatabaseHelper = DatabaseHelper.getInstance(this);
Thread thread = new Thread("OpenDbThread") {
public void run(){
mDatabaseHelper.open();
}
};
thread.start();
inside an Activity somewhere?
You're correct that the code you wrote would open the database on a background thread. However, you wouldn't actually the database was opened until thread.isAlive() returned false (or mDatabase.isOpen() returned true). Alternatively, you could make your Activity listen for a callback from your Thread.
I have two database to support two languages for my application.
I want to change database when I change language from settings.
Is it possible?? How can i do this?
It should be possible quite easily when you provide a string resource with the name of the database:
In /res/values/strings.xml put a line like this:
<string name="db_name">database</string>
In /res/values-de/strings.xml put that line:
<string name="db_name">database_de</string>
And in your DBHelper class use the database name of the strings file currently active according to language settings:
public class DBHelper extends SQLiteOpenHelper {
private final static int DB_VERSION = 1;
private static DBHelper sInstance;
/**
* Provides access to DBHelper singleton.
* #param context
* #return
*/
public static DBHelper getInstance(Context context) {
// 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 (sInstance == null) {
sInstance = new DBHelper(context.getApplicationContext());
}
return sInstance;
}
/**
* Constructor should be private to prevent direct instantiation.
* make call to static factory method "getInstance()" instead.
*/
private DBHelper(Context context) {
// here comes the magic:
String dbName = context.getString(R.string.db_name);
super(context, db_name, null, 1);
}
#Override
public void onCreate(SQLiteDatabase db) {
// ...
}
// ...
}
using Ridcully solution, you will need to add only the database name part,
all you need to add is the class you extend.
this example from the library you mentioned:
public class MyDatabase extends SQLiteAssetHelper {
private static final int DATABASE_VERSION = 1;
public MyDatabase(Context context) {
// here comes the magic:
String dbName = context.getString(R.string.db_name);
super(context, dbName , null, DATABASE_VERSION);
}
}
The other database class can be:
public class MyDatabase2 extends SQLiteAssetHelper {
private static final int DATABASE_VERSION = 1;
public MyDatabase(Context context) {
// here comes the magic:
String dbName = context.getString(R.string.db_name_2);
super(context, dbName , null, DATABASE_VERSION);
}
}
NOTE: to use SQLiteAssetHelper, u need to create the database yourself, and put in the assets/databases folder.
you can create sqlite database with this app Sqlitebrowser
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
}
}
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
}
}
}
I know there are similar forum threads to this one, but I've read them and tried the methods for solving the problem but it doesn't seem to do it.
I get the:
close() was never explicity called on database /data/data...
application did not close the database or cursor that was opened...
My error does not occur directly, it happens after awhile, when I've gone back and forth between the two activities.
I use two activities which both need a connection to the database. My idea was for the first activity to close the database before the other activity starts. Here is my code:
#Override
public void onCreate(Bundle savedInstance) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
movies = new MoviesData(this);
cursor = getTitles();
showTitles(cursor);
}
#Override
public void onPause() {
movies.close();
super.onPause();
}
#Override
public void onResume() {
movies = new MoviesData(this);
super.onResume();
}
This is my first activity, the second one is pretty much alike and is started upon a buttonpress. The MoviesData class is just an empty SQLiteOpenHelper class found below.
public class MoviesData extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "movies.db";
private static final int DATABASE_VERSION = 1;
public MoviesData(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
}
I now know when the error is displayed. If I quit the application and then open it again and try to do something the error is showing. I've tried to close the database in "onDestroy()" but that doesn't help either...
//
#Override
public void onPause() {
super.onPause();
movies.close();
cursor.close();
}
// no need to write this code
#Override
public void onResume() {
movies = new MoviesData(this);
super.onResume();
}
I made it work now!
I just added this to my SQLiteOpenHelper class.
public class MoviesData extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "movies.db";
private static final int DATABASE_VERSION = 1;
private static MoviesData movies;
private MoviesData(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public static MoviesData getInstance(Context context) {
if (movies == null) {
movies = new MoviesData(context);
}
return movies;
}
}