I have problem with my insert method while testing it by JUnit Android Test and no enrty is saved in the database :
public long save(TAV t) {
ContentValues v = new ContentValues();
v.put(TAV_TITRE, t.getTitle());
v.put(TAV_DATE, t.getDate());
v.put(TAV_DESCRIPTION, t.getDescription());
return db.insert(TAV_TABLE, null, v);
}
//this is the JUnit Test Method
public void testAddition() {
setUp();
TAV t = new TAV("titre", "date", "decsritpion");
m.open();
m.save(t);
Log.i(tag, "insertion");
testShowAll();
}
HELP PLEASE !!!
In your save() method, make sure you make an instance of your databse,something like SQLiteDatabase db = this.getWritableDatabase();.And remove return from return db.insert(TAV_TABLE, null, v); i.e use
public void save(TAV t) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues v = new ContentValues();
v.put(TAV_TITRE, t.getTitle());
v.put(TAV_DATE, t.getDate());
v.put(TAV_DESCRIPTION, t.getDescription());
db.insert(TAV_TABLE, null, v);
}
From the SQLiteDatabase Documents
public long insert (String table, String nullColumnHack, ContentValues values) Returns
the row ID of the newly inserted row, or -1 if an error occurred
So if your purpose is just to add a row into your database then your method need not return anything.So you can just make return type of your method void and use db.insert inside.
Related
I try to include transactions in my application because writing in database is very slow and I saw here and here that transactions are a solution but they are still very confusing to me.
I have Schedule objects that contains an object LineStation, and I want to write them in database using transactions.
Here, the method addSchedules in my class ScheduleDAO, that writes all schedules in database. It contains only one transaction.
public void addSchedules(ArrayList<Schedule> schedulesList) {
SQLiteDatabase db = this.dh.getWritableDatabase();
db.beginTransactionNonExclusive();
for (Schedule schedule : schedulesList) {
ContentValues values = new ContentValues();
// insert linestation
LineStationDAO.getLineStationDAO().addLineStation(schedule.getLineStation());
values.put(/*...*/);
/* ... */
db.insert(DatabaseHandler.TABLE_SCHEDULE, null, values);
}
db.setTransactionSuccessful();
db.endTransaction();
db.close();
}
And this is, the method addLineStation in my class LineStationDAO that saves the object LineStation given. It's called by addSchedules and doesn't contain transaction because it is "nested" in the addSchedules transaction.
public void addLineStation(LineStation lineStation) {
SQLiteDatabase db = this.dh.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(/*...*/);
/* ... */
db.insert(DatabaseHandler.TABLE_LINE_STATION, null, values); // database is locked (code 5)
db.close();
}
The LineStation insert implies an SQLiteDatabaseLockedException (database is locked -code 5).
What I have done wrong, please? Thanks.
The problem is that a database transaction cannot exist across multiple database connections. In the addLineStation method, you are opening a second database connection, when you should be using the one created in addSchedules.
You need to pass the SQLiteDatabase db object down to the addLineStation method like this:
LineStationDAO.getLineStationDAO().addLineStation(db, schedule.getLineStation());
and change this:
public void addLineStation(SQLiteDatabase db, LineStation lineStation) {
ContentValues values = new ContentValues();
values.put(/*...*/);
/* ... */
db.insert(DatabaseHandler.TABLE_LINE_STATION, null, values); // database is no longer locked (code 5)
}
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.
Basically, I have a Local DB file called DBhelper in which i have this function
public void addWallpost(Wall accountwallpost) {
Log.d("addWallPost", accountwallpost.toString());
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_WALL_ID, accountwallpost.wallID);
values.put(KEY_WALL_POSTER, (accountwallpost.poster).toString());
values.put(KEY_WALL_POST, accountwallpost.wallContent);
values.put(KEY_WALL_POSTER_COMPANY_ANNOUNCE_TITLE, accountwallpost.announcementTitle);
values.put(KEY_WALL_POSTER_COMPANY_ANNOUNCE_LINK, accountwallpost.announcementLink);
values.put(KEY_WALL_TARGET_NAME, (accountwallpost.target).toString());
values.put(KEY_WALL_NUMBER_LIKES, accountwallpost.userLike);
values.put(KEY_WALL_GAP, accountwallpost.gap);
db.insert(TABLE_ACCOUNTWALLPOST, null, values);
db.close();
}
I have this other file which loads from the server database all the values of the Wallpost table
public List<Wall> loadHome(long accountID, int start, int numberOfResult) throws Exception {
this.setFunction("LOAD_HOME");
this.addAccountID(accountID);
this.addParameter("start", start);
this.addParameter("numberOfResult", numberOfResult);
return WallParser.parseWallList(this.postJSON().getJSONArray("wallpost"));
}
What i need help in is how do i save the data from the server database to the Local DB?
I tried adding the code
DBHelper.get(context).addWallpost(accountwallpost);
But i dont know how to get a row from the server database since the data is gotten as a List.
Any help is appreciated.
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.
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.