How to create and pre-populate sqlite database file with Android Room? - java

I want to create the sqlite database file DatabaseName.db with few entities that should be created in path of application (/data/data/MyApplicationName/databases/DatabaseName.db) when I try to execute the snippet code bellow, however the DatabaseName.db file is not there. Why ?
MyDatabaseSample db = Room.databaseBuilder(context,
MyClass.class,
"DatabaseName.db")
.addCallback(new RoomDatabase.Callback() {
#Override
public void onCreate(#NonNull SupportSQLiteDatabase ssdb) {
super.onCreate(db);
Log.d(TAG, "Database created - populate database");
}).build();
The database is created in the path of application only if I create an instance of a entity object and insert it in database right after get the database reference db. As I want to pre-populate database just after database creation, I think just make sense do it inside onCreate method of callback, but onCreate will never be called. So, How can I create the "DatabaseName.db" file with all tables representing entities and populate the database using callback ?
OBS: I am using Room version use 1.1.0-alpha2 and compiling with SDK android API 27.

I think you need to define some Room entities before pre-populate the db that's what i have done and it works just as expected, here is some code of what i have done so far:
public class DatabaseCreator {
private static MyDatabaseSample appDatabase;
private static final Object LOCK = new Object();
public synchronized static MyDatabaseSample getDBInstance(final Context context){
if(appDatabase == null) {
synchronized (LOCK) {
if (appDatabase == null) {
RoomDatabase.Callback appDBCallback = new RoomDatabase.Callback() {
#Override
public void onCreate(#NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
try {
ReadScript.insertFromFile(context, R.raw.populate_db, db);
} catch (IOException e) {
Log.d("DB Population Error", e.toString());
}
}
};
appDatabase = Room.databaseBuilder(context,
MyDatabaseSample.class, "DatabaseName").addCallback(appDBCallback).build();
}
}
}
return appDatabase;
}
}
The code above is a singleton that uses the Callback's onCreate to pre-populate the db using a "raw resource" (To add raw resources to your project just create a folder inside your res folder like this "res/raw") that contains an sql script. To read the script i have used this code:
public class ReadScript {
public static int insertFromFile(Context context, int resourceCode, SupportSQLiteDatabase db) throws IOException {
// Reseting Counter
int result = 0;
// Open the resource
InputStream insertsStream = context.getResources().openRawResource(resourceCode);
BufferedReader insertReader = new BufferedReader(new InputStreamReader(insertsStream));
// Iterate through lines (assuming each insert has its own line and theres no other stuff)
while (insertReader.ready()) {
String insertStmt = insertReader.readLine();
if(insertStmt != null){
if(insertStmt.isEmpty()) continue;
db.execSQL(insertStmt);
result++;
Log.d("Statement #", Integer.toString(result));
}
}
insertReader.close();
// returning number of inserted rows
return result;
}
}
And then you just create the db instance by doing:
MyDatabaseSample db = DatabaseCreator.getDBInstance(getContext());
Note: You can try to create tables inside the raw script but i haven't tried it yet.
Goog luck.

Related

Can't retrieve any data from database

I have imported an existing db to my Android Studio Project. I am trying to run a search query on database and feed the results to my recycler view but it seems all I am getting from my db is null or similar.... I tried removing the WHERE arguments but didn't work. Maybe it is a silly question but this is my first real world project and I am kind of lost, I appreciate any help.
class BackgroundRunnable implements Runnable {
private String name;
public BackgroundRunnable(String name) {
this.name = name;
}
#Override
public void run() {
Log.d(TAG, "code is in the Runnable");
final Map<Integer, String> backgroundmap = new HashMap<>();
DatabaseAccess mydatabase = DatabaseAccess.getInstance(getContext());
mydatabase.open();
Cursor cursor = mydatabase.SearchbyName();
if (cursor != null && cursor.moveToFirst()) {
for (int i = 0; i < cursor.getCount(); i++) {
Log.d(TAG, "MainFragment code in cursor result:" + cursor.getString(cursor.getColumnIndex("name")));
backgroundmap.put(cursor.getInt(cursor.getColumnIndex("id")), cursor.getString(cursor.getColumnIndex("name")));
cursor.moveToNext();
}
cursor.close();
mainHandler.post(new Runnable() {
#Override
public void run() {
keyList.addAll(backgroundmap.keySet());
valueList.addAll(backgroundmap.values());
adapter.setvalues(keyList, valueList);
}
});
}
mydatabase.close();
}
}
After 2 days of pulling my hair out, I figured out an answer. In short: create the database using sqlite in the terminal or similar, don't use external .exe like DB Browser. I noticed that the database I create and imported from DB Browser appeared as empty even though a check in DB Browser would tell otherwise. I recreated the tables and values but to no avail. Then I created a new database with another name and changed my Database Helper class, worked like a charm.... –

I am unable to create SQLite Database. ERROR: java.lang.NullPointerException

Here are following my classes:
StatsObjectId.java
public class StatsObjectId extends Activity {
DBClass db;
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
db = new DBClass(this);
}
public void addObjId(String objid){
Log.e("objectid","This is the object id going to store: "+objid);
db.addObjectId(objid); //This is the line# 105
if(getObjId()){
Log.e("objectid","Successfully stored!");
}else{
Log.e("objectid","Error in storing object id!");
}
}
public boolean getObjId(){
boolean result;
try{
c = db.getObjectId();
c.moveToFirst();
String str = c.getString(c.getColumnIndex("objectid"));
Log.e("objectid","Object id returned form DB: "+str);
result = true;
}catch(CursorIndexOutOfBoundsException e){
Log.e("objectid","Cursor index out of bound");
result = false;
e.printStackTrace();
}catch(Exception e){
Log.e("objectid","Some Another Exception");
result = false;
e.printStackTrace();
}
return result;
}
ParseComServerAccessor.java
public class ParseComServerAccessor {
//I am skipping some irrelevant code
public void putStats(String authtoken, String userId, Tas statsToAdd) throws Exception {
//Again skip some code
//Here I got some HttpResponse and I need to extract an object id and save it to database
HttpResponse response = httpClient.execute(httpPost);
String responseString = EntityUtils.toString(response.getEntity());
JSONObject json = new JSONObject(responseString);
Log.e("objectid","Now Object Id is: "+json.getString("objectId") );
StatsObjectId ob = new StatsObjectId();
ob.addObjId(json.getString("objectId")); // This is the line#156
//skip some code
}
}
TasSyncAdapter.java
public class TasSyncAdapter extends AbstractThreadedSyncAdapter {
//skipped Constructor code
public void onPerformSync(Account account, Bundle extras, String authority,
ContentProviderClient provider, SyncResult syncResult) {
//skipped some code
ParseComServerAccessor parseComService = new ParseComServerAccessor();
//skipped some code again
parseComService.putStats(authToken, userObjectId, remoteTas); //This is the line# 134
//skip some code
}
}
Now finally when I run my app... this is the following Log Cat
Tag Text
objectid This is the object id going to store: 9AFysqffz7
System.err java.lang.NullPointerException
System.err at com.myapp.ds_app.StatsObjectId.addObjId(StatsObjectId.java:105)
System.err at com.myapp.ds_app.syncadapter.ParseComServerAccessor.putStats(ParseComServerAccessor.java:156)
System.err at com.myapp.ds_app.syncadapter.TasSyncAdapter.onPerformSync(TasSyncAdapter.java:134)
System.err at android.content.AbstractThreadedSyncAdapter$SyncThread.run(AbstractThreadedSyncAdapter.java:254)
DBClass.java
public class DBClass extends SQLiteOpenHelper {
private static final String DATABASE_NAME="myapp.db";
public DBClass(Context cxt){
super(cxt, DATABASE_NAME, null, 1);
}
#Override
public void onCreate(SQLiteDatabase mydatabase) {
mydatabase.execSQL("CREATE TABLE IF NOT EXISTS temp (objectid STRING)");
}
public Cursor getObjectId(){
Cursor cursor = getReadableDatabase().rawQuery("SELECT objectid FROM temp", null);
return cursor;
}
public void addObjectId(String objid){
try{
ContentValues cv = new ContentValues(1);
Log.e("objectid","In DBClass and object id: "+objid);
cv.put("objectid", objid);
Log.e("objectid","Content value contains: "+cv.toString());
getWritableDatabase().insert("temp", "objectid", cv);
}catch(NullPointerException e){
e.printStackTrace();
}
}
}
Now, I am stucked at this point!
So far, I need to save just a single value. I tried to create a file instead of saving a value in database. But again there is some exception of ContextWrapper.
I am currently interested to deal with database.
Please let me know if you guys need any other information.
I would really appreciate if any one please explain this thing. I'm android newbie and would love to learn about this problem. Thanks in advance!
StatsObjectId ob = new StatsObjectId();
You are instanciating an Activity class. You are not allowed to do that. (There should really be something in Android to tell you when you do that) Basically, the context is not initialized, because android needs to do that in order to have a functional Activity.
Plus, Android (when it creates the Activity) calls the onCreate method with a proper context. You don't (and you can't, either), therefore your db is null.
In AbstractThreadedSyncAdapter, you have a getContext method to get a proper context. Use this to initialize your database and to insert data in it, rather than passing it to the Activity object.

Android: SQLite Query Return 0 Rows Without Reload?

My application has a SQLite database to contain a list of highways. It shows them all in a list. It first tries to query the database for the roads. If the query doesn't return any, it calls another method that downloads a list from a remote server, and populates the database. After that returns, it immediately queries the database again.
That's how it should work. How it actually works is, the first query always returns nothing. It goes straight to downloading a fresh list, it inserts the list into the database, and queries again. The second query always returns the correct result. The strange thing is, I can repeat the operation without even exiting the application. Using the adb shell, I can read the SQLite3 database on the emulator. The data shown in the database is exactly as expected. But the application is behaving as though the data isn't there? Is there some behaviour I'm not aware of? Here's the code.
RoadsDataSource.java
public class RoadsDataSource {
private DataStorage data;
private static Context context;
public RoadsDataSource() {
this.data = new DataStorage(RoadsDataSource.context);
}
private List<Road> getRoads(Integer state) {
List<Road> roads = loadRoadsFromDb(state);
if (roads.isEmpty()) {
Request api = new Request(RoadsDataSource.context);
Roads apiRoads = api.fetchRoads(state);
this.data.storeRoads(apiRoads);
roads = loadRoadsFromDb(state);
}
return roads;
}
private List<Road> loadRoadsFromDb(Integer state) {
SQLiteQueryBuilder query = new SQLiteQueryBuilder();
query.setTables(Queries.ROAD_STATE_MATCHES);
Cursor results = query.query(
this.data.getWritableDatabase(),
new String[] {Tables.ROADS + "." + Tables.Roads.ID, Tables.ROADS + "." + Tables.Roads.TYPE, Tables.ROADS + "." + Tables.Roads.NUMBER},
Queries.ROADS_BY_STATE,
new String[] {state.toString()}, null, null, null
);
List<Road> roads = new ArrayList<Road>();
results.moveToFirst();
while (!results.isAfterLast()) {
roads.add(new Road(results.getInt(0), results.getString(1), results.getInt(2)));
results.moveToNext();
}
results.close();
System.out.println(roads.size());
return roads;
}
}
DataStorage.java
public class DataStorage extends SQLiteOpenHelper {
public void storeRoads(Roads roads) {
SQLiteDatabase db = this.getWritableDatabase();
for (Road road : roads.getRoads()) {
ContentValues roadRow = new ContentValues();
roadRow.put(Tables.Roads.ID, road.getId());
roadRow.put(Tables.Roads.TYPE, road.getType());
roadRow.put(Tables.Roads.NUMBER, road.getNumber());
try {
db.insertOrThrow(Tables.ROADS, null, roadRow);
} catch (SQLException e) {
}
ContentValues linkRow = new ContentValues();
linkRow.put(Tables.StatesRoads.STATE_ID, roads.getState());
linkRow.put(Tables.StatesRoads.ROAD_ID, road.getId());
try {
db.insertOrThrow(Tables.STATES_ROADS, null, linkRow);
} catch (SQLException e) {
}
}
}
}
Mo Kargas is right. Your db helper should look more like this http://code.google.com/p/android-notes/source/browse/trunk/src/com/bitsetters/android/notes/DBHelper.java?r=10
This may fix your issue though Replace
SQLiteDatabase db = this.getWritableDatabase();
with this
SQLiteDatabase db;
try {
db = dbHelper.getWritableDatabase();
} catch (SQLiteException e) {
db = dbHelper.getReadableDatabase();
}
I've had huge issues in the past with not closing the database handle - generally I do all db operations inside an SQLiteOpenHelper subclass, keeping a reference to the db, opening and closing it atomically.

How to optimize the insertion of an entry with multiple Strings and Images into a SQLite database

I defined a method to add an entry in my database helper class and insert data into database using it, but it is not working. This is my method defined in databasehelper class:
public void createchannelEntry(ChannelPoster channel) {
openDB();
ByteArrayOutputStream out = new ByteArrayOutputStream();
channel.getPoster().compress(Bitmap.CompressFormat.PNG, 100, out);
ContentValues cv = new ContentValues();
cv.put(KEY_POSTER, out.toByteArray());
cv.put(KEY_CHANNEL, channel.getChannel());
cv.put(KEY_PATH, channel.getPath());
cv.put(KEY_DBLINK, channel.getDBlink());
mDb.insert(channelS_TABLE, null, cv);
closeDB();
}
this is how I insert data
Bitmap sherlock = BitmapFactory.decodeResource(getResources(), R.drawable.sherlock);
mDB.createchannelEntry(new ChannelPoster(sherlock, "aa" ,"ll" ,"ha" ));
and I have a JavaBean for holding an entry
public class ChannelPoster {
private Bitmap poster;
private String channel;
private String path;
private String dblink;
public ChannelPoster(Bitmap pi, String c, String p, String d) {
poster = pi;
channel = c;
path = p;
dblink = d;
}
public Bitmap getPoster() { return poster; }
public String getChannel() { return channel; }
public String getPath() { return path; }
public String getDBlink() { return dblink; }
}
And because I am adding entries one by one, the program runs very slow, so it's there a faster way to insert many entries? like get all of them in one event?
I suggest not saving the images in the database, but rather saving them as files, and saving a path to them in the database (using a normal TEXT field).
If you don't want to do that, there are two things that will still greatly improve the speed of your processing:
Open and close the database only once around all your inserts
Use a transaction
Something like that:
SQLiteDatabase db = openDB();
db.beginTransaction();
try {
// Add here the loop with all your inserts
db.setTransactionSuccessful();
} finally {
db.endTransaction(); // will rollback and cancel the inserts if not marked as successful
db.close();
}
(the finally is there to make sure you close the transaction and the connection even if it somehow fails during the inserts: in this case ALL your inserts will be cancelled)

SQLite Android Problem

I am making a local high scores table using SQLite for my Android application (Java).
For some reason, the application crashes while trying to add a new high score to the table. Here is the relevant code:
private static String HIGHSCORES_TABLE_NAME = "SCORES_TABLE";
private SQLiteDatabase highScoresDB = null;
private Cursor cursor = null;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
try
{
highScoresDB = openOrCreateDatabase("ScoresDatabase", MODE_PRIVATE, null);
createTable();
lookupData();
}
catch (SQLiteException se)
{
Log.e(getClass().getSimpleName(), "Could not create or Open the database");
}
finally
{
if (highScoresDB != null)
highScoresDB.execSQL("DELETE FROM " + HIGHSCORES_TABLE_NAME);
highScoresDB.close();
}
}
private void createTable() {
highScoresDB.execSQL("CREATE TABLE IF NOT EXISTS " + HIGHSCORES_TABLE_NAME + " (SCORE INT(3));");
}
private void insertData() {
highScoresDB.execSQL("INSERT INTO " + HIGHSCORES_TABLE_NAME + " Values ("+ highscore +");");
}
private void lookupData() {
cursor = highScoresDB.rawQuery("SELECT SCORE FROM " + HIGHSCORES_TABLE_NAME, null);
if (cursor.moveToLast()) {
highscore = cursor.getInt(cursor.getColumnIndex("SCORE"));
}
cursor.close();
}
public void restart() {
insertData();
}
When I look up the high score, I only want the most recent one so I use moveToLast().
I found that "cursor.moveToLast()" does not seem to work correctly. It does move the position in the cursor, but throws an exception when you attempt to read that record.
This works:
cursor.moveToPosition(cursor.getCount()-1)
What is the exception that causes it to crash, When are you inserting a new row ? Are you opening the database before inserting a row , as Close() is being called on in the finally block of the create method.
If this is the only information you are going to store in the database , consider using Shared Preferences.
This link has a demo of how to use it -
Shared preferences demo
Instead of doing statements like you are doing use some of the provided methods that are included in the SQLite Object class:
http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html
This makes your code less error prone to SQL Typos or small errors.
Also please post your logcat.

Categories

Resources