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.... –
Related
I'm trying to create an app that only adds an entry to the database if there is no entry already at a specific time intervals and modifies the existing entry if there is already one in the database. I'm using Room.
It works, but only with a workaroud, because I have to call the add function twice before the value gets added (make the input two times before it works). And I also don't like my adding the Observer and immediately removing it afterwards. I also had to implement the workaround when instatiating the DB, with a value when it was first created.
How can I get the data from my LiveData List inside the Repository class and change it without ending up in an endless loop or how do I have to redesign my code to avoid that?
The complete code can be found on my Github account: Github repository
I would really appreciate any suggestion fix my problem and learn to design and plan my code better.
MainActivity
public void ok_clicked(View view) {
Intent intent = new Intent(this, DataActivity.class);
...
Diary addDiary = new Diary(new Date(), diaryCh.isChecked(), readingCh.isChecked(),writingCh.isChecked(),pianoCh.isChecked(),youtubeCh.isChecked());
mDiaryViewModel.insert(addDiary);
startActivity(intent);
}
DiaryViewModel
public void insert(Diary diary) {mRepositroy.add(diary);}
DiaryRepository
public class DiaryRepository {
private DiaryDao mDiaryDao;
private LiveData<List<Diary>> mEntriesToday;
DiaryRepository(Application application) {
AppDatabase db = AppDatabase.getDatabase(application);
mDiaryDao = db.diaryDao();
mEntriesToday = mDiaryDao.findEntriesByDate(Dates.getYesterdayMidnight(), Dates.getTomdayMidnight());
}
LiveData<List<Diary>> getmEntriesToday() { return mEntriesToday;}
void add(Diary diary) {
Observer<List<Diary>> observerEntriesToday = new Observer<List<Diary>>() {
#Override
public void onChanged(List<Diary> diaries) {
if (diaries != null) {
Log.e(TAG, "add: with matching entries"+ diaries.get(0) + " add: " + diary );
diaries.get(0).addAttributes(diary);
new updateDiaryAsyncTask(mDiaryDao).execute(diaries.get(0));
} else {
Log.e(TAG, "add: without matching entries"+" add: " + diary );
new insertDiaryAsyncTask(mDiaryDao).execute(diary);
}
}
};
getmEntriesToday().observeForever(observerEntriesToday);
getmEntriesToday().removeObserver(observerEntriesToday);
}
You shouldn't be using LiveData in this scenario at all. It is only a wrapper for data that will be observed from Activity/Fragment.
First you need to modify mEntriesToday to be MutableLiveData so you can update it.
In your case, you can omit using Observer for updating DB, and so something simple like:
void add(Diary diary){
if (mEntriesToday.getValue() != null) {
Log.e(TAG, "add: with matching entries"+ mEntriesToday.getValue().get(0) + " add: " + diary );
mEntriesToday.getValue().get(0).addAttributes(diary);
new updateDiaryAsyncTask(mDiaryDao).execute(mEntriesToday.getValue().get(0));
} else {
Log.e(TAG, "add: without matching entries"+" add: " + diary );
new insertDiaryAsyncTask(mDiaryDao).execute(diary);
}
}
If you need this data, outside this class, then you can use getmEntriesToday() and observe it.
You can get the value of the LiveData using the getValue() method
void add(Diary diary) {
List<Diary> diaries = mEntriesToday.getValue();
if(diaries!=null){
diaries.get(0).addAttributes(diary);
//update
}else{
//insert
}
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.
I am including a database in my Android application. I am following the guide here:
http://developer.android.com/training/basics/data-storage/databases.html
I have a "DatabaseHelper" class that extends SQLiteOpenHelper as suggested, and I have a Contract that holds the information about the table and implements 'BaseColumns'. Therein, I have a function for inserting a new row into the database:
public static void addUploadInfo(SQLiteOpenHelper dbHelper, UploadInfo info) {
// Gets the data repository in write mode
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = info.getContentValues();
// Insert the new row, returning the primary key value of the new row
long newRowId;
newRowId = db.insert(
UploadInfoTable.TABLE_NAME,
null,
values);
db.close(); // Closing database connection
info.setDatabaseId(newRowId);
}
I am using the database to store app related meta data about a file. When I create a new file, I run the above function, and a row is successfully added to the database (and the database is created successfully if needed). I can see it using:
public static List<UploadInfo> getUploadInfoList(SQLiteOpenHelper dbHelper) {
List<UploadInfo> infoList = new ArrayList<>();
SQLiteDatabase db = dbHelper.getReadableDatabase();
String allQuery = "SELECT * FROM " + UploadInfoTable.TABLE_NAME;
Cursor cursor = db.rawQuery(allQuery, null);
if (cursor.moveToFirst()) {
do {
infoList.add(new UploadInfo(cursor));
} while (cursor.moveToNext());
}
cursor.close();
db.close();
return infoList;
}
However, when the app first loads, I insert a few initial entries into the database using:
#Override
public void onResume() {
super.onResume();
DatabaseHelper dbHelper = new DatabaseHelper(getActivity());
for (UploadInfo info: uploadList) {
UploadInfoTable.addUploadInfo(dbHelper, info);
}
}
These entries are assigned a new row ID that appears to be the correct value (not -1 indicating an error). There are no errors in the log. However, they are not found when I next run getUploadInfoList.
I have also tried this alternate insert function:
public static void addUploadInfo(SQLiteOpenHelper dbHelper, UploadInfo info) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = info.getContentValues();
// Insert the new row, returning the primary key value of the new row
db.beginTransaction();
long newRowId = -1;
try {
newRowId = db.insertOrThrow(
UploadInfoTable.TABLE_NAME,
null,
values);
db.setTransactionSuccessful();
} catch (Exception e) {
e.printStackTrace();
} finally {
db.endTransaction();
}
db.close(); // Closing database connection
info.setDatabaseId(newRowId);
}
but I see the same result. In no case is info null. I always log the contents of the ContentValues. I use final variables for column names, so don't think I have an error in column name. This would show up as a row value of -1 anyway, and it doesn't.
Why would one implementation of the code insert successfully and the other not?
I suspect your code in onResume() is not successfully detecting the upgrade. Rather put all your code having to do with the upgrade in onUpgrade() instead of trying to detect an upgrade in onResume(). That should resolve the issue.
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.
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.