SQLite Android Problem - java

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.

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.... –

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

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.

Azure easy table given me package info in my ListView instead of data in the Azure table

When i query the azure table for a SEEDNAME (column in my Azure table) i get null back. when i put required data in the logcat like: Log.i(TAG, "Read object with ID " + item.id + " " + item.SEEDNAME); i get the proper ID and a null for the name.
and when i add the data to a list view i get what looks like the package name.
public class Azuretbl {
public String id;
public String SEEDNAME;
public String SEEDTYPE;
public int SEED_AMOUNT;
}
This is the client table which matches table on Azure.
the Code for querying:
public void viewFromAzure(){
button_view_from_azure = (Button)findViewById(R.id.btnViewDataFromAzure);
button_view_from_azure.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
final ArrayAdapter<Azuretbl> myAdapter = new ArrayAdapter<Azuretbl>
(getApplicationContext(), android.R.layout.simple_list_item_activated_1);
azure_list_view = (ListView) findViewById(R.id.listViewAzure);
azure_list_view.setAdapter(myAdapter);
new AsyncTask<Void, Void, MobileServiceList<Azuretbl>>(){
MobileServiceTable<Azuretbl> myTestAzuretbl = mClient.getTable(Azuretbl.class);
#Override
protected MobileServiceList<Azuretbl> doInBackground(Void... params) {
MobileServiceList<Azuretbl> result;
try {
result = myTestAzuretbl.where().field("SEEDNAME").eq("Tomato").execute().get();
/*where().field("SEEDNAME").eq("tomato").*/
final MobileServiceList<Azuretbl> finalResult = result;
runOnUiThread(new Runnable() {
#Override
public void run() {
myAdapter.clear();
for (Azuretbl item : finalResult) {
Log.i(TAG, "Read object with ID " + item.id + " " + item.SEEDNAME);
System.out.println("Item is " + finalResult);
myAdapter.add(item);
}
}
});
} catch (Exception exception) {
}
return null;
}
}.execute();
}
}
);
}
and i get this in the logcat:
04-09 13:21:29.232 3029-3029/? I/JonnysMessage: Read object with ID a822b906-5f84-4345-86d2-3031247e380a null
04-09 13:21:29.232 3029-3029/? I/System.out: Item is [com.jonnyg.gardenapp.Azuretbl#537e457c, com.jonnyg.gardenapp.Azuretbl#537e4b04]
Snapshot of listview on app
Result of the listview on app
snapshot of Azure table on cloud
Azure snapshot of table
just to add i am using the new portal on azure. i have permission set for read insert etc.. to allow anonymous access. I am not using an application key do i need one?
I have figured out my problem.
On azure the easy table i had created had the field SEEDNAME as seedNAME in the area where you add a column this was visible and not visible when viewing the table on azure. After solving this the Seed name was viewing in the logcat.
I also created a custom adapter to view the data in a listview.

Java illegal state exception

I am following a tutorial online, but i am getting an illegal state exception.
Link to tutorial:
http://www.developerfeed.com/android/tutorial/building-todo-list-app-android-using-sqlite
Here is the Database class:
public class TaskerDbHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 1;
// Database Name
private static final String DATABASE_NAME = "taskerManager";
// tasks table name
private static final String TABLE_TASKS = "tasks";
// tasks Table Columns names
private static final String KEY_ID = "id";
private static final String KEY_TASKNAME = "taskName";
private static final String KEY_STATUS = "status";
public TaskerDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
String sql = "CREATE TABLE IF NOT EXISTS " + TABLE_TASKS + " ( "
+ KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + KEY_TASKNAME
+ " TEXT, " + KEY_STATUS + " INTEGER)";
db.execSQL(sql);
db.close();
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldV, int newV) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + TABLE_TASKS);
// Create tables again
onCreate(db);
}
// Adding new task
public void addTask(Task task) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_TASKNAME, task.getTaskName()); // task name
// status of task- can be 0 for not done and 1 for done
values.put(KEY_STATUS, task.getStatus());
// Inserting Row
db.insert(TABLE_TASKS, null, values);
db.close(); // Closing database connection
}
public List<Task> getAllTasks() {
List<Task> taskList = new ArrayList<Task>();
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_TASKS;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
Task task = new Task();
task.setId(cursor.getInt(0));
task.setTaskName(cursor.getString(1));
task.setStatus(cursor.getInt(2));
// Adding contact to list
taskList.add(task);
} while (cursor.moveToNext());
}
// return task list
return taskList;
}
public void updateTask(Task task) {
// updating row
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_TASKNAME, task.getTaskName());
values.put(KEY_STATUS, task.getStatus());
db.update(TABLE_TASKS, values, KEY_ID + " = ?",new String[] {String.valueOf(task.getId())});
db.close();
}
}
And here is what the log file says:
08-14 14:21:42.133: E/AndroidRuntime(10366): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.tasker/com.example.tasker.ViewTask}: java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/data/com.example.tasker/databases/taskerManager
There are two problems in your code:
A) you must not close the db in onCreate. That method is part of opening the db so the db should be open afterwards. source-code
public void onCreate(SQLiteDatabase db) {
...
db.close();
}
B) You close the database at the end of every task.
public void updateTask(Task task) {
db = get..
...
db.close();
}
But while doing that you are still using the same database via a Cursor
db = db.get..
Cursor cursor = db.rawQuery
while (cursor.moveToNext() {
updateTask();
}
db.close();
SQLiteOpenHelper will always give you the same db object since there is only one database. Closing the connection in one method while using it in another one can lead to your problem as well.
You could probably solve the task problem by using the existing db object from the outer loop or simply not closing the db in updateTask but it is in practice much better not to close the database at all.
Especially if you hand out references to Cursor. You must not close the database before the cursor is closed because Cursor can re-query it's data using the database connection it knows about. That will happen in two cases:
If your code uses cursor.requery() probably indirectly through a bad CursorAdapter.
The second case is not as common. Cursor can only see a limited windows of the current query. If you move the cursor outside of that window it will re-query the required part using the database connection as well. Typical small databases are usually much smaller than the window so there is no need to move the window and no hidden requery will happen.
Closing resources is usually a good thing. Closing the database is in most cases not. It is also no problem not doing it. SQLite makes sure nothing bad happens since every modification to the database is guaranteed by the transaction safety of SQLite.
you are closing the databse-connection at the end of each method with db.close().
So if you start another method you will always have to re-enable the connection.
with
getWritableDatabase();
you should get it done.
Or you don't close the connection at the end of every method. That totally depends on what your app is meant for.
you have not called db.close(); in
public List<Task> getAllTasks() {
.....
}
It may lead that problem because when you try to call getWritableDatabase(); in next function at that time database is already being open. so call db.close(); and close it in getAllTasks() method also.

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.

Categories

Resources