Im trying to store a particular columns data in a method and call that method in another classes String [] where a spinner will access that array to display the columns rows for the user to select which will then get stored in another database.
Im getting nulpointerexception and when I try and open() the database the database gets locked. Sorry for sounding like a complete amateur, relatively new to android. Thank you in advance for any help.
Here is my code when I call getInstance() and getCPnames() in my main class
String[] carParks = CarParkDb.getInstance().getCpnames();
Here is my code for the database:
package com.example.parkangel;
import java.util.ArrayList;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class CarParkDb {
public static final String KEY_ID = "_id";
public static final String KEY_CPNAME = "cpname";
public static final String KEY_COST = "cost";
private static final String DATABASE_NAME = "CPDB";
private static final String DATABASE_TABLE = "CPTable";
private static final int DATABASE_VERSION = 1;
private CPDbHelper cpdbHelper;
private Context ourContext;
private SQLiteDatabase ourDatabase;
private static CarParkDb instance;
private static class CPDbHelper extends SQLiteOpenHelper{
public CPDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
// TODO Auto-generated constructor stub
}
#Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" +
KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
KEY_CPNAME + " TEXT NOT NULL, " + KEY_COST + " TEXTNOT NULL);");
db.execSQL("INSERT INTO " + DATABASE_TABLE + " Values('1','LearningResource Center','2');");
db.execSQL("INSERT INTO " + DATABASE_TABLE + " Values ('2','ParkandRide','1');");
db.execSQL("INSERT INTO " + DATABASE_TABLE + " Values ('3','deHavilland Campus','2');");
db.execSQL("INSERT INTO " + DATABASE_TABLE + " Values('4','MultiStorey Building','2');");
db.execSQL("INSERT INTO " + DATABASE_TABLE + " Values('5','Reception','2');");
}
public void onOpen(final SQLiteDatabase db) {
super.onOpen(db);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
onCreate(db);
}
}
public CarParkDb (final Context c)
{
this.cpdbHelper= new CPDbHelper(c);
establishDb();
//ourContext = c;
}
public void establishDb()
{
if (this.ourDatabase == null)
{
this.ourDatabase = this.cpdbHelper.getWritableDatabase();
}
}
public CarParkDb() {
// TODO Auto-generated constructor stub
}
public CarParkDb open() throws SQLException
{
System.out.println ("running open");
cpdbHelper = new CPDbHelper(ourContext);
ourDatabase = cpdbHelper.getWritableDatabase();
return this;
}
public void close()
{
ourDatabase.close();
}
/*public long createEntry(String cpname, String cost){
ContentValues cv = new ContentValues();
cv.put(KEY_CPNAME, cpname);
cv.put(KEY_COST, cost);
return ourDatabase.insert(DATABASE_TABLE, null, cv);
}*/
public String getData() {
// TODO Auto-generated method stub
//open();
String[] columns = new String[] {KEY_ID, KEY_CPNAME, KEY_COST};
Cursor c = ourDatabase.query(DATABASE_TABLE, columns, null,null,null, null, null);
String result = " ";
int iRow = c.getColumnIndexOrThrow(KEY_ID);
int iCpname = c.getColumnIndexOrThrow(KEY_CPNAME);
int iCost = c.getColumnIndexOrThrow(KEY_COST);
for(c.moveToFirst(); !c.isAfterLast(); c.moveToNext()){
result = result + c.getString(iRow) + " " +c.getString(iCpname) + " " + c.getString(iCost) + " " + "\n";
c.close();
ourDatabase.close();
}
return result;
}
public static CarParkDb getInstance()
{
synchronized(CarParkDb.class)
{
if (instance == null)
{
instance = new CarParkDb();
}
return instance;
}
}
public String[] getCpnames()
{
//open();
if (ourDatabase == null) System.out.println ("is null");
Cursor c = null;
ArrayList<String> list = new ArrayList<String>();
ourDatabase = cpdbHelper.getReadableDatabase();
//SQLiteDatabase db = cpdbHelper.getReadableDatabase();
String query = "SELECT " + KEY_CPNAME + " FROM " + DATABASE_TABLE;
{
c = this.ourDatabase.rawQuery(query, null);
int iCpname = c.getColumnIndexOrThrow(KEY_CPNAME);
if (c.moveToFirst())
{
do
{
list.add(c.getString(iCpname));;
}
while (c.moveToNext());
}
if (c != null && !c.isClosed())
{
c.close();
ourDatabase.close();
}
return list.toArray(new String[]{});
}
}
}
**LogCat**
03-12 01:32:39.759: E/AndroidRuntime(4176): Caused by:java.lang.NullPointerException
03-12 01:32:39.759: E/AndroidRuntime(4176):
at com.example.parkangel.CarParkDb.getCpnames(CarParkDb.java:191)
03-12 01:32:39.759: E/AndroidRuntime(4176):
at com.example.parkangel.BookTicket.<init>(BookTicket.java:22)
03-12 01:32:39.759: E/AndroidRuntime(4176):
at java.lang.Class.newInstanceImpl(Native Method)
03-12 01:32:39.759: E/AndroidRuntime(4176):
at java.lang.Class.newInstance(Class.java:1208)
The database doesn't get locked. The "locked" thinkg is just a NPE in a method called getDatabaseLocked() and it's caused by a null Context passed to SQLiteOpenHelper in constructor that manifests itself with getWritableDatabase() or getReadableDatabase().
To fix the NPE in getDatabaseLocked(), make sure ourContext in open() is not null. As of now, you've never initialized ourContext and it's always null. Uncomment the //ourContext = c; in constructor and move it above the establishDb(), remove the other no-argument constructor and pass in a Context for example as suggested by Merlevede.
The NPE stacktrace in your question is when you call getCpNames() with open() commented out and are trying to call a method on a null ourDatabase object reference. Uncomment the open() there once it's fixed. The stacktrace also says you're trying to call getCpNames() in object initialization phase e.g. when initializing a member variable. That might be too early, for example an activity cannot be used as a Context until onCreate().
Some other things in your code you'd hit next:
in onCreate(): + KEY_COST + " TEXTNOT NULL) - add space between TEXT and NOT
in getData(): you're closing the cursor and database in the loop where you're accessing the cursor. Do it after the loop. The code shouldn't compile as you're not returning anything from a non-void function in case moveToFirst() returns false.
Try updating your getInstance() code with this:
public static CarParkDb getInstance(Context c) // <-- added context as parameter
{
synchronized(CarParkDb.class)
{
if (instance == null)
{
instance = new CarParkDb(c); // <-- used context in constructor
}
return instance;
}
}
The problem seems to be that you're using a constructor (for CarParkDb) that does nothing. You have another constructor that takes a Context as parameter and initializes some of the objects that you're using later.
Related
I am writing an Android application that queries a database with 170,000 dictionary words. (It has 31 columns: _id, word, sortedWord, length, and count_A, count_B, count_C, ... count_Z)
Here is the code for my Dictionary database helper
public class DictionaryDbHelper extends SQLiteOpenHelper {
private static final String TAG = "DataBaseHelper";
// The Android's default system path of your application database.
private static String DB_PATH = "/data/data/com.rabbitfighter.wordsleuth/databases/";
// Database name
private static String DB_NAME = "dictionary.db";
// Database, and context
private SQLiteDatabase myDataBase;
private final Context myContext;
// Table name
public static final String TABLE_NAME = "dictionary";
// Table columns
public static final String UID = "_id";
// Word
public static final String COLUMN_NAME_WORD = "word";
// Length
public static final String COLUMN_NAME_WORD_LENGTH = "length";
// For all the letters, A-Z.
public static final String COLUMN_NAME_COUNT_A = "count_A";
public static final String COLUMN_NAME_COUNT_B = "count_B";
public static final String COLUMN_NAME_COUNT_C = "count_C";
public static final String COLUMN_NAME_COUNT_D = "count_D";
public static final String COLUMN_NAME_COUNT_E = "count_E";
public static final String COLUMN_NAME_COUNT_F = "count_F";
public static final String COLUMN_NAME_COUNT_G = "count_G";
public static final String COLUMN_NAME_COUNT_H = "count_H";
public static final String COLUMN_NAME_COUNT_I = "count_I";
public static final String COLUMN_NAME_COUNT_J = "count_J";
public static final String COLUMN_NAME_COUNT_K = "count_K";
public static final String COLUMN_NAME_COUNT_L = "count_L";
public static final String COLUMN_NAME_COUNT_M = "count_M";
public static final String COLUMN_NAME_COUNT_N = "count_N";
public static final String COLUMN_NAME_COUNT_O = "count_O";
public static final String COLUMN_NAME_COUNT_P = "count_P";
public static final String COLUMN_NAME_COUNT_Q = "count_Q";
public static final String COLUMN_NAME_COUNT_R = "count_R";
public static final String COLUMN_NAME_COUNT_S = "count_S";
public static final String COLUMN_NAME_COUNT_T = "count_T";
public static final String COLUMN_NAME_COUNT_U = "count_U";
public static final String COLUMN_NAME_COUNT_V = "count_V";
public static final String COLUMN_NAME_COUNT_W = "count_W";
public static final String COLUMN_NAME_COUNT_X = "count_X";
public static final String COLUMN_NAME_COUNT_Y = "count_Y";
public static final String COLUMN_NAME_COUNT_Z = "count_Z";
/**
* Constructor
* Takes and keeps a reference of the passed context in order to access to the application assets and resources.
* #param context
*/
public DictionaryDbHelper(Context context) {
super(context, DB_NAME, null, 1);
this.myContext = context;
}
/* ------------------------ */
/* --- Override Methods --- */
/* ------------------------ */
/**
* On creation
* #param db - the database
*/
public void onCreate(SQLiteDatabase db) {
//Nothing to do here
}
/**
* On upgrade
* #param db - the database
* #param oldVersion - the old database version int
* #param newVersion - the new database version int
*/
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i(TAG, "Database " + db + " version " + oldVersion + " upgraded to " + newVersion);
}
/**
* On downgrade
* #param db - the database
* #param oldVersion - the old database version int
* #param newVersion - the new database version int
*/
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i(TAG, "Database " + db + " version " + oldVersion + " downgraded to " + newVersion);
}
/**
* Creates a empty database on the system and rewrites it with your own database.
* */
public void createDataBase() throws IOException{
if(checkDataBase()){
//do nothing - database already exist
Log.i(TAG, "Database already exists... Nothing to do.");
}else{
//By calling this method and empty database will be created into the default system path
//of your application so we are gonna be able to overwrite that database with our database.
this.getReadableDatabase();
try {
copyDataBase();
Log.i(TAG, "Successfully copied database");
} catch (IOException e) {
Log.i(TAG, "Error copying");
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;
try{
String myPath = DB_PATH + DB_NAME;
checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
}catch(SQLiteException e){
//database doesn't exist yet.
Log.i(TAG, "Database doesn't exist yet");
}
// Check for null db
if(checkDB != null){
checkDB.close();
Log.i(TAG, "Closed dict database");
}
// Return null or not null
return checkDB != null;
}
/**
* 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 transfering bytestream.
* */
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 input file to the output file
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();
}
public void openDataBase() throws SQLException {
//Open the database
String myPath = DB_PATH + DB_NAME;
myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
}
#Override
public synchronized void close() {
if(myDataBase != null) {
Log.i(TAG, "Closing dictionary database");
myDataBase.close();
}
super.close();
}
/* -------------------------- */
/* --- Database retrieval --- */
/* -------------------------- */
/**
* Get the Anagrams in the database
* #return the number of anagrams
*/
public ArrayList<Result> getMatches(
// Params. Yeah, I know...
int count_A, int count_B, int count_C, int count_D, int count_E, int count_F,
int count_G, int count_H, int count_I, int count_J, int count_K, int count_L,
int count_M, int count_N, int count_O, int count_P, int count_Q, int count_R,
int count_S, int count_T, int count_U, int count_V, int count_W, int count_X,
int count_Y, int count_Z, int count_WILDCARDS
) {
// Get the database helper to get access to everything...
SQLiteDatabase db = this.getWritableDatabase();
// List to hold matches
ArrayList<Result> resultList = new ArrayList<>();
// Here are the columns we care about in our search
String[] columns = {
UID,
COLUMN_NAME_WORD,
COLUMN_NAME_WORD_LENGTH,
COLUMN_NAME_COUNT_A,
COLUMN_NAME_COUNT_B,
COLUMN_NAME_COUNT_C,
COLUMN_NAME_COUNT_D,
COLUMN_NAME_COUNT_E,
COLUMN_NAME_COUNT_F,
COLUMN_NAME_COUNT_G,
COLUMN_NAME_COUNT_H,
COLUMN_NAME_COUNT_I,
COLUMN_NAME_COUNT_J,
COLUMN_NAME_COUNT_K,
COLUMN_NAME_COUNT_L,
COLUMN_NAME_COUNT_M,
COLUMN_NAME_COUNT_N,
COLUMN_NAME_COUNT_O,
COLUMN_NAME_COUNT_P,
COLUMN_NAME_COUNT_Q,
COLUMN_NAME_COUNT_R,
COLUMN_NAME_COUNT_S,
COLUMN_NAME_COUNT_T,
COLUMN_NAME_COUNT_U,
COLUMN_NAME_COUNT_V,
COLUMN_NAME_COUNT_W,
COLUMN_NAME_COUNT_X,
COLUMN_NAME_COUNT_Y,
COLUMN_NAME_COUNT_Z,
};
String[] selectionArgs = null;
// The selection (WHERE ...)
String selection =
COLUMN_NAME_COUNT_A +"<="+ count_A + " AND " +
COLUMN_NAME_COUNT_B +"<="+ count_B + " AND " +
COLUMN_NAME_COUNT_C +"<="+ count_C + " AND " +
COLUMN_NAME_COUNT_D +"<="+ count_D + " AND " +
COLUMN_NAME_COUNT_E +"<="+ count_E + " AND " +
COLUMN_NAME_COUNT_F +"<="+ count_F + " AND " +
COLUMN_NAME_COUNT_G +"<="+ count_G + " AND " +
COLUMN_NAME_COUNT_H +"<="+ count_H + " AND " +
COLUMN_NAME_COUNT_I +"<="+ count_I + " AND " +
COLUMN_NAME_COUNT_J +"<="+ count_J + " AND " +
COLUMN_NAME_COUNT_K +"<="+ count_K + " AND " +
COLUMN_NAME_COUNT_L +"<="+ count_L + " AND " +
COLUMN_NAME_COUNT_M +"<="+ count_M + " AND " +
COLUMN_NAME_COUNT_N +"<="+ count_N + " AND " +
COLUMN_NAME_COUNT_O +"<="+ count_O + " AND " +
COLUMN_NAME_COUNT_P +"<="+ count_P + " AND " +
COLUMN_NAME_COUNT_Q +"<="+ count_Q + " AND " +
COLUMN_NAME_COUNT_R +"<="+ count_R + " AND " +
COLUMN_NAME_COUNT_S +"<="+ count_S + " AND " +
COLUMN_NAME_COUNT_T +"<="+ count_T + " AND " +
COLUMN_NAME_COUNT_U +"<="+ count_U + " AND " +
COLUMN_NAME_COUNT_V +"<="+ count_V + " AND " +
COLUMN_NAME_COUNT_W +"<="+ count_W + " AND " +
COLUMN_NAME_COUNT_X +"<="+ count_X + " AND " +
COLUMN_NAME_COUNT_Y +"<="+ count_Y + " AND " +
COLUMN_NAME_COUNT_Z +"<="+ count_Z;
String groupBy = null;
String having = null;
String orderBy = null;
// Query the database
Cursor cursor = db.query(
TABLE_NAME, // Table name
columns, // Columns
selection, // Selection
selectionArgs, // Selection arguments
groupBy, // Group by...
having, // having
orderBy // Order by
);
while (cursor.moveToNext()) {
int columnResult = cursor.getColumnIndex(COLUMN_NAME_WORD);
// Add the result to the list to return
resultList.add(new Result(cursor.getString(columnResult)));
}
cursor.close();
// Return the list
return resultList;
}
}//EOF
And here is where I query the Dictionary in another class:
How can I query for wildcards given my current setup? I am new to sql, so any suggestions would be greatly appreciated... I am looking for a parameter for the WHERE clause to allow for up to 2 wildcards, each of which could be anything from A-Z.
Here is an example of how i'm doing a lookup now, from my search service:
DictionaryDbHelper helper = DictionaryDbHelper(this);
ArrayList<Result> matches = helper.getMatches(
this.getQuery().getCount_A(), this.getQuery().getCount_B(),
this.getQuery().getCount_C(), this.getQuery().getCount_D(),
this.getQuery().getCount_E(), this.getQuery().getCount_F(),
this.getQuery().getCount_G(), this.getQuery().getCount_H(),
this.getQuery().getCount_I(), this.getQuery().getCount_J(),
this.getQuery().getCount_K(), this.getQuery().getCount_L(),
this.getQuery().getCount_M(), this.getQuery().getCount_N(),
this.getQuery().getCount_O(), this.getQuery().getCount_P(),
this.getQuery().getCount_Q(), this.getQuery().getCount_R(),
this.getQuery().getCount_S(), this.getQuery().getCount_T(),
this.getQuery().getCount_U(), this.getQuery().getCount_V(),
this.getQuery().getCount_W(), this.getQuery().getCount_X(),
this.getQuery().getCount_Y(), this.getQuery().getCount_Z(),0 // wildcards not in use yet
)
I have a table with two columns first is date and the second is a counter. I do not have a primary key but the date acts as one. So my code checks if the current date exists in the table, if so it will only increment the counter other wise it will add a new entry. The existence of the current date is only possible at the last row. here is the code:
SQLiteOpenHelper implementation:
public class SqliteHelperInstance extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "app_stats";
public static final String TABLE_NAME = "day_stats";
public static final String COLUMN_DATE = "date";
public static final String COLUMN_CIGCOUNT = "cigcount";
public static final int DATABASE_VERSION = 1;
private static final String CREATE_DB = "create table " + TABLE_NAME + " ( " + COLUMN_DATE + " text, "
+ COLUMN_CIGCOUNT + " integer );";
public SqliteHelperInstance(Context context){
super(context,DATABASE_NAME , null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL(CREATE_DB);
}
}
The implementation of database manager:
public class DbManager {
private SqliteHelperInstance sqlHelper;
private SQLiteDatabase database;
private String[] columns = { SqliteHelperInstance.COLUMN_DATE, SqliteHelperInstance.COLUMN_CIGCOUNT};
public DbManager(Context context){
sqlHelper = new SqliteHelperInstance(context);
}
public void addEntry(Calendar cal){
ContentValues values = new ContentValues();
String dateEntry = dateFormatter(cal);
Cursor cursor = database.query(SqliteHelperInstance.TABLE_NAME, null, null, null, null, null,
SqliteHelperInstance.COLUMN_DATE + " DESC LIMIT 1");
//check if the last entered date is equal to the current date
if(cursor.moveToFirst()){
String lastDate = cursor.getString(0);
if(lastDate.equalsIgnoreCase(dateEntry)){
//the cigNum should be updated for the current date
int cigNum = cursor.getInt(1);
cigNum ++;
values.put(SqliteHelperInstance.COLUMN_DATE,lastDate);
values.put(SqliteHelperInstance.COLUMN_CIGCOUNT, cigNum);
int i = database.update(SqliteHelperInstance.TABLE_NAME, values,SqliteHelperInstance.COLUMN_DATE + " = " + lastDate , null);
if(i == 0){
Log.d("Tag", "No row is affected");
}
}
else{
//the last date is different than current day so we need to add a new entry
DbEntry newEntry = new DbEntry();
newEntry.setDate(dateEntry);
values.put(SqliteHelperInstance.COLUMN_DATE, dateEntry);
values.put(SqliteHelperInstance.COLUMN_CIGCOUNT, newEntry.getCigNum());
database.insert(SqliteHelperInstance.TABLE_NAME, null, values);
}
}
else{
//its the first time that the application is loading
DbEntry newEntry = new DbEntry();
newEntry.setDate(dateEntry);
newEntry.setCignum(1);
values.put(SqliteHelperInstance.COLUMN_DATE, dateEntry);
values.put(SqliteHelperInstance.COLUMN_CIGCOUNT, newEntry.getCigNum());
Log.i(null, "values are set");
database.insert(SqliteHelperInstance.TABLE_NAME, null, values);
}
}
But when I run the application, I keep getting 0 row affected by the update function.I assume the comparison in the where clause is not returning any particular row. can anyone help me with this issue?
Try getting the lastDate like this:
String lastDate = cursor.getString(cursor.getColumnIndex(SqliteHelperInstance.COLUMN_DATE));
Also, you should use parameterized queries:
int i = database.update(SqliteHelperInstance.TABLE_NAME, values,SqliteHelperInstance.COLUMN_DATE + " = ?", new String[]{ lastDate });
Other than that, I'm not sure what could be wrong.
I'm working on a Searchable dictionary. Its Raw database is separated by "-" like
ColumnA(Key_Word) ColumnB(Key_defination)
Apple - One kind of Fruit
Mango - One fruit also
But I want to make it 3 column, (Column C will be Key_details)
ColumnA ColumnB ColumnC (Key_details)
Apple - One kind of Fruit - Round shape
Mango - One fruit also - Found in Bangladesh
When people search A, application will show Column B and C. The reason why i splited string is I want to show Coumn B and C on different window. How to do that? Here is my source-
/**
* Contains logic to return specific words from the dictionary, and
* load the dictionary table when it needs to be created.
*/
public class DictionaryDatabase {
private static final String TAG = "DictionaryDatabase";
//The columns we'll include in the dictionary table
public static final String KEY_WORD = SearchManager.SUGGEST_COLUMN_TEXT_1;
public static final String KEY_DEFINITION = SearchManager.SUGGEST_COLUMN_TEXT_2;
private static final String DATABASE_NAME = "dictionary";
private static final String FTS_VIRTUAL_TABLE = "FTSdictionary";
private static final int DATABASE_VERSION = 2;
private final DictionaryOpenHelper mDatabaseOpenHelper;
private static final HashMap<String,String> mColumnMap = buildColumnMap();
public DictionaryDatabase(Context context) {
mDatabaseOpenHelper = new DictionaryOpenHelper(context);
}
private static HashMap<String,String> buildColumnMap() {
HashMap<String,String> map = new HashMap<String,String>();
map.put(KEY_WORD, KEY_WORD);
map.put(KEY_DEFINITION, KEY_DEFINITION);
map.put(BaseColumns._ID, "rowid AS " +
BaseColumns._ID);
map.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID, "rowid AS " +
SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID);
map.put(SearchManager.SUGGEST_COLUMN_SHORTCUT_ID, "rowid AS " +
SearchManager.SUGGEST_COLUMN_SHORTCUT_ID);
return map;
}
public Cursor getWord(String rowId, String[] columns) {
String selection = "rowid = ?";
String[] selectionArgs = new String[] {rowId};
return query(selection, selectionArgs, columns);
}
public Cursor getWordMatches(String query, String[] columns) {
String selection = KEY_WORD + " MATCH ?";
String[] selectionArgs = new String[] {query+"*"};
return query(selection, selectionArgs, columns);
}
private Cursor query(String selection, String[] selectionArgs, String[] columns) {
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
builder.setTables(FTS_VIRTUAL_TABLE);
builder.setProjectionMap(mColumnMap);
Cursor cursor = builder.query(mDatabaseOpenHelper.getReadableDatabase(),
columns, selection, selectionArgs, null, null, null);
if (cursor == null) {
return null;
} else if (!cursor.moveToFirst()) {
cursor.close();
return null;
}
return cursor;
}
private static class DictionaryOpenHelper extends SQLiteOpenHelper {
private final Context mHelperContext;
private SQLiteDatabase mDatabase;
private static final String FTS_TABLE_CREATE =
"CREATE VIRTUAL TABLE " + FTS_VIRTUAL_TABLE +
" USING fts3 (" +
KEY_WORD + ", " +
KEY_DEFINITION + ");";
DictionaryOpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
mHelperContext = context;
}
#Override
public void onCreate(SQLiteDatabase db) {
mDatabase = db;
mDatabase.execSQL(FTS_TABLE_CREATE);
loadDictionary();
}
private void loadDictionary() {
new Thread(new Runnable() {
public void run() {
try {
loadWords();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}).start();
}
private void loadWords() throws IOException {
Log.d(TAG, "Loading words...");
final Resources resources = mHelperContext.getResources();
InputStream inputStream = resources.openRawResource(R.raw.definitions);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
String line;
while ((line = reader.readLine()) != null) {
String[] strings = TextUtils.split(line, "-");
if (strings.length < 2) continue;
long id = addWord(strings[0].trim(), strings[1].trim());
if (id < 0) {
Log.e(TAG, "unable to add word: " + strings[0].trim());
}
}
} finally {
reader.close();
}
Log.d(TAG, "DONE loading words.");
}
public long addWord(String word, String definition) {
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_WORD, word);
initialValues.put(KEY_DEFINITION, definition);
return mDatabase.insert(FTS_VIRTUAL_TABLE, null, initialValues);
}
#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 " + FTS_VIRTUAL_TABLE);
onCreate(db);
}
}
}
String[] arr = string.split("-");
String#split(String regex)
Returns the array of strings computed by splitting this string around
matches of the given regular expression.
EDIT:
long id = addWord(strings[0].trim(), strings[1].trim());
Above line should be:
long id = addWord(strings[0].trim(), strings[1].trim(),strings[2].trim());
And change your addWord function as I mentioned below.
public long addWord(String word, String definition,String details) {
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_WORD, word);
initialValues.put(KEY_DEFINITION, definition);
initialValues.put(KEY_DETAILS, details);
return mDatabase.insert(FTS_VIRTUAL_TABLE, null, initialValues);
}
A better way to handle the tokenization is by using StringTokenizer
StringTokenizer token = new StringTokenizer(str,"-");
To access the tokens,
while(token.hasNext())
{
String tmp = token.nextToken();
...
}
Currently my SQLite database is working great, I have read up on various methods such as this one to achieve this, though currently I am having issues with setting up the Date constructor and also how to define the data for use in putting it to the database (and getting it back!)
So far I have used static final String to define my data variables, notsure which is the correct way to use Date.
I'm not concerned with the time, just the date the entry was created.
Below is my java class:
import java.sql.Date;
import java.text.SimpleDateFormat;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class Stats {
public static final String KEY_ROWID = "_id";
public static final String KEY_WEIGHT = "weight";
public static final String KEY_WAIST = "waist";
public static final String KEY_CHEST = "chest";
public static final String KEY_LEGS = "legs";
public static final String KEY_ARMS = "arms";
public static final String KEY_DATE = "date";
private static final String DATABASE_NAME = "statsDB";
private static final String DATABASE_TABLE = "personalStats";
private static final int DATABASE_VERSION = 3;
private DbHelper ffHelper;
private final Context ffContext;
private SQLiteDatabase ffDatabase;
private static class DbHelper extends SQLiteOpenHelper {
public DbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" + KEY_ROWID
+ " INTEGER PRIMARY KEY AUTOINCREMENT, " + KEY_WEIGHT
+ " TEXT NOT NULL, " + KEY_WAIST + " TEXT NOT NULL, "
+ KEY_CHEST + " TEXT NOT NULL, " + KEY_LEGS
+ " TEXT NOT NULL, " + KEY_ARMS + " TEXT NOT NULL, "
+ KEY_DATE + " TEXT NOT NULL);");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
onCreate(db);
}
}
public Stats(Context c) {
ffContext = c;
}
public Stats open() throws SQLException {
ffHelper = new DbHelper(ffContext);
ffDatabase = ffHelper.getWritableDatabase();
return this;
}
public void close() {
ffHelper.close();
}
public long createEntry(String weight, String waist, String chest, String legs, String arms) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date();
ContentValues cv = new ContentValues();
cv.put(KEY_WEIGHT, weight);
cv.put(KEY_WAIST, waist);
cv.put(KEY_CHEST, chest);
cv.put(KEY_LEGS, legs);
cv.put(KEY_ARMS, arms);
cv.put("date_created", dateFormat.format(date));
return ffDatabase.insert(DATABASE_TABLE, null, cv);
}
public String getData() {
String[] columns = new String[] { KEY_ROWID, KEY_WEIGHT, KEY_WAIST, KEY_CHEST, KEY_LEGS, KEY_ARMS, KEY_DATE };
Cursor c = ffDatabase.query(DATABASE_TABLE, columns, null, null, null,
null, null);
String result = "";
int iRow = c.getColumnIndex(KEY_ROWID);
int iWeight = c.getColumnIndex(KEY_WEIGHT);
int iWaist = c.getColumnIndex(KEY_WAIST);
int iChest = c.getColumnIndex(KEY_CHEST);
int iLegs = c.getColumnIndex(KEY_LEGS);
int iArms = c.getColumnIndex(KEY_ARMS);
int iDate = c.getColumnIndex(KEY_DATE);
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
result = result + c.getString(iRow) + " " + c.getString(iWeight)
+ " " + c.getString(iWaist)
+ " " + c.getString(iChest)
+ " " + c.getString(iLegs)
+ " " + c.getString(iArms)
+ " " + c.getString(iDate)+ "\n";
}
return result;
}
}
Obviously any time Date is mentioned is where I have attempted to add this extra functionality.
You may put date like string in database, but this string must have good format.
For SQLite it is:
YYYY-MM-dd
YYYY-MM-dd hh:mm
YYYY-MM-dd hh:mm:ss
YYYY-MM-dd hh:mm:ss.sss
YYYY-MM-DDThh:mm
YYYY-MM-DDThh:mm:ss
YYYY-MM-DDThh:mm:ss.sss
hh:mm
hh:mm:ss
hh:mm:ss.sss
Like Yoann write you can convert date to string with:
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateForinsert = dateFormat(new GregorianCalendar(2013, GregorianCalendar.MAY, 5).getTime());
"Now" you can set with:
String dateForinsert = dateFormat(new GregorianCalendar().getTime());
Well i been fighting with this all yesterday and today, i got a simple SQLite insert that keeps returning a -1 as a return value, i read somewhere to change the primary key name to _id but made no change.
so here are the snaps op the code.
My constants for the fields:
//BALLS TABLE
public static final String BALLS_TABLE = "balls";
public static final String BALL_ID = "id";
public static final String BALL_USERID = "userId";
public static final String BALL_MODEL = "model";
public static final String BALL_BRAND = "brand";
public static final String BALL_SERIAL = "serial";
public static final String BALL_NOTES = "notes";
public static final String BALL_IMAGE = "image";
then on my createTables(SQLiteDatabase db) i got
//BALLS TABLE
db.execSQL(
"create table " + BALLS_TABLE +" (" +
BALL_ID + " integer primary key autoincrement not null," +
BALL_USERID + "integer not null," +
BALL_MODEL + " text not null," +
BALL_BRAND + " text not null," +
BALL_SERIAL + " text not null," +
BALL_NOTES + " text not null," +
BALL_IMAGE + " blob" +
");");
the creation of tables is working as i got other tables that are been populated.
and finally the whole ball Helper class
package com.kegel.android.bowlermanager.data;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
public class BallHelper {
private SQLiteDatabase database;
private ArrayList<Ball> currentBalls;
private Context context;
public BallHelper(Context context,SQLiteDatabase database)
{
this.context = context;
this.database = database;
loadBalls();
}
public ArrayList<Ball> getCurrentBalls() {
return currentBalls;
}
public Boolean BallExists(long id)
{
for (Ball ball : currentBalls)
{
if (ball.getId() == id)
return true;
}
return false;
}
public Boolean BallExists(Ball u)
{
for (Ball ball : currentBalls)
{
if (ball.getId() == u.getId())
return true;
}
return false;
}
public void updateBall(Ball b) {
assert(null != b);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] by = null;
if (b.getImage() != null )
{
Bitmap bmp = b.getImage();
bmp.compress(Bitmap.CompressFormat.PNG, 100, baos);
by = baos.toByteArray();
}
ContentValues values = new ContentValues();
values.put(SQLiteOpenDataHelper.BALL_USERID, 1);
values.put(SQLiteOpenDataHelper.BALL_MODEL, b.getModel());
values.put(SQLiteOpenDataHelper.BALL_BRAND , b.getBrand());
values.put(SQLiteOpenDataHelper.BALL_SERIAL , b.getSerial());
values.put(SQLiteOpenDataHelper.BALL_NOTES, b.getNotes());
values.put(SQLiteOpenDataHelper.BALL_IMAGE , by);
if (b.isValid())
{
if (b.getId() == 0)
{
b.setId(database.insert(SQLiteOpenDataHelper.BALLS_TABLE, null, values));
}
else
{
long id = b.getId();
String where = String.format("%s = %d", SQLiteOpenDataHelper.BALL_ID, id);
database.update(SQLiteOpenDataHelper.BALLS_TABLE, values, where, null);
}
loadBalls();
}
}
public void deleteBalls(Long id) {
String where = String.format("%s in (%s)", SQLiteOpenDataHelper.BALL_ID, id);
database.delete(SQLiteOpenDataHelper.BALLS_TABLE, where, null);
loadBalls();
}
public void deleteBalls(Ball u) {
String where = String.format("%s in (%s)", SQLiteOpenDataHelper.BALL_ID, u.getId());
database.delete(SQLiteOpenDataHelper.BALLS_TABLE, where, null);
loadBalls();
}
private void loadBalls() {
byte[] img = null;
currentBalls = new ArrayList<Ball>();
//try
//{
Cursor ballsCursor = database.query(SQLiteOpenDataHelper.BALLS_TABLE, new String[] {SQLiteOpenDataHelper.BALL_ID,SQLiteOpenDataHelper.USER_ID, SQLiteOpenDataHelper.BALL_MODEL, SQLiteOpenDataHelper.BALL_BRAND, SQLiteOpenDataHelper.BALL_SERIAL, SQLiteOpenDataHelper.BALL_NOTES, SQLiteOpenDataHelper.BALL_IMAGE}, null, null, null, null, null);
ballsCursor.moveToFirst();
Ball b;
if (! ballsCursor.isAfterLast()) {
do {
long id = ballsCursor.getInt(0);
long bowlerId = ballsCursor.getLong(1);
String model = ballsCursor.getString(2);
String brand = ballsCursor.getString(3);
String serial = ballsCursor.getString(4);
String notes = ballsCursor.getString(5);
img = ballsCursor.getBlob(6);
Bitmap bmp=BitmapFactory.decodeByteArray(img,0,img.length);
b = new Ball(context,bowlerId,model,brand,serial,notes);
b.setId(id);
b.setImage(bmp);
currentBalls.add(b);
} while (ballsCursor.moveToNext());
}
ballsCursor.close();
}
}
A second pair of eyes here will come handy! so if anyone can spot anything here, or let me know if I'm missing something i will really appreciate it. I already checked the values on b ( is even passing my internal validation ) but and insertion like this will fail:
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.fake_pofile);
Ball ball = new Ball(this,1, "Test", "Test", "", "");
ball.setImage(bm);
mHelper.updateBall(ball);
Well... as i didn't, nobody else noted on the code for the table creation, between the field BALL_USERID i wasn't leaving a space so it was a whole word, funny thing that db.exec is supposed to throw exceptions but in this case didn't and accepted a strange name as a field with no type and created the table with no field "userId" but "useridinteger" with no type ( is there a default type if you don't set one?? )
Sometimes are just those litte things that can make you go nuts.
I know this is an old example, but for anyone looking for an Objective C sample, this is good. However, be sure to put the sqlite3_reset(statement) lines BEFORE the return statements. Otherwise, the code only works on the first save or find.