Room: Database calls retrieving null - android

I am attempting to call to my database from many different areas of my app, but I am having trouble saving and retrieving objects. When I inspect my data it looks like I am getting the cursor for the right columns, but it is always returning a null object even though it seems there is data in those columns.
I'm not sure what the issue is, but it may have to do with this recursive looking call into the database I found in the variable explorer (it continues this cascading for as far as I cared to explore).
To access my SQLite DB via Android Room I use a method call such as below from any relevant class (this gets called many times from various unique objects [should I be closing it?]):
#Entity(tableName = "cell")
public class LivingCell extends AsyncTask<Integer, Integer, Integer>{
....
getCellsDB.getCell(uid);}
public CellsDBHandler getCellsDB(){
if (cellsDBHandler == null)
cellsDBHandler = CellsDBHandler.getAppDatabase(MainActivity.getContext(),uid);
return cellsDBHandler;
}
Now I was under the impression that it wouldn't create a new instance of the database handler because this is what my CellsDBHandler looks like:
#Database(entities = {LivingCell.class})
public abstract class CellsDBHandler extends RoomDatabase {
private static CellsDBHandler INSTANCE;
public abstract CellDao cellDao();
public static CellsDBHandler getAppDatabase(Context context, String cityUid) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
CellsDBHandler.class,
DBPath).build();}
return INSTANCE;
}
public LivingCell getCell(String cellUid) {
return cellDao().getCellByID(cellUid);}
}
And my CellDao
//ALL DAO CALLS ARE RETURNING NULL OBJECTS BUT HAVE POPULATED TABLES
#Dao
public interface CellDao {
#Query("SELECT * FROM cell")
List<LivingCell> getAll();
#Query("SELECT uid FROM cell")
List<String> getAllUids();
#Query("SELECT * FROM cell WHERE uid LIKE (:cellUid)")
LivingCell getCellByID(String cellUid);
#Insert(onConflict = REPLACE)
void insert(LivingCell cell);
...
Perhaps my call to MainActivity is the issue though... is this at all an acceptable way to find the application context?
private static MainActivity instance;
public static Context getContext(){
return instance;
}
Incase it matters, all my UIDs are:
//form of: 1c21df2a-5b8f-4a56-ac5b-ed385ba8e4b8
uid = UUID.randomUUID().toString();

as the cellUid is a single String, not an Array or Collection, try the following
#Query("SELECT * FROM cell WHERE uid LIKE :cellUid")

Related

Data not inserting or updating after delete table in room DB Android

I'm trying to clear the database on the logout button click.
FlatDatabase class
#Database(entities = {SocietyFlatsDetailsData.class},version = 1)
public abstract class FlatDatabase extends RoomDatabase {
public static FlatDatabase instance;
public abstract FlatDao flatDao();
public static synchronized FlatDatabase getInstance(Context context){
if (instance==null){
instance = Room.databaseBuilder(context.getApplicationContext()
,FlatDatabase.class,"flat_database")
.fallbackToDestructiveMigration()
.allowMainThreadQueries()
.build();
}
return instance;
}
}
I'm clearing data by this line
FlatDatabase.getInstance(getContext()).clearAllTables();
after executing this line table data is clear successfully. but the problem is data are not inserting when I'm trying to insert after delete table data.
it might be because of schema change
any solution ??

room database,What is the difference between inMemoryDatabaseBuilder and databaseBuilder?

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.

How to call Application getDatabase in Room

I downloaded the Room BasicSample app from here:
https://github.com/googlesamples/android-architecture-components
This sample is a readonly database. There is no example to insert a single entity. I am modifying it, and struggling to figure out how to call the getDatabase so I can do a simple insert on the db on a button click -
getDatabase().wordDao().insert(...) ?
How do I get access to the singleton BasicApp and call getDatabase method, and where do I call it from?
Any help is appreciated.
single Insert
#Insert(onConflict = IGNORE)
void insert(WordEntity word);
AppDatabase.java (not sure if this insert method goes here)
private static void insert(final AppDatabase database, final WordEntity word) {
database.wordDao().insert(word);
}
BasicApp.java
public class BasicApp extends Application {
private AppExecutors mAppExecutors;
#Override
public void onCreate() {
super.onCreate();
mAppExecutors = new AppExecutors();
}
public AppDatabase getDatabase() {
return AppDatabase.getInstance(this, mAppExecutors);
} // ==> how do I get access to this?
public DataRepository getRepository() {
return DataRepository.getInstance(getDatabase());
}
}
In the case you are accessing BasicApp class from an activity or service you can just call ((BasicApp)getApplication()).getDatabase().
Depends a little on what class you are working in.
if it is an activity method (like onCreate):
BasicApp basicApp = (BasicApp) this.getApplicationContext();
AppDatabase appDatabase = basicApp.getDatabase();
//... do work here
If you only have a view (like in an onClickListener which passes a view as an arg):
BasicApp basicApp = (BasicApp) view.getContext().getApplicationContext();
AppDatabase appDatabase = basicApp.getDatabase();
//... do work here

Access SQLite database simultaneously from different threads

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.

How to extend the BaseDaoImpl class of ORMLite on Android to extend functionality

I'm wondering whether there's a way to extend the BaseDaoImpl class of ORMLite on Android. In my Android project I'm using several different Dao objects to access the different business objects. My business objects are stored in different tables and are all inherited form an BusinessObject base class which has the two members Long id; and Long objectId; where id is the real unique id of the object within the database table.
public abstract class BusinessObject{
public static final String ID_COLUMN_NAME = "_id";
public static final String OBJECT_ID_COLUMN_NAME = "object_id";
#SerializedName(value="_id")
#DatabaseField(canBeNull=false, columnName = ID_COLUMN_NAME, generatedId=true)
private int id;
#SerializedName(value="id")
#DatabaseField(canBeNull=false, columnName=OBJECT_ID_COLUMN_NAME, index=true, unique = true)
private long objectId;
}
Now I want to be able to delete business objects by id and by objectId. Deleting by id is of course already possible due to the BaseDaoImpl class. To be able to delete them also by objectId I thought about extending the BaseDaoImpl class and adding an generic method deleteByObjectId() method to it. Within the method I would delete the object using the dao's delete() method which takes a PreparedDelete statement.
public class ExtendedDaoImple<T, ID> extends BaseDaoImpl<T, ID> implements ExtendedDao<T, ID> {
protected ExtendedDaoImple(Class<T> dataClass) throws SQLException {
super(dataClass);
}
public int deleteByObjectId(long objectId) throws SQLException {
DeleteBuilder<T, ID> delBuilder = (DeleteBuilder<T, ID>) deleteBuilder();
delBuilder.where().eq(BusinessObject.OBJECT_ID_COLUMN_NAME, objectId).prepare();
return delete(delBuilder.prepare());
}
}
My problem is that I don't know how to create an instance of ExtendedDaoImpl class form the OrmLiteSqliteOpenHelper class. Normally a Dao is created by calling getDao() method of the OrmLiteSqliteOpenHelper class and passing the class of the BusinessObject the Dao should be used for. E.g.
Dao<Image, Long> imageDao = getDao(Image.class);
So is there a way to modify the OrmLiteSqliteOpenHelper class in such a way that ExtendedDaoImpl objects can be retrieved instead of a BaseDaoImpl object?
My problem is that I don't know how to create an instance of ExtendedDaoImpl class form the OrmLiteSqliteOpenHelper class...
Nicely worded question. The #DatabaseTable annotation has a field daoClass which can be used to specify the DAO class to construct.
http://ormlite.com/javadoc/ormlite-core/com/j256/ormlite/table/DatabaseTable.html#daoClass()
Here are the docs for the DaoManager.
http://ormlite.com/docs/dao-manager
Your class will need to have a constructor with ConnectionSource and Class arguments.
The solution is not well documented. Let me know if you have any ideas how I can improve the documentation.

Categories

Resources