SQLiteOpenHelper .update() does not persist - java

I have a sortid row in my table to have a custom order of my data.
in my SQLiteOpenHelper class, i have a drop() function which calls .update(), and in loadCities() the rows are queried but i get the old sortId.
here are parts of my code:
public class TimesHelper extends SQLiteOpenHelper {
private static final String TABLE_CREATE = "CREATE TABLE " + TABLE_NAME
+ " (" + KEY__ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ [...] + KEY_SORTID + " INTEGER);";
private SQLiteDatabase mDB;
private Handler mHandler;
public SQLiteDatabase getDB() {
if (mDB == null) {
mDB = getWritableDatabase();
} else {
mHandler.removeCallbacks(mClose);
}
//useful, but i am not sure wether this is good practise, please comment...
mHandler.postDelayed(mClose, 500);
return mDB;
}
private Runnable mClose = new Runnable() {
#Override
public void run() {
if (mDB != null) {
mDB.close();
mDB = null;
}
}
};
public void drop(int from, int to) {
List<Integer> keys = new ArrayList<Integer>(Times.Cities.keySet());
Integer key = keys.get(from);
keys.remove(key);
keys.add(to, key);
getDB().beginTransaction();
for (Integer i : keys) {
ContentValues val = new ContentValues();
val.put(KEY_SORTID, keys.indexOf(i));
getDB().update(TABLE_NAME, val,
KEY__ID + "=" + i, null);//returning 1
}
getDB().endTransaction();
loadCities();
}
public void loadCities() {
HashMap<Integer, Times> cities = Times.Cities;
cities.clear();
Cursor c = getDB().query(TABLE_NAME, null, null, null, null, null,
KEY_SORTID);
c.moveToFirst();
if (c.isAfterLast()) {
c.close();
return;
}
do {
int s = c.getInt(c.getColumnIndex(KEY_SORTID));
int id = c.getInt(c.getColumnIndex(KEY__ID));
//here i still have the old values...
//do whatever
}
} while (c.moveToNext());
c.close();
}
}
i tried anything, but without success...
Metin Kale

You forgot setTransactionSuccessful(). Calling endTransaction() without it rolls back any changes done within the transaction.
The preferred, exception-safe pattern to handle transactions is
beginTransaction();
try {
// db operations...
setTransactionSuccessful(); // didn't throw so far
} finally {
endTransaction(); // rollback or commit
}

Related

Singleton Instance returns null

In my application, I use the users password as the encryption key for encryption media. I am encrypting media using PBEWithMD5AndDES and this works fine with a password stored in shared preferences. Now to achieve a level of security I am removing the password from shared preferences and using a singleton that is only kept alive during the app session (as the app logs out automatically requiring entry of the password). Below is my singleton:
public class Credentials {
private static Credentials dataObject = null;
private Credentials() {
// left blank intentionally
}
public static Credentials getInstance() {
if (dataObject == null)
dataObject = new Credentials();
return dataObject;
}
private char[] user_password;
public char[] getUser_password() {
return user_password;
}
public void setUser_password(char[] user_password) {
this.user_password = user_password;
}
}
The password is zeroed out from memory if the app logs out, or is log out by the user or gets destroyed. However at times I am getting a null pointer when trying to retrieve the password.
char[] pswd = Credentials.getInstance().getUser_password();
What could be causing this? is there any other method I can use except a singleton?
Alternatively, you can store the password using built-in Sqlite db, though I'd still recommend you save it encrypted for max protection. You can do this in 4 steps:
2) Create an entity object to store the password:
public class Password {
int password_id; // will be auto-increamted
String password;
public Password(int password_id, String password) {
this.password_id = password_id;
this.password = password;
}
// getter/setters ...
}
2) Create an Sqlite utility object:
public class SQLiteDBAdapter {
protected static final String DATABASE_NAME = "mydb";
protected static final int DATABASE_VERSION = 1;
protected Context context;
protected static DatabaseHelper mDbHelper;
public static final String TABLE_PASSWORD = "tbl_password";
// columns
public static final String PASSWORD_ID = "_id";
public static final String PASSWORD = "password";
// create table string
private static final String CREATE_TABLE_PASSWORD =
"CREATE TABLE if not exists " + TABLE_PASSWORD + " ( " +
PASSWORD_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
PASSWORD + " TEXT NOT NULL);";
public SQLiteDBAdapter(Context context) {
context = context.getApplicationContext();
}
public SQLiteDatabase openDb() {
if (mDbHelper == null) {
mDbHelper = new DatabaseHelper(mContext);
}
return mDbHelper.getWritableDatabase();
}
protected static class DatabaseHelper extends SQLiteOpenHelper {
// -------------------------------------------------------------------------------------------
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// -------------------------------------------------------------------------------------------
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE_PASSWORD);
}
// -------------------------------------------------------------------------------------------
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database from version " + oldVersion + " to " +
newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS routes");
onCreate(db);
}
}
}
3) Extend an Sqlite object to manipulate the table (CRUD operations):
public class PasswordDbAdapter extends SQLiteDBAdapter {
private SQLiteDatabase db;
// these are column corresponding indices
public static final int INDEX_PASSWORD_ID = 0; // an auto-increment
public static final int INDEX_PASSWORD = 1;
public PasswordDbAdapter(Context context) {
super(context);
}
public void addPassword(String password) {
db = openDb();
ContentValues values = new ContentValues();
values.put(PASSWORD, password);
db.insert(TABLE_PASSWORD, null, values);
}
public void updatePassword(String password) {
db = openDb();
ContentValues values = new ContentValues();
values.put(PASSWORD, password);
db.update(TABLE_PASSWORD, values, null);
}
public void deletePassword() {
db = openDb();
db.delete(TABLE_PASSWORD, null, null);
}
public boolean isEmpty() {
db = openDb();
boolean empty = true;
Cursor cur = db.rawQuery("SELECT COUNT(*) FROM " + TABLE_PASSWORD, null);
if (cur != null && cur.moveToFirst()) {
empty = (cur.getInt (0) == 0);
}
cur.close();
return empty;
}
public Password fetchPassword() { // ok because there's only one password record
db = openDb();
Cursor cursor = db.query(TABLE_PASSWORD, new String[]{PASSWORD_ID, PASSWORD},
null, null, null, null, null, null);
if (cursor != null &&
cursor.moveToFirst()) {
return new Password(
cursor.getString(INDEX_PASSWORD_ID),
cursor.getInt(INDEX_PASSWORD));
}
return null;
}
}
4) Finally, save/update/retrieve the password as desired:
public class MainActivity extends AppCompatActivity {
private PasswordDbAdapter passwordDB;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
// initialize the password db
passwordDB = new PasswordDbAdapter(this);
// check if password record exists
if (passwordDB.isEmpty() {
// save a new copy
passwordDB.addPassword("the_password"); // more secure if it is saved encrypted
} else {
// update it
passwordDB.updatePassword("the_password");
}
}
...
public String fetchPassword() {
return passwordDB.fetchPassword(); // or first decrypt it, then return it
}
}

How to update an existing SQLite db table data with new android app update?

I recently launched an app on the android app store that contained a SQLite database.
I am now attempting to release an update of the app, and want to add more data into the existing database, however have come a bit unstuck. I have read answers on SO that outline making changes to the database itself, however I want my tables and columns to stay the same, only add new data in.
The data that i want to add to the database is pulled from CSV files in the Raw file, and originally loaded into the database when the user registers for the app.
I have a feeling I am going to need to implement the onUpgrade method, however should I be adding the new data from the CSV files in at that point as well? Is it a matter of simple updating the database version and using the onUpgrade to load the new data?
I am fairly new to SQLite DB, so any help would be hugely appreciated.
CourseDBHelper Code
public class CourseDBHelper extends SQLiteOpenHelper {
// Database Version
private static final int DATABASE_VERSION = 1;
// Database Name
private static final String DATABASE_NAME = "CourseDB";
// Create two table names
private static final String TABLE_COURSES = "courses";
// Universities Table Columns names
private static final String COURSE_NAME = "Course_name";
private static final String UNI_NAME = "Uni_name";
private static final String COURSE_DURATION = "Duration";
private static final String COURSE_STUDY_MODE = "Study_mode";
private static final String COURSE_QUALIFICATION = "Qualification";
private static final String COURSE_ENTRY_STANDARDS = "Entry_standards";
private static final String COURSE_GRADUATE_PROSPECTS = "Graduate_prospects";
private static final String COURSE_STUDENT_SATISFACTION = "Student_satisfaction";
private String CREATE_COURSES_TABLE = "CREATE TABLE courses" +
"(" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT," +
"Course_name TEXT NOT NULL," +
"Uni_name TEXT NOT NULL," +
"Duration TEXT NOT NULL," +
"Study_mode TEXT NOT NULL," +
"Qualification TEXT NOT NULL," +
"Entry_standards TEXT NOT NULL," +
"Graduate_prospects TEXT NOT NULL," +
"Student_satisfaction TEXT NOT NULL" +
");";
private static final String[] COLUMNS = {
COURSE_NAME,
UNI_NAME,
COURSE_DURATION,
COURSE_STUDY_MODE,
COURSE_QUALIFICATION,
COURSE_ENTRY_STANDARDS,
COURSE_GRADUATE_PROSPECTS,
COURSE_STUDENT_SATISFACTION
};
public CourseDBHelper(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// TODO: REMOVED NOT NULL FROM EVERY COLUMN FOR TEST PURPOSES, WILL NEED TO BE READDED
#Override
public void onCreate(SQLiteDatabase db)
{
db.execSQL(CREATE_COURSES_TABLE);
}
public void deleteAll()
{
SQLiteDatabase db = this.getWritableDatabase();
db.delete("courses", null, null);
db.execSQL("delete from " + "courses");
db.close();
}
// Getting one course by course name and uni name
public Course getCourse(String courseName, String uniName) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_COURSES, COLUMNS, " Course_name = ? AND Uni_name = ?",
new String[]{courseName, uniName},
null,
null,
null,
null);
if (cursor != null)
cursor.moveToFirst();
Course course = new Course();
/*
System.out.println(cursor.getString(0));
System.out.println(cursor.getString(1));
System.out.println(cursor.getString(2));
System.out.println(cursor.getString(3));
System.out.println(cursor.getString(4));
System.out.println(cursor.getString(5));
System.out.println(cursor.getString(6));
*/
course.setCourseName(cursor.getString(0));
course.setUniversity(cursor.getString(1));
course.setCourseDuration(cursor.getString(2));
course.setStudyMode(cursor.getString(3));
course.setQualification(cursor.getString(4));
course.setEntryStandards(cursor.getString(5));
course.setGradProspects(cursor.getString(6));
course.setStudentSatisfaction(cursor.getString(7));
return course;
}
public void addCourse(Course course)
{
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COURSE_NAME, course.getCourseName());
values.put(UNI_NAME, course.getUniversity());
values.put(COURSE_DURATION, course.getCourseDuration());
values.put(COURSE_STUDY_MODE, course.getStudyMode());
values.put(COURSE_QUALIFICATION, course.getQualification());
values.put(COURSE_ENTRY_STANDARDS, course.getEntryStandards());
values.put(COURSE_GRADUATE_PROSPECTS, course.getGradProspects());
values.put(COURSE_STUDENT_SATISFACTION, course.getStudentSatisfaction());
db.insert(TABLE_COURSES,
null, //nullColumnHack
values);
db.close();
}
public ArrayList<Course> getAllCourses()
{
ArrayList<Course> courses = new ArrayList<>();
// 1. build the query
String query = "SELECT * FROM " + TABLE_COURSES;
// 2. get reference to writable DB
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(query, null);
// 3. go over each row, build course and add it to list
Course course;
if(cursor.moveToFirst()){
cursor.moveToNext();
do{
course = new Course();
course.setCourseName(cursor.getString(1));
course.setUniversity(cursor.getString(2));
course.setCourseDuration(cursor.getString(3));
course.setStudyMode(cursor.getString(4));
course.setQualification(cursor.getString(5));
course.setEntryStandards(cursor.getString(6));
course.setGradProspects(cursor.getString(7));
course.setStudentSatisfaction(cursor.getString(8));
// Add course to courses list
courses.add(course);
} while(cursor.moveToNext());
}
// return courses
return courses;
}
public int getDBCount()
{
SQLiteDatabase db = this.getWritableDatabase();
String count = "SELECT count(*) FROM courses";
Cursor mcursor = db.rawQuery(count, null);
mcursor.moveToFirst();
int icount = mcursor.getInt(0);
return icount;
}
public void deleteCourse(Course course) {
// 1. get reference to writable DB
SQLiteDatabase db = this.getWritableDatabase();
// 2. delete
db.delete("courses", //table name
"Course_name = ? AND Uni_name = ?", // selections
new String[] { course.getCourseName(), course.getUniversity() }); //selections args
// 3. close
db.close();
}
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
Method that loads data from CSV file to SQlite DB
public void populateCourseDatabase(int id) {
// NOW POPULATE THE COURSE DATABASE FILE
inputStream = getResources().openRawResource(R.raw.coursesone);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String word;
String cvsSplitBy = ",";
try{
while((word = reader.readLine()) != null){
Log.d(TAG, "constructing Course object from: " + word);
String[] segment = word.split(cvsSplitBy);
Course course = new Course();
course.setCourseName(segment[0]);
course.setUniversity(segment[1]);
course.setCourseDuration(segment[2]);
course.setStudyMode(segment[3]);
course.setQualification(segment[4]);
course.setEntryStandards(segment[5]);
course.setGradProspects(segment[6]);
course.setStudentSatisfaction(segment[7]);
myCourseDBHelper.addCourse(course);
progressBar.setProgress(count);
count = count + 1;
System.out.println("Sucessfully added: " + course.toString());
}
}
catch(IOException e1){
e1.printStackTrace();
System.out.println("SOMETHING WENT WRONG");
}
}
SQLiteOpenHelper onCreate() and onUpgrade() callbacks are invoked when the database is actually opened, for example by a call to getWritableDatabase().onCreate() is only run when the database file did not exist and was just created. onUpgrade() is only called when the database file exists but the stored version number is lower than requested in constructor.Increment the database version so that onUpgrade() is invoked.
Example pseudo code below
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch(oldVersion) {
case 1:
//upgrade logic from version 1 to 2
case 2:
//upgrade logic from version 2 to 3
case 3:
//upgrade logic from version 3 to 4
break;
default:
throw new IllegalStateException(
"onUpgrade() with unknown oldVersion " + oldVersion);
}
}

can I add android sqlite transaction in other class(not MyDatabaseHelper, not MyDB)?

As I make the SQLite in android app, I made 3 class.
first is "MyDatabaseHelper.java" that make database and table.
second is "MyDB.java" that contain some functions(insert, cursor, update, delete).
third is "MyDBDefaultValues" that make default values using insert function in "MyDB.java".
The point is about transaction.
following the transaction manual(Android Database Transaction),
I need to insert "db.beginTransaction()" into "MyDB.java" because there are SQLitebase.
but I make the default values using insert function in other class(MyDBDefaultValues.java).
As a results, I don't know where to add transaction in my code. I know if I make a default code in "MyDB.java", I can add transaction in "MyDB.java".
but I want to separate "MyDB.java" and "MyDBDefaultValues.java".please tell me how to add transaction in my code.
Under is my code.
MyDatabaseHelper.java
public class MyDatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "Torticollis";
private static final int DATABASE_VERSION = 1;
// Database creation sql statement
private static final String DATABASE_CREATE = "create table Torticollis_Management(" +
"_id integer primary key autoincrement, " +
"date text not null, " + // store date to text type and convert between formats using the built-in date and time functions
"stretching1 text, " +
"stretching2 text, " +
"stretching3 text, " +
"stretching4 text, " +
"stretching5 text," +
"today_pain integer);";
public MyDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
Log.d("confirm", "this is first's god");
}
// Method is called during creation of the database
#Override
public void onCreate(SQLiteDatabase database) {
database.execSQL(DATABASE_CREATE);
}
// Method is called during an upgrade of the database,
#Override
public void onUpgrade(SQLiteDatabase database,int oldVersion,int newVersion){
Log.w(MyDatabaseHelper.class.getName(),
"Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
database.execSQL("DROP TABLE IF EXISTS Torticollis_Management");
onCreate(database);
}
}
MyDB.java
public class MyDB{
private MyDatabaseHelper dbHelper;
private SQLiteDatabase database;
public final static String Tor_TABLE = "Torticollis_Management"; // name of table
public final static String Tor_ID = "_id"; // id value for Torticollis
public final static String Tor_DATE = "date"; // date of Torticollis
public final static String Tor_STRETCHING1 = "stretching1"; // stretching1 of Torticollis
public final static String Tor_STRETCHING2 = "stretching2"; // stretching2 of Torticollis
public final static String Tor_STRETCHING3 = "stretching3"; // stretching3 of Torticollis
public final static String Tor_STRETCHING4 = "stretching4"; // stretching4 of Torticollis
public final static String Tor_STRETCHING5 = "stretching5"; // stretching5 of Torticollis
public final static String Tor_TODAY_PAIN = "today_pain"; // today_pain of Torticollis
// today_pain value's type is "String" but it's real type is "int"
/**
*
* #param context
*/
public MyDB(Context context){ // why do I add this 'context'??
dbHelper = new MyDatabaseHelper(context);
}
public long insert(String date, String stretching1, String stretching2, String stretching3,
String stretching4, String stretching5, int today_pain){
database = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
// values.put(Tor_ID, id); // "id" don't need to insert because that's made "autoincrement".
values.put(Tor_DATE, date);
values.put(Tor_STRETCHING1, stretching1);
values.put(Tor_STRETCHING2, stretching2);
values.put(Tor_STRETCHING3, stretching3);
values.put(Tor_STRETCHING4, stretching4);
values.put(Tor_STRETCHING5, stretching5);
values.put(Tor_TODAY_PAIN, today_pain); // why do I have to inert "integer"'s today_pain value into "String"'s Tor_TODAY_PAIN?
return database.insert(Tor_TABLE, null, values);
}
public Cursor cursor() {
database = dbHelper.getReadableDatabase();
String[] cols = new String[] {Tor_ID, Tor_DATE, Tor_STRETCHING1, Tor_STRETCHING2, Tor_STRETCHING3,
Tor_STRETCHING4, Tor_STRETCHING5, Tor_TODAY_PAIN};
Cursor mCursor = database.query(true, Tor_TABLE, cols, null, null, null, null, null, null);
if (mCursor != null) {mCursor.moveToFirst();}
return mCursor; // iterate to get each value.
}
public boolean update(String date, String stretching1, String stretching2, String stretching3,
String stretching4, String stretching5, int today_pain) {
database = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
// values.put(Tor_ID, id); // "id" don't need to insert because that exist only for counting
values.put("date", date);
values.put("stretching1", stretching1);
values.put("stretching2", stretching2);
values.put("stretching3", stretching3);
values.put("stretching4", stretching4);
values.put("stretching5", stretching5);
values.put("today_pain", today_pain);
database.update("Torticollis_Management", values, "date = ?", new String[]{date}); // need to know this coding
return true;
}
public Integer delete(String date) {
database = dbHelper.getWritableDatabase();
return database.delete("Torticollis_Management", "id = ?", new String[]{date}); // need to know this coding
}
}
MyDBDefaultValues.java
public class MyDBDefaultValues {
MyDB mydb;
public MyDBDefaultValues(Context context){ // why do I have to write the word "context". what's the mean of "context"?
mydb = new MyDB(context);
insertDefaultValues(); // insert default values if there is no data.
}
public void insertDefaultValues() {
Cursor cursor = mydb.cursor();
cursor.moveToLast();
int count = cursor.getCount();
if(count > 0) {
// do nothing
} else { // insert default values if there is no data.
mydb.insert("2016-07-01", "X", "X", "X", "X", "X", 0);
mydb.insert("2016-07-02", "X", "X", "X", "X", "X", 0);
mydb.insert("2016-07-03", "X", "X", "X", "X", "X", 0);
mydb.insert("2016-07-04", "X", "X", "X", "X", "X", 0);
}
}
}
In general, you should put transactions into the outermost function(s); this is both correct (multiple DB operations are then atomic), and more efficient:
public void insertDefaultValues() {
mydb.beginTransaction();
try {
if (mydb.cursor().getCount() == 0) {
mydb.insert(...);
...
}
mydb.setTransactionSuccessful();
} finally {
mydb.endTransaction();
}
}
This requires that you add wrappers for the beginTransaction() etc. calls to your MyDB class.

Unable to insert record into SQLite database from another class

I am trying to insert record into a sqlite database and bypassing the contentResolver. The first class named EventProvider extends ContentProvider and also contains an instance of my SQLite database helper class as shown below. So the code in the first class works fine when i insert records through a contentResolver but within the EventJSONParser class i want to insert the record directly the sqlite instead it throughs a NullPointerException in the SQLiteDatabase db = provider.getDatabase(); line of code within the unmarshalEventQuery method. I suspect that an instance of the databasehelper is not created by the onCreate() method. Please i need suggestions on how to solve this problem. thanks.
First Class:
public class EventProvider extends ContentProvider{
private DatabaseHelper helper;
private SQLiteDatabase db;
#Override
public boolean onCreate() {
helper = new DatabaseHelper(getContext());
db = helper.getWritableDatabase();
return true;
}
public SQLiteDatabase getDatabase(){
return db;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
if (BuildConfig.DEBUG) { Log.d(TAG, "insert#" + uri); }
switch (uriMatcher.match(uri)){
case EVENTS_DIR:
break;
default:
throw new UnsupportedOperationException("Unrecognized URI: " + uri);
}
values = COLUMN_MAP.translateCols(values);
values.put(DatabaseContract.COL_DIRTY, MARK);enter code here
SQLiteDatabase db = getDatabase();
return eventInsert(uri, values, db);
}
public Uri eventInsert(Uri uri, ContentValues values, SQLiteDatabase mdb){
if (BuildConfig.DEBUG){
Log.d(TAG, "insert#" + uri + ": {" + values + "}");
}
long pk = mdb.insert(DatabaseContract.EVENT_TABLE, null, values);
if (pk > 0) {
uri = null;
} else{
uri = uri.buildUpon().appendPath(String.valueOf(pk)).build();
getContext().getContentResolver().notifyChange(uri, null);
}
return uri;
}
Second class:
public class EventJSONParser {
private EventProvider provider;
public EventJSONParser(EventProvider restfulProvider){
provider = restfulProvider;
}
public void unmarshalEventQuery(JSONObject json){
try {
String error = json.getString(Const.KEY_ERROR);
int statusCode = json.getInt(Const.KEY_STATUS_CODE);
if (error.equals("false") && statusCode == 200){
JSONArray events = json.getJSONArray(TAG_EVENTS);
for(int i = 0; i < events.length(); i++){
JSONObject e = events.getJSONObject(i);
ContentValues values = new ContentValues();
values.put(UNMARSHAL_TAB.get(TAG_EVENT_ID), e.getString(TAG_EVENT_ID));
values.put(UNMARSHAL_TAB.get(TAG_CAL_ID), e.getString(TAG_CAL_ID));
values.put(UNMARSHAL_TAB.get(TAG_EVENT_TITLE), e.getString(TAG_EVENT_TITLE));
values.put(UNMARSHAL_TAB.get(TAG_START_DATE), e.getString(TAG_START_DATE));
values.put(UNMARSHAL_TAB.get(TAG_END_DATE), e.getString(TAG_END_DATE));
values.put(UNMARSHAL_TAB.get(TAG_LOCATION), e.getString(TAG_LOCATION));
values.put(UNMARSHAL_TAB.get(TAG_VISIBILITY), e.getString(TAG_VISIBILITY));
values.put(UNMARSHAL_TAB.get(TAG_DESCRIPTION), e.getString(TAG_DESCRIPTION));
SQLiteDatabase db = provider.getDatabase();
Uri uri = provider.eventInsert(EventContract.EVENT_URI, values, db);
Log.e(TAG, "query uri" + uri);
}
}
}catch (JSONException ex){
ex.printStackTrace();
}
}
}
You should open the database before running an operation into database.
This class file link
public CourseGateWay(Context context) {
dbOpenHelper = new DBOpenHelper(context);
this.context = context;
}
public void open() {
try {
sqLiteDB = dbOpenHelper.getWritableDatabase();
} catch (SQLException s) {
new Exception("Error with DB Open");
}
}
public void close() {
sqLiteDB.close();
}
public String saveCourse(Courses aCore) {
ContentValues contentValues = new ContentValues();
open();
contentValues.put(DBOpenHelper.COURS_CODE, aCore.getcCode());
contentValues.put(DBOpenHelper.COURS_NAME, aCore.getcName());
contentValues.put(DBOpenHelper.COURS_DEPT, aCore.getdCode());
long res = sqLiteDB.insert(DBOpenHelper.TABLE_COURS, null,
contentValues);
close();
if (res > 0) {
return "Course Added with: " + aCore.getcCode();
} else {
return "Duplicate Entry with: " + aCore.getcName();
}
}
Please see my github : here
For better give the permission in Manifesto file:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Android application force closing on device

On the Emulator the app runs fine. On the device the moment im trying to copy my database over the application's database and execute a query the app force closes. Any idea why this could be happening? Do i have to request any kind of permissions or something in manifest for it to run?
Database.Java
public class Database extends SQLiteOpenHelper{
//The Android's default system path of your application database.
private static String DB_PATH = "/data/data/gr.BHC.www/databases/";
//Name of the Database to be created.
private static String DB_NAME = "BHCLibrary3.sqlite";
private SQLiteDatabase myDataBase;
private final Context myContext;
* Constructor
* Takes and keeps a reference of the passed context in order to access to the application assets and resources.
* #param context
*/
public Database(Context context) {
super(context, DB_NAME, null, 1);
this.myContext = context;
}
/**
* Creates a empty database on the system and rewrites it with your own database.
* */
public void createDataBase() throws IOException{
//First we check if the database already exists, Method declared later
boolean dbExist = checkDataBase();
if(dbExist){
//do nothing - database already exists
}else{
//By calling this method an empty database will be created into the default system path
//of your application so we are going to be able to overwrite that database with our database.
this.getReadableDatabase();
try {
copyDataBase(); //Method declared later
} catch (IOException e) {
throw new Error("Error copying database");
}
}
}
/**
* Check if the database already exist to avoid re-copying the file each time you open the application.
* #return true if it exists, false if it doesn't
*/
private boolean checkDataBase() {
//SQLiteDatabase checkdb = null;
boolean checkdb = false;
try{
String myPath = DB_PATH + DB_NAME;
File dbfile = new File(myPath);
//checkdb = SQLiteDatabase.openDatabase(myPath,null,SQLiteDatabase.OPEN_READWRITE);
checkdb = dbfile.exists();
}
catch(SQLiteException e){
System.out.println("Database doesn't exist");
}
return checkdb;
}
/**
* Copies your database from your local assets-folder to the just created empty database in the
* system folder, from where it can be accessed and handled.
* This is done by transferring byte stream.
* */
private void copyDataBase() throws IOException{
//Open your local db as the input stream
InputStream myInput = myContext.getAssets().open(DB_NAME);
// Path to the just created empty db
String outFileName = DB_PATH + DB_NAME;
//Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(outFileName);
//transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer))>0){
myOutput.write(buffer, 0, length);
}
//Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
}
//Opening the Database
public void openDataBase() throws SQLException{
//Open the database
String myPath = DB_PATH + DB_NAME;
myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);
}
//Finally overriding a few methods as required
#Override
public synchronized void close() {
if(myDataBase != null)
myDataBase.close();
super.close();
}
#Override
public void onCreate(SQLiteDatabase db) {
//First we check if the database already exists, Method declared later
boolean dbExist = checkDataBase();
if(dbExist){
//do nothing - database already exists
}else{
//By calling this method an empty database will be created into the default system path
//of your application so we are going to be able to overwrite that database with our database.
this.getReadableDatabase();
try {
copyDataBase(); //Method declared later
} catch (IOException e) {
throw new Error("Error copying database");
}
}
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
And Results.java (The activity i run my query)
public class SearchResults extends ListActivity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.searchresults);
Database myDbHelper = new Database(null);
myDbHelper = new Database(this);
}
// Get the intent, verify the action and get the query
Intent intent = getIntent();
String query = intent.getStringExtra(SearchManager.QUERY);
SQLiteDatabase myDb = myDbHelper.getReadableDatabase();
//Executing our query against the server using rawQuery and getting the cursor
String select="SELECT DISTINCT b._ISBN as _id, b.BookTitle, b.Edition, b.Year, b.Pages, b.Rating, c.Category, p.Publisher, w.LastName" +
" FROM" +
" Books b" +
" JOIN Categories_Books cb ON cb._Books_ISBN = _id" +
" JOIN Categories c ON c._CategoryID = cb._Categories_CategoryID" +
" JOIN Publishers p ON p._PublisherID = b.PublisherID" +
" JOIN Writers_Books wb ON wb._Books_ISBN = _id" +
" JOIN Writers w ON w._WriterID = wb._Writers_WriterID" +
" WHERE b.BookTitle LIKE '%" + query +"%'" +
" OR c.Category LIKE '%" + query +"%'" +
" OR p.Publisher LIKE '%" + query +"%'" +
" OR w.LastName LIKE '%" + query +"%'" +
" OR _id LIKE '%" + query +"%'" +
" GROUP BY b.BookTitle";
Cursor c = myDb.rawQuery(select, null);
startManagingCursor(c);
// the desired columns to be bound
String[] columns = new String[] { "Books.BookTitle", "Publishers.Publisher" };
// the XML defined views which the data will be bound to
int[] to = new int[] { R.id.ISBN_entry, R.id.Title_entry };
//Getting results into our listview
try
{
SimpleCursorAdapter mAdapter = new SimpleCursorAdapter(this, R.layout.listlayout, c, columns, to);
this.setListAdapter(mAdapter);
}
catch( Exception e)
{
}
}
}
Help would be appreciated.
EDIT: The error im getting is : java.lang.runtimeexception: Unable to start activity Componentinfo(gr.BHC.www/gr.BHC.www.SearchResults} and then various exceptions saying table books etc dont exist.
EDIT2: I saw the exception im getting usually related with content providers but i still cant figure out why i'd get that.
I think I solved the problem. I made some changes on your codes and now it is working. Here are the codes:
SearchResults.java
public class SearchResults extends ListActivity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.searchresults);
DbManager myDbHelper = new DbManager(null);
myDbHelper = new DbManager(this);
// Get the intent, verify the action and get the query
myDbHelper.createNewDatabase();
try {
myDbHelper.open();
Log.d("Search Results", "database opened");
} catch (SQLException sqle) {
throw sqle;
}
Intent intent = getIntent();
String query = intent.getStringExtra(SearchManager.QUERY);
// Executing our query against the server using rawQuery and getting the
// cursor
String select = "SELECT DISTINCT b._ISBN as _id, b.BookTitle, b.Edition, b.Year, b.Pages, b.Rating, c.Category, p.Publisher, w.LastName"
+ " FROM"
+ " Books b"
+ " JOIN Categories_Books cb ON cb._Books_ISBN = _id"
+ " JOIN Categories c ON c._CategoryID = cb._Categories_CategoryID"
+ " JOIN Publishers p ON p._PublisherID = b.PublisherID"
+ " JOIN Writers_Books wb ON wb._Books_ISBN = _id"
+ " JOIN Writers w ON w._WriterID = wb._Writers_WriterID"
+ " WHERE b.BookTitle LIKE '%"
+ query
+ "%'"
+ " OR c.Category LIKE '%"
+ query
+ "%'"
+ " OR p.Publisher LIKE '%"
+ query
+ "%'"
+ " OR w.LastName LIKE '%"
+ query
+ "%'"
+ " OR _id LIKE '%"
+ query
+ "%'"
+ " GROUP BY b.BookTitle";
Cursor c = myDbHelper.rawQ(select);
startManagingCursor(c);
// the desired columns to be bound
String[] columns = new String[] { "Books.BookTitle",
"Publishers.Publisher" };
// the XML defined views which the data will be bound to
int[] to = new int[] { R.id.ISBN_entry, R.id.Title_entry };
// Getting results into our listview
try {
SimpleCursorAdapter mAdapter = new SimpleCursorAdapter(this,
R.layout.listlayout, c, columns, to);
this.setListAdapter(mAdapter);
} catch (Exception e) {
}
}
}
And your new database helper, DbManager:
DbManager.java
public class DbManager extends SQLiteOpenHelper {
private static final String DB_NAME = "BHCLibrary3.sqlite";
private static final String DB_PATH = "/data/data/gr.BHC.www/databases/";
private static final Integer DB_VERSION = 1;
private static final String TAG = "DbManager";
private final Context context;
private SQLiteDatabase db;
private DbManager dbManager;
public DbManager(Context context) {
super(context, DB_NAME, null, DB_VERSION);
this.context = context;
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE 'notes' (_id integer primary key autoincrement, title text not null);");
}
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
public DbManager open() {
dbManager = new DbManager(context);
db = dbManager.getWritableDatabase();
return this;
}
public void createNewDatabase() {
InputStream assetsDB = null;
try {
assetsDB = context.getAssets().open(DB_NAME);
OutputStream dbOut = new FileOutputStream(DB_PATH + DB_NAME);
byte[] buffer = new byte[1024];
int length;
while ((length = assetsDB.read(buffer)) > 0) {
dbOut.write(buffer, 0, length);
}
dbOut.flush();
dbOut.close();
assetsDB.close();
Log.i(TAG, "New database created...");
} catch (IOException e) {
Log.e(TAG, "Could not create new database...");
e.printStackTrace();
}
}
public Cursor rawQ(String select) {
return db.rawQuery(select, null);
}
}
Looks like the size of your database exceeds one MB. In that case you need to store it in the assets folder as .jpg and then copy it over. This is because Android places a restriction on the size of the text assets.

Categories