hope your doing fine, i have a problem with my sqliteDatabase, i am Holding my Database in a Service always running in background, and i get it like this :
public static SQLiteDatabase getPostsDatabase(){
if(PostsDatabase == null){
if(getAnAvailableContext() == null){ return null; }
PostsDbHelper = new PostsDBHelper(getAnAvailableContext());
PostsDatabase = PostsDbHelper.getWritableDatabase();
}
return PostsDatabase;
}
public static Context getAnAvailableContext(){
if(MainActivity.mainActivityInstance != null){
return MainActivity.mainActivityInstance;
}else if(getInstance() != null){
return getInstance();
}else{
return LMApplication.getInstance().getApplicationContext();
}
}
it works fine for first timer, but when the applications is restored from saved instance , and context instances change , my data on the database has changed and are wrong, my question is Is the Context Change really the Problem ? and if its so , how can i have a presistent context ? i tried to use application context for creating it but no improvement !
Related
I have created ContentProvider which creates one Database on application launching.
Now In that application, I am doing process of deleting database when user logout from app.
After that when I come again to login, the ContentProvider cant call onCreate() of overrided class.
Is there any way to recreate database using ContentProvider?
I found solution as,
First of all I referred Refresh/Reload database reference in custom ContentProvider after restore but not satisfied with answer because its just for closing database.
So I have created my answer as below:
DBHelper.java
/**
* Delete database
*/
public static void reCreateDatabase(Context mContext) {
ContentResolver resolver = mContext.getContentResolver();
ContentProviderClient client = resolver.acquireContentProviderClient(KOOPSContentProvider.AUTHORITY);
assert client != null;
KOOPSContentProvider provider = (KOOPSContentProvider) client.getLocalContentProvider();
assert provider != null;
provider.resetDatabase();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
client.close();
else
client.release();
LOGD("Database Deleted...");
}
public void removeDatabase(Context mContext) {
mContext.deleteDatabase(DATABASE_NAME);
LOGD("Database Deleted...");
}
KOOPSContentProvider.java
public void resetDatabase() {
if(dbHelper != null) {
dbHelper.removeDatabase(getContext());
dbHelper = new DbHelper(getContext());
} else {
LOGD("Database NULL");
}
}
USE As:
DbHelper.reCreateDatabase(mContext);
Thank you :) :)
I am developing an android app. In that app, I have to add and get the data from my database constantly.
I using three separate threads to do so. I do not think I have a thread problem as in my DDMS I can monitor the threads opening But what I think, I am failing to grasp is the Database instances.
For example,
I have a method which shall construct a filename which is made up of the value in a cell of one table + "_" + value of a cell in another table. So, I have this method which calling two other methods each with the task to go to the database and get that value.
Problem is that I am not sure how I should create an instance.Below you can see that for each method I have created a separate instance of the same database and then closed that.
In this AsyncTaskRunner class I have many methods of the same as below which are doing their own task, but open a different instance name for the same database each time.
This seems very wrong.I would imagine that as soon as the class opens I could open ONE single instance of the database and then not close it until Destroy() so that all methods can do their thing.
What can I do better?
Here is my code :
public String evaluateATable(String filenamePrefix){
SQLDatabase getATableData = new SQLDatabase(mContext);
getATableData.open();
String aRowId = SQLDatabase.evalATable(filenamePrefix);
getATableData.close();
if(aRowId != null){
return aRowId;
}
return null;
}
public String evaluateLTable(String filenamePrefix){
SQLDatabase getLtabledata = new SQLDatabase(mContext);
getLtabledata.open();
String lRowId = SQLDatabase.evalLTable(filenamePrefix);
getLtabledata.close();
if(lRowId != null){
return lRowId;
}
return null;
}
you can do one thing ,you have to declare SQLDatabase and create instance of it once, and then use that in all method
just like below
Public class test extends Activity {
SQLDatabase getATableData;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SQLDatabase getATableData = new SQLDatabase(this);
}
public String evaluateATable(String filenamePrefix){
getATableData.open();
String aRowId = SQLDatabase.evalATable(filenamePrefix);
getATableData.close();
if(aRowId != null){
return aRowId;
}
return null;
}
public String evaluateLTable(String filenamePrefix){
getLtabledata.open();
String lRowId = SQLDatabase.evalLTable(filenamePrefix);
getLtabledata.close();
if(lRowId != null){
return lRowId;
}
return null;
}
Is it a good practice to open and close the database for every database transaction operation? let me clear you more.
I have two methods like
public SQLiteDatabase getDatabase() {
if (database == null || !database.isOpen()) {
database = getWritableDatabase();
}
return database;
}
public void closeDatabase() {
if (database != null && database.isOpen()) {
database.close();
}
}
so every time, when I am updating/inserting or deleting, I am opening the database and closing it.
public void insert(...) {
getDatabase().insert(...);
closeDatabase();
}
public void update(...) {
getDatabase().update(...);
closeDatabase();
}
public void delete(...) {
getDatabase().delete(...);
closeDatabase();
}
remember that all these methods are inside a class DatabaseHelper which is extending SQLiteOpenHelper and there is a global variable private SQLiteDatabase database
and I will perform these operations(insert/update/delete) more frequently.
So my question is Is it a good practice to open and close database for every transaction? if not, what is the good way? Where and When I have to close my database?
Opening and closing the database every time may (un-intentionally) run into problem such as Trying to open an already closed database.
Hence, I would suggest is to have a Singleton for the creating the database object, so that every time you make a call to database = getWritableDatabase(); you refer to the same object.
Consider closing this in onDestroy() method, so that as and when the App closes database is closed too.
private static AllItemsDB db; //AllItemsDB is my database class
public static AllItemsDB getDb() {
if (db == null) {
Log.d("","Issue here");
db = new AllItemsDB(app);
Log.d("","Issue here not");
}
return db;
}
since this is a static method, I can do AllItemsDB.myCRUD_methods and it will return me the same oblect every time and easy to access as well. :)
Help.
There are a few Android APIs (after donut and before honeycomb) if Im not mistaken, where Google have enabled the AsyncTasks to run paralelly aiming for faster execution. Then lots of devs made mistakes when reaching out to the same database using multiple AsyncTasks, and since Android 3.0 AsyncTasks are running serially by default.
I am suffering this problem now when testing my app on an Android 2.3.4 device with my SQLite
First, Im getting categories from the server, I open DB, insert them close DB.
Second I get the subcategories from the server, open DB, insert them into DB, close DB
Third I get user items from the server, open DB, insert items, then close DB
Im taking good care to ensure that one starts after another, but in every 8-10 iterations something somewhere slows down and overlaps with another procedure right in the moment where a task is opening the db, another task closes it right after, and the first task starts trying to write to a closed db....
What do I do? I want clean, reliable separation, sequential execution and I dont want to start the asynctasks from the previous asynctask's onPostExecute, because these three will not always run in a row
I read an article yesterday that you CANT do it on android 2.x
Shall I try to open the DB and DBHelper before ALL of the operations and close the DB afterwards?
EDIT: Usually I get the error here (at Begin transaction):
(The error says that the DB is closed)
#Override
protected Void doInBackground(Void... arg0) {
// dbTools.close();
try {
if (database == null) {
database = dbTools.getWritableDatabase();
}
} catch (Exception e) {
e.printStackTrace();
}
ContentValues values = new ContentValues();
database.beginTransaction();
try {
// Iterating all UserItem objects from the LinkedHashSet and getting their info
for (UserItem userItem : userItems) {
// Inserting values for the database to insert in a new record
values.put(C.DBColumns.ITEM_ID, userItem.getItemId());
values.put(C.DBColumns.ITEM_NAME, userItem.getItemName());
// database.insertWithOnConflict(C.DBTables.ITEMS, null, values, SQLiteDatabase.CONFLICT_REPLACE);
database.insert(C.DBTables.ITEMS, null, values);
} // End of For loop
database.setTransactionSuccessful();
} finally {
database.endTransaction();
}
// Closing all cursors, databases and database helpers properly because not closing them can spring lots of trouble.
if (database != null && database.isOpen()) {
try {
database.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
} // End of doInBackground
And this is my DBTOOLS CLASS:
public class DBTools extends SQLiteOpenHelper {
// Its a good practice for DBTools to be a singleton. Do not instantiate it with "new DBTools(context)" but with
// DBTools.getInstance(context) instead
private static DBTools sInstance;
public static DBTools getInstance(Context context) {
if (sInstance == null) {
sInstance = new DBTools(context);
}
return sInstance;
}
public DBTools(Context context) {
super(context, C.Preferences.LOCAL_SQLITE_DATABASE_NAME, null, 1);
}
public void onCreate(SQLiteDatabase database) {
database.execSQL(SQLQueries.tableCategoriesCreate);
database.execSQL(SQLQueries.tableSubcategoriesCreate);
database.execSQL(SQLQueries.tableItemsCreate);
}
public void onOpen(SQLiteDatabase database) {
database.execSQL(SQLQueries.tableCategoriesCreate);
database.execSQL(SQLQueries.tableSubcategoriesCreate);
database.execSQL(SQLQueries.tableItemsCreate);
}
public void onUpgrade(SQLiteDatabase database, int version_old, int current_version) {
database.execSQL(SQLQueries.tableCategoriesDrop);
database.execSQL(SQLQueries.tableSubcategoriesDrop);
database.execSQL(SQLQueries.tableItemsDrop);
onCreate(database);
}
} // End of Class
Since you can't call from onPostExecute, I would say you have two options, one would be to move your open close calls to the beginning and end of your activity or service.
Option two would be to setup a reference counter in your DB and DBHelper where you track the number of times open has been called, and then decrement that count when close is called. That way you can perform close only when the count is 0. One thing to remember when taking this approach is that you should probably have a method that will force the db to close that you call when you are sure your other connections are done. This shouldn't be necessary but will be a failsafe to ensure the db gets closed if something goes wrong.
Edit: You would have to make DBTools a singleton for it to work, but it's not equivalent. Here's a quick example.
public class DBTools {
private static DBTools instance;
private static int openCount;
public DBTools getInstance() {
if (instance == null) {
instance = new DBTools();
}
return instance;
}
private DBTools() {
openCount = 0;
}
public void open() {
openCount++;
//Do open
}
public close() {
openCount--;
if (openCount == 0) {
//Do close
}
public void forceDBClose() {
//Do close
}
}
I am also a newbee in android. I was having a problem like this too.
To overcome this, i used Singleton class.
I created one instance of the DBHelper class and used it in all my asynctasks.
So, until the DB is closed, all the asynctasks access the initialised DB object.
If there is no object in the memory, the async tasks, instantiates it and use it then.
I have created a databaseprovider class which uses single instance of db object. Object is created in main activity and closed onDestroy method. This seems ok (but get some errors such as: db already closed or db is not open on some users devices that I cannot simulate).
I want to add a service to the application for the content download and this service can run with scheduler which make me think about single instance of db object will not work. Should I use another object for the service, will it result consistency problems? Can you kindly advice what would be the best way?
Databaseprovider class exm:
public class DatabaseProvider {
private static DatabaseHelper helperWriter;
public static SQLiteDatabase db_global;
public DatabaseProvider(Context c) {
helperWriter = DatabaseHelper.getHelper(c, true);
}
private static SQLiteDatabase getDB() {
if(db_global == null)
db_global = helperWriter.getWritableDatabase();
else if(!db_global.isOpen()) {
try {
db_global.close();
}
catch(Exception ex) {
ex.printStackTrace();
}
db_global = helperWriter.getWritableDatabase();
}
return db_global;
}
public String GetVersion() {
SQLiteDatabase db = getDB();
Cursor c = db.query(DatabaseHelper.PARAMETER_TABLE_NAME, new String[] {"VALUE"}, "KEY='Version'", null, null,null,null);
String version = "";
if(c.moveToNext())
{
version = c.getString(0);
}
else
version = "0";
c.close();
return version;
}
public long UpdateVersion(String value) {
ContentValues initialValues = new ContentValues();
initialValues.put(DatabaseHelper.PARAMETER_COLUMN_VALUE, value);
SQLiteDatabase db = getDB();
long r = db.update(DatabaseHelper.PARAMETER_TABLE_NAME, initialValues, "KEY='Version'", null);
if(r <= 0)
r = helperWriter.AddParameter(db, "Version", value);
//db.close();
return r;
}
public void CloseDB() {
if (db_global != null)
db_global.close();
db_global = null;
helperWriter.close();
}
}
Not sure if this will help, but...
you can't rely on onDestroy() in case the app crashes. Android may also keep your app in RAM, even if you exit it. Also, your main activity may get destroyed while the app is getting used if you are on a subactivity. It can also get recreated.
Sometimes it's better to have calls that open the DB, does stuff to it, and then closes it within the same function. If you are using a service, it may actually help things. I also am not sure if you should have a situation where a DB can be opened and/or accessed from a variety to different places at once without some management code
I see a couple questions:
A)
(but get some errors such as: db already closed or db is not open on some users devices that I cannot simulate).
...
Start an activity, then update content and some db operations in AsyncTask. While update is in progress go back and start the same activity again.
To work around these errors have you considered using a [Loader][1]? It's a callback based framework around ContentProviders.
B)
add a service to the application for the content download and this service can run with scheduler which make me think about single instance of db object will not work. Should I use another object for the service, will it result consistency problems?
This post by #commonsware from this website, suggests not to use Service for long running tasks. Instead the AlarmManager is suggested. I've only worked with short running services (for audio IO) myself.