Is there a way to change what database an SQLiteOpenHelper object uses without having to force every class that uses the helper to replace their instance of the class?
The reason why I'm changing the database is because I have some live data and some offline data in two separate databases with identical table structures. I update the offline data and then swap them, allowing me to lock the offline database on big inserts.
You must use the singleton pattern to acces to your database with only one instance
it's look like
public class SingletonDemo {
private static SingletonDemo instance = null;
private SingletonDemo() { // do what you want here}
public static SingletonDemo getInstance() {
if (instance == null) {
synchronized (SingletonDemo.class) {
if (instance == null) {
instance = new SingletonDemo();
}
}
}
return instance;
}
...
// Add all the class function you need here
}
This is thread safe and can be use every where you need.
Related
It is thread safe to use single instance of database by all activities of my Applications. And if i do so, when should i close the database connection.
Please recommend the right method to use SqliteOpenHelper .
I've been using an approach I found in an online course and haven't had a slightest issue with it. Just put a synchronized keyword for your database instance so that multiple threads could manage it at the same time. This is what I am using:
synchronized static AppDatabase getInstance(Context context) {
if (instance == null) {
instance = new AppDatabase(context.getApplicationContext());
}
return (instance);
}
We can get a database throw followed two methods
/**
* Copyright:MyApplication
* Author: liyang <br>
* Date:2018/6/15 下午5:07<br>
* Desc: <br>
*/
#Database(entities = {Pet.class ,User.class}, version = 1)
public abstract class RoomDb extends RoomDatabase {
private static RoomDb INSTANCE;
private static final Object sLock = new Object();
public abstract UserDao getUserDao();
public abstract PetDao getPetDao();
public static RoomDb getInstance(Context context) {
if (INSTANCE == null) {
synchronized (sLock) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),RoomDb.class,"Sample.db").build();
}
}
}
return INSTANCE;
}
public static RoomDb getInMemoreyDatabase(Context context){
if (INSTANCE == null) {
synchronized (sLock) {
if (INSTANCE == null) {
INSTANCE = Room.inMemoryDatabaseBuilder(context.getApplicationContext(),RoomDb.class).build();
}
}
}
return INSTANCE;
}
}
But I really want to know what the difference is between them!
Does getInMemoreyDatabase run faster than Room.databaseBuilder?
inMemoryDatabaseBuilder(): The database will be created in system memory, If you kill the app (Killing your process), database will be removed and data will not be persisted. This can be used while Testing.
databaseBuilder() : The database will be created in /data/data/com.your.app and will be persisted. This you will be using it in production.
inMemoryDatabaseBuilder() will build the database on a temporary basis. The database will reside in system memory and it would be destroyed as soon as the process is killed.
databaseBuilder()
it will build the database on a permanent basis and the database would be stored in /data/data/.... folder.
databaseBuilder()
Creates a RoomDatabase.Builder for a persistent database. Once a database is built, you should keep a reference to it and re-use it.
Returns
A RoomDatabaseBuilder<T> which you can use to create the database.
inMemoryDatabaseBuilder()
Creates a RoomDatabase.Builder for an in memory database. Information stored in an in memory database disappears when the process is killed. Once a database is built, you should keep a reference to it and re-use it.
Returns
A RoomDatabaseBuilder<T> which you can use to create the database.
I want to get a reference to my database in one activity, and pass the referred database variable to another Activity through an intent. Is there any way I can do this?
You have to make a method in your Sqlite class to get Singleton object of that class :
public static synchronized SQLiteDatabaseHandler getInstance(Context mContext) {
if (instance == null) {
instance = new SQLiteDatabaseHandler(mContext);
}
return instance;
}
You can get Object of this class in any of your classes (no need to
pass SqliteDatabaseHandler Object to another class) :
SQLiteDatabaseHandler.getInstance(mContext);
In my application, I am using a single instance of the Helper class which means that I have only one database connection.
public static MyHelper getInstance(Context context) {
if (instance == null) {
synchronized (MyHelper.class) {
if (instance == null) {
instance = new MyHelper(context);
}
}
}
return instance;
}
And as I am using only one connection, all my operations to the database will be serialized. It means that even if I am using multiple threads there is no need for me to take care of synchronization. It will be taken care by Sqlite. But strangely sometimes I am getting the exception that the database is locked. So what can be the reason for this exception ? How can this exception be avoided ?
Here is my problem. My app starts several threads, each for a particular object to be updated. The update of the object happens with a query to a single database. There is a single database and a single OpenHelper. The behavior of my app suggests me that the calls to the database are non simultaneous as well as I would like. How can I access the same database from different threads simultaneously? If the data for each object are in different tables is more efficient to split the database in several databases, one for each object?
public class SomethingToBeUpdated implements Runnable {
private SQLiteDatabase db;
#Override
public void run() {
db.rawQuery( ... bla bla
}
}
public class MainActivity extends Activity {
private SomethingToBeUpdated[] list = bla bla...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
for( SomethingToBeUpdated x : list ) {
new Thread(x).start();
}
}
}
For the sake of accessing the database in various threads you need to have a Database manager which keeps an object of your database class and pass it to any thread that needs it. In android you cannot access database simultaneously in several threads with different objects. It may just block your UI (the problem i was facing a few days ago).
So to overcome this problem you can use the the database manager i used which is defined as follows:
public class DatabaseManager {
private AtomicInteger mOpenCounter = new AtomicInteger();
private static DatabaseManager instance;
private static SQLiteOpenHelper mDatabaseHelper;
private SQLiteDatabase mDatabase;
public static synchronized void initializeInstance(SQLiteOpenHelper helper) {
if (instance == null) {
instance = new DatabaseManager();
mDatabaseHelper = helper;
}
}
public static synchronized DatabaseManager getInstance() {
if (instance == null) {
throw new IllegalStateException(DatabaseManager.class.getSimpleName() +
" is not initialized, call initializeInstance(..) method first.");
}
return instance;
}
public synchronized SQLiteDatabase openDatabase() {
if(mOpenCounter.incrementAndGet() == 1) {
mDatabase = mDatabaseHelper.getWritableDatabase();
}
return mDatabase;
}
public synchronized void closeDatabase() {
if(mOpenCounter.decrementAndGet() == 0) {
mDatabase.close();
}
}
}
Then you initialize it once like this:
DatabaseManager.initializeInstance(new ChatSQL(c));
And then you can get the database object wherever you want with this syntax:
SQLiteDatabase db = DatabaseManager.getInstance().openDatabase(); //in your methods which are querying the database
With this method your database is now thread safe. Hope this helps.
If the data for each object are in different tables is more efficient to split the database in several databases, one for each object?
No it is not efficient. It has a lot of overheads to define, access, make object and query different databases. And what if you want to join tables? you just cannot.