I am developing a song book app and I have the following files:
SbDatabase.java for creating a database
SbProvider.java for creating a provider service to access the song
Searchable.java for searching the for songs
Song.java for showing one song that is picked from a listview of results
I need help to create an action that would allow a user switch to another song either ahead of before the current song being viewed. Here are my codes
1.SbDatabase.java
public class SbDatabase {
private static final String TAG = "SbDatabase";
public static final String KEY_WORD = SearchManager.SUGGEST_COLUMN_TEXT_1;
public static final String KEY_SONGCONT = SearchManager.SUGGEST_COLUMN_TEXT_2;
private static final String DATABASE_NAME = "songbook";
private static final String FTS_VIRTUAL_TABLE = "FTSsongbook";
private static final int DATABASE_VERSION = 2;
private final SongbookOpenHelper mDatabaseOpenHelper;
private static final HashMap<String,String> mColumnMap = buildColumnMap();
public SbDatabase(Context context) {
mDatabaseOpenHelper = new SongbookOpenHelper(context);
}
private static HashMap<String,String> buildColumnMap() {
HashMap<String,String> map = new HashMap<String,String>();
map.put(KEY_WORD, KEY_WORD);
map.put(KEY_SONGCONT, KEY_SONGCONT);
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;
}
/**
* Returns a Cursor positioned at the song specified by rowId
*
* #param rowId id of song to retrieve
* #param columns The columns to include, if null then all are included
* #return Cursor positioned to matching song, or null if not found.
*/
public Cursor getSong(String rowId, String[] columns) {
String selection = "rowid = ?";
String[] selectionArgs = new String[] {rowId};
return query(selection, selectionArgs, columns);
/* This builds a query that looks like:
* SELECT <columns> FROM <table> WHERE rowid = <rowId>
*/
}
/**
* Returns a Cursor over all songs that match the given query
*
* #param query The string to search for
* #param columns The columns to include, if null then all are included
* #return Cursor over all songs that match, or null if none found.
*/
public Cursor getSongMatches(String query, String[] columns) {
String selection = KEY_WORD + " MATCH ?";
String[] selectionArgs = new String[] {query+"*"};
return query(selection, selectionArgs, columns);
/* This builds a query that looks like:
* SELECT <columns> FROM <table> WHERE <KEY_WORD> MATCH 'query*'
* which is an FTS3 search for the query text (plus a wildcard) inside the song column.
*
* - "rowid" is the unique id for all rows but we need this value for the "_id" column in
* order for the Adapters to work, so the columns need to make "_id" an alias for "rowid"
* - "rowid" also needs to be used by the SUGGEST_COLUMN_INTENT_DATA alias in order
* for suggestions to carry the proper intent data.
* These aliases are defined in the SbProvider when queries are made.
* - This can be revised to also search the songcont text with FTS3 by changing
* the selection clause to use FTS_VIRTUAL_TABLE instead of KEY_WORD (to search across
* the entire table, but sorting the relevance could be difficult.
*/
}
/**
* Performs a database query.
* #param selection The selection clause
* #param selectionArgs Selection arguments for "?" components in the selection
* #param columns The columns to return
* #return A Cursor over all rows matching the query
*/
private Cursor query(String selection, String[] selectionArgs, String[] columns) {
/* The SQLiteBuilder provides a map for all possible columns requested to
* actual columns in the database, creating a simple column alias mechanism
* by which the ContentProvider does not need to know the real column names
*/
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;
}
/**
* This creates/opens the database.
*/
private static class SongbookOpenHelper extends SQLiteOpenHelper {
private final Context mHelperContext;
private SQLiteDatabase mDatabase;
/* Note that FTS3 does not support column constraints and thus, you cannot
* declare a primary key. However, "rowid" is automatically used as a unique
* identifier, so when making requests, we will use "_id" as an alias for "rowid"
*/
private static final String FTS_TABLE_CREATE =
"CREATE VIRTUAL TABLE " + FTS_VIRTUAL_TABLE +
" USING fts3 (" +
KEY_WORD + ", " +
KEY_SONGCONT + ");";
SongbookOpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
mHelperContext = context;
}
#Override
public void onCreate(SQLiteDatabase db) {
mDatabase = db;
mDatabase.execSQL(FTS_TABLE_CREATE);
loadSongbook();
}
/**
* Starts a thread to load the database table with songs
*/
private void loadSongbook() {
new Thread(new Runnable() {
public void run() {
try {
loadSongs();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}).start();
}
private void loadSongs() throws IOException {
Log.d(TAG, "Loading songs...");
final Resources resources = mHelperContext.getResources();
InputStream inputStream = resources.openRawResource(R.raw.songbook);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
String line;
String thesong;
while ((line = reader.readLine()) != null) {
thesong = line.replace("$", System.getProperty("line.separator"));
String[] strings = TextUtils.split(thesong, "%");
if (strings.length < 2) continue;
long id = addSong(strings[0].trim(), strings[1].trim());
if (id < 0) {
Log.e(TAG, "unable to add song: " + strings[0].trim());
}
}
} finally {
reader.close();
}
Log.d(TAG, "DONE loading songs.");
}
public long addSong(String song, String songcont) {
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_WORD, song);
initialValues.put(KEY_SONGCONT, songcont);
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);
}
}
SbProvider.java
public SbDatabase(Context context) {
mDatabaseOpenHelper = new SongbookOpenHelper(context);
}
private static HashMap<String,String> buildColumnMap() {
HashMap<String,String> map = new HashMap<String,String>();
map.put(KEY_WORD, KEY_WORD);
map.put(KEY_SONGCONT, KEY_SONGCONT);
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;
}
/**
* Returns a Cursor positioned at the song specified by rowId
*
* #param rowId id of song to retrieve
* #param columns The columns to include, if null then all are included
* #return Cursor positioned to matching song, or null if not found.
*/
public Cursor getSong(String rowId, String[] columns) {
String selection = "rowid = ?";
String[] selectionArgs = new String[] {rowId};
return query(selection, selectionArgs, columns);
/* This builds a query that looks like:
* SELECT <columns> FROM <table> WHERE rowid = <rowId>
*/
}
/**
* Returns a Cursor over all songs that match the given query
*
* #param query The string to search for
* #param columns The columns to include, if null then all are included
* #return Cursor over all songs that match, or null if none found.
*/
public Cursor getSongMatches(String query, String[] columns) {
String selection = KEY_WORD + " MATCH ?";
String[] selectionArgs = new String[] {query+"*"};
return query(selection, selectionArgs, columns);
/* This builds a query that looks like:
* SELECT <columns> FROM <table> WHERE <KEY_WORD> MATCH 'query*'
* which is an FTS3 search for the query text (plus a wildcard) inside the song column.
*
* - "rowid" is the unique id for all rows but we need this value for the "_id" column in
* order for the Adapters to work, so the columns need to make "_id" an alias for "rowid"
* - "rowid" also needs to be used by the SUGGEST_COLUMN_INTENT_DATA alias in order
* for suggestions to carry the proper intent data.
* These aliases are defined in the SbProvider when queries are made.
* - This can be revised to also search the songcont text with FTS3 by changing
* the selection clause to use FTS_VIRTUAL_TABLE instead of KEY_WORD (to search across
* the entire table, but sorting the relevance could be difficult.
*/
}
/**
* Performs a database query.
* #param selection The selection clause
* #param selectionArgs Selection arguments for "?" components in the selection
* #param columns The columns to return
* #return A Cursor over all rows matching the query
*/
private Cursor query(String selection, String[] selectionArgs, String[] columns) {
/* The SQLiteBuilder provides a map for all possible columns requested to
* actual columns in the database, creating a simple column alias mechanism
* by which the ContentProvider does not need to know the real column names
*/
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;
}
/**
* This creates/opens the database.
*/
private static class SongbookOpenHelper extends SQLiteOpenHelper {
private final Context mHelperContext;
private SQLiteDatabase mDatabase;
/* Note that FTS3 does not support column constraints and thus, you cannot
* declare a primary key. However, "rowid" is automatically used as a unique
* identifier, so when making requests, we will use "_id" as an alias for "rowid"
*/
private static final String FTS_TABLE_CREATE =
"CREATE VIRTUAL TABLE " + FTS_VIRTUAL_TABLE +
" USING fts3 (" +
KEY_WORD + ", " +
KEY_SONGCONT + ");";
SongbookOpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
mHelperContext = context;
}
#Override
public void onCreate(SQLiteDatabase db) {
mDatabase = db;
mDatabase.execSQL(FTS_TABLE_CREATE);
loadSongbook();
}
/**
* Starts a thread to load the database table with songs
*/
private void loadSongbook() {
new Thread(new Runnable() {
public void run() {
try {
loadSongs();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}).start();
}
private void loadSongs() throws IOException {
Log.d(TAG, "Loading songs...");
final Resources resources = mHelperContext.getResources();
InputStream inputStream = resources.openRawResource(R.raw.songbook);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
String line;
String thesong;
while ((line = reader.readLine()) != null) {
thesong = line.replace("$", System.getProperty("line.separator"));
String[] strings = TextUtils.split(thesong, "%");
if (strings.length < 2) continue;
long id = addSong(strings[0].trim(), strings[1].trim());
if (id < 0) {
Log.e(TAG, "unable to add song: " + strings[0].trim());
}
}
} finally {
reader.close();
}
Log.d(TAG, "DONE loading songs.");
}
public long addSong(String song, String songcont) {
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_WORD, song);
initialValues.put(KEY_SONGCONT, songcont);
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);
}
}
Searchable.java
public class Searchable extends ActionBarActivity {
private TextView mTextView;
private ListView mListView;
LinearLayout MySong;
#SuppressWarnings("deprecation")
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.search);
mTextView = (TextView) findViewById(R.id.text);
mListView = (ListView) findViewById(R.id.list);
handleIntent(getIntent());
Cursor cursor = managedQuery(SbProvider.CONTENT_URI, null, null,
new String[] {"Lotv"}, null);
String[] from = new String[] { SbDatabase.KEY_WORD,
SbDatabase.KEY_SONGCONT };
int[] to = new int[] { R.id.song, R.id.songcont };
SimpleCursorAdapter songs = new SimpleCursorAdapter(this,
R.layout.result, cursor, from, to);
mListView.setAdapter(songs);
mListView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent songIntent = new Intent(getApplicationContext(), Song.class);
Uri data = Uri.withAppendedPath(SbProvider.CONTENT_URI,
String.valueOf(id));
songIntent.setData(data);
startActivity(songIntent);
}
});
mTextView.setText("568 Songs of Worship!");
}
#Override
protected void onNewIntent(Intent intent) {
handleIntent(intent);
}
private void handleIntent(Intent intent) {
if (Intent.ACTION_VIEW.equals(intent.getAction())) {
Intent songIntent = new Intent(this, Song.class);
songIntent.setData(intent.getData());
startActivity(songIntent);
} else if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
showResults(query);
}
}
private void showResults(String query) {
Cursor cursor = managedQuery(SbProvider.CONTENT_URI, null, null,
new String[] {query}, null);
String[] from = new String[] { SbDatabase.KEY_WORD,
SbDatabase.KEY_SONGCONT };
int[] to = new int[] { R.id.song,
R.id.songcont };
SimpleCursorAdapter songs = new SimpleCursorAdapter(this,
R.layout.result, cursor, from, to);
mListView.setAdapter(songs);
mListView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent songIntent = new Intent(getApplicationContext(), Song.class);
Uri data = Uri.withAppendedPath(SbProvider.CONTENT_URI,
String.valueOf(id));
songIntent.setData(data);
startActivity(songIntent);
}
});
if (cursor == null) {
mTextView.setText(getString(R.string.no_songs, new Object[] {query}));
} else {
int count = cursor.getCount();
String countString = getResources().getQuantityString(R.plurals.search_results,
count, new Object[] {count, query});
mTextView.setText(countString);
}
}
}
}
Song.java is where I need you help to fix a button to allow a user go to another song on the ImageButton Next
public class Song extends ActionBarActivity {
RelativeLayout MySong;
TextView songcont;
private ImageButton Previous;
private ImageButton Next;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.song);
Uri uri = getIntent().getData();
Cursor cursor = managedQuery(uri, null, null, null, null);
if (cursor == null) {
finish();
} else {
cursor.moveToFirst();
TextView songcont = (TextView) findViewById(R.id.songcont);
songcont.setMovementMethod(new ScrollingMovementMethod());
int wIndex = cursor.getColumnIndexOrThrow(SbDatabase.KEY_WORD);
int dIndex = cursor.getColumnIndexOrThrow(SbDatabase.KEY_SONGCONT);
setTitle(cursor.getString(wIndex));
songcont.setText(cursor.getString(dIndex));
Previous = (ImageButton)findViewById (R.id.imageButton1 );
Next = (ImageButton)findViewById (R.id.imageButton2 );
Next.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
Intent songIntent = new Intent(getApplicationContext(), Song.class);
//Uri data = Uri.withAppendedPath(SbProvider.CONTENT_URI, String.valueOf(id));
Uri data = Uri.withAppendedPath(SbProvider.CONTENT_URI, String.valueOf(id));
songIntent.setData(data);
startActivity(songIntent);
}
});
} } }
This code can work for you
public class Song extends ActionBarActivity {
TextView songcont;
private SbDatabase mSongbook;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.song);
Uri uri = getIntent().getData();
Cursor cursor = managedQuery(uri, null, null, null, null);
cursor.moveToFirst();
TextView songcont = (TextView) findViewById(R.id.songcont);
songcont.setMovementMethod(new ScrollingMovementMethod());
int wIndex = cursor.getColumnIndexOrThrow(SbDatabase.KEY_WORD);
int dIndex = cursor.getColumnIndexOrThrow(SbDatabase.KEY_SONGCONT);
String thetitle = (cursor.getString(wIndex));
songcont.setText(cursor.getString(dIndex));
setTitle(thetitle.replace("#", ""));
Previous = (ImageButton)findViewById (R.id.imageButton1 );
Previous.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
Uri uri = getIntent().getData();
Cursor cursor = managedQuery(uri, null, null, null, null);
cursor.moveToFirst();
int wIndex = cursor.getColumnIndexOrThrow(SbDatabase.KEY_WORD);
String Title = (cursor.getString(wIndex));
String[] strings = TextUtils.split(Title, "#");
String MyTitle = strings[0].trim();
int id = Integer.parseInt(MyTitle);
Uri data = Uri.withAppendedPath(SbProvider.CONTENT_URI, String.valueOf(id-1));
Intent songIntent = new Intent(getApplicationContext(), Song.class);
songIntent.setData(data);
startActivity(songIntent);
}
});
Next = (ImageButton)findViewById (R.id.imageButton2 );
Next.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
Uri uri = getIntent().getData();
Cursor cursor = managedQuery(uri, null, null, null, null);
cursor.moveToFirst();
int wIndex = cursor.getColumnIndexOrThrow(SbDatabase.KEY_WORD);
String Title = (cursor.getString(wIndex));
String[] strings = TextUtils.split(Title, "#");
String MyTitle = strings[0].trim();
int id = Integer.parseInt(MyTitle);
Uri data = Uri.withAppendedPath(SbProvider.CONTENT_URI, String.valueOf(id+1));
Intent songIntent = new Intent(getApplicationContext(), Song.class);
songIntent.setData(data);
startActivity(songIntent);
}
});
detector = new SimpleGestureFilter(this,this);
}
Here is what worked for me:
public class Song extends ActionBarActivity {
TextView songcont;
private SbDatabase mSongbook;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.song);
Uri uri = getIntent().getData();
Cursor cursor = managedQuery(uri, null, null, null, null);
cursor.moveToFirst();
TextView songcont = (TextView) findViewById(R.id.songcont);
songcont.setMovementMethod(new ScrollingMovementMethod());
int wIndex = cursor.getColumnIndexOrThrow(SbDatabase.KEY_WORD);
int dIndex = cursor.getColumnIndexOrThrow(SbDatabase.KEY_SONGCONT);
String thetitle = (cursor.getString(wIndex));
songcont.setText(cursor.getString(dIndex));
setTitle(thetitle.replace("#", ""));
Previous = (ImageButton)findViewById (R.id.imageButton1 );
Previous.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
Uri uri = getIntent().getData();
Cursor cursor = managedQuery(uri, null, null, null, null);
cursor.moveToFirst();
int wIndex = cursor.getColumnIndexOrThrow(SbDatabase.KEY_WORD);
String Title = (cursor.getString(wIndex));
String[] strings = TextUtils.split(Title, "#");
String MyTitle = strings[0].trim();
int id = Integer.parseInt(MyTitle);
Uri data = Uri.withAppendedPath(SbProvider.CONTENT_URI, String.valueOf(id-1));
Intent songIntent = new Intent(getApplicationContext(), Song.class);
songIntent.setData(data);
startActivity(songIntent);
}
});
Next = (ImageButton)findViewById (R.id.imageButton2 );
Next.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
Uri uri = getIntent().getData();
Cursor cursor = managedQuery(uri, null, null, null, null);
cursor.moveToFirst();
int wIndex = cursor.getColumnIndexOrThrow(SbDatabase.KEY_WORD);
String Title = (cursor.getString(wIndex));
String[] strings = TextUtils.split(Title, "#");
String MyTitle = strings[0].trim();
int id = Integer.parseInt(MyTitle);
Uri data = Uri.withAppendedPath(SbProvider.CONTENT_URI, String.valueOf(id+1));
Intent songIntent = new Intent(getApplicationContext(), Song.class);
songIntent.setData(data);
startActivity(songIntent);
}
});
detector = new SimpleGestureFilter(this,this);
}
In Song class add dowhile loop Then call moveToNext() to move next record in database .
do
{
} while (cur.moveToNext());
Related
hi I want to remove(delete) an item from listview from a second activity which I previously saved from another activity. I found similar question on deleting row from database but I think there is a little bit change in my database and the one's given in other questions and answers. here is my code.
the activity from where I am saving and deleting the row. here I want to delete the row from listview.
case R.id.id_favorit:
// Add it to the DB and re-draw the ListView
myDb.insertRow("Atherosclerosis", 0, "");
Toast.makeText(getApplicationContext(), "Item Added to favorite list!", Toast.LENGTH_SHORT).show();
favClicked=true;
editor.putBoolean("menu_item", favClicked);
editor.commit();
invalidateOptionsMenu();
return true;
case R.id.id_favorit2:
myDb.deleteRow(??);
Toast.makeText(getApplicationContext(), "Item deleted from favorite list!", Toast.LENGTH_SHORT).show();
favClicked=false;
editor.putBoolean("menu_item", favClicked);
editor.commit();
invalidateOptionsMenu();
return super.onOptionsItemSelected(item);
}
return true;
}
here is my database
public class DBAdapter {
/////////////////////////////////////////////////////////////////////
// Constants & Data
/////////////////////////////////////////////////////////////////////
// For logging:
private static final String TAG = "DBAdapter";
// DB Fields
public static final String KEY_ROWID = "_id";
public static final int COL_ROWID = 0;
/*
* CHANGE 1:
*/
// TODO: Setup your fields here:
public static final String KEY_NAME = "name";
public static final String KEY_STUDENTNUM = "studentnum";
public static final String KEY_FAVCOLOUR = "favcolour";
// TODO: Setup your field numbers here (0 = KEY_ROWID, 1=...)
public static final int COL_NAME = 1;
public static final int COL_STUDENTNUM = 2;
public static final int COL_FAVCOLOUR = 3;
public static final String[] ALL_KEYS = new String[] {KEY_ROWID, KEY_NAME, KEY_STUDENTNUM, KEY_FAVCOLOUR};
// DB info: it's name, and the table we are using (just one).
public static final String DATABASE_NAME = "MyDb";
public static final String DATABASE_TABLE = "mainTable";
// Track DB version if a new version of your app changes the format.
public static final int DATABASE_VERSION = 2;
private static final String DATABASE_CREATE_SQL =
"create table " + DATABASE_TABLE
+ " (" + KEY_ROWID + " integer primary key autoincrement, "
/*
* CHANGE 2:
*/
// TODO: Place your fields here!
// + KEY_{...} + " {type} not null"
// - Key is the column name you created above.
// - {type} is one of: text, integer, real, blob
// (http://www.sqlite.org/datatype3.html)
// - "not null" means it is a required field (must be given a value).
// NOTE: All must be comma separated (end of line!) Last one must have NO comma!!
+ KEY_NAME + " text not null, "
+ KEY_STUDENTNUM + " integer not null, "
+ KEY_FAVCOLOUR + " string not null"
// Rest of creation:
+ ");";
// Context of application who uses us.
private final Context context;
private DatabaseHelper myDBHelper;
private SQLiteDatabase db;
/////////////////////////////////////////////////////////////////////
// Public methods:
/////////////////////////////////////////////////////////////////////
public DBAdapter(Context ctx) {
this.context = ctx;
myDBHelper = new DatabaseHelper(context);
}
// Open the database connection.
public DBAdapter open() {
db = myDBHelper.getWritableDatabase();
return this;
}
// Close the database connection.
public void close() {
myDBHelper.close();
}
// Add a new set of values to the database.
#SuppressLint("NewApi")
public long insertRow(String name, int studentNum, String favColour) {
Cursor c= db.query(true, DATABASE_TABLE, ALL_KEYS, KEY_NAME + "='" + name +"'", null, null, null, null, null, null);
if(c.getCount()>0){
return -1;
}
c.close();
/*
* CHANGE 3:
*/
// TODO: Update data in the row with new fields.
// TODO: Also change the function's arguments to be what you need!
// Create row's data:
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_NAME, name);
initialValues.put(KEY_STUDENTNUM, studentNum);
initialValues.put(KEY_FAVCOLOUR, favColour);
// Insert it into the database.
return db.insert(DATABASE_TABLE, null, initialValues);
}
// Delete a row from the database, by rowId (primary key)
public boolean deleteRow(long rowId) {
String where = KEY_ROWID + "=" + rowId;
return db.delete(DATABASE_TABLE, where, null) != 0;
}
public void deleteAll() {
Cursor c = getAllRows();
long rowId = c.getColumnIndexOrThrow(KEY_ROWID);
if (c.moveToFirst()) {
do {
deleteRow(c.getLong((int) rowId));
} while (c.moveToNext());
}
c.close();
}
// Return all data in the database.
#SuppressLint("NewApi")
public Cursor getAllRows() {
String where = null;
Cursor c = db.query(true, DATABASE_TABLE, ALL_KEYS,
where, null, null, null, KEY_ROWID + " DESC", null, null);
if (c != null) {
c.moveToFirst();
}
return c;
}
// Get a specific row (by rowId)
public Cursor getRow(long rowId) {
String where = KEY_ROWID + "=" + rowId;
Cursor c = db.query(true, DATABASE_TABLE, ALL_KEYS,
where, null, null, null, null, null);
if (c != null) {
c.moveToFirst();
}
return c;
}
// Change an existing row to be equal to new data.
public boolean updateRow(long rowId, String name, int studentNum, String favColour) {
String where = KEY_ROWID + "=" + rowId;
/*
* CHANGE 4:
*/
// TODO: Update data in the row with new fields.
// TODO: Also change the function's arguments to be what you need!
// Create row's data:
ContentValues newValues = new ContentValues();
newValues.put(KEY_NAME, name);
newValues.put(KEY_STUDENTNUM, studentNum);
newValues.put(KEY_FAVCOLOUR, favColour);
// Insert it into the database.
return db.update(DATABASE_TABLE, newValues, where, null) != 0;
}
/////////////////////////////////////////////////////////////////////
// Private Helper Classes:
/////////////////////////////////////////////////////////////////////
/**
* Private class which handles database creation and upgrading.
* Used to handle low-level database access.
*/
private static class DatabaseHelper extends SQLiteOpenHelper
{
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase _db) {
_db.execSQL(DATABASE_CREATE_SQL);
}
#Override
public void onUpgrade(SQLiteDatabase _db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading application's database from version " + oldVersion
+ " to " + newVersion + ", which will destroy all old data!");
// Destroy old database:
_db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
// Recreate new database:
onCreate(_db);
}
}
}
and now my listview another activity
private void populateListViewFromDB() {
Cursor cursor = myDb.getAllRows();
// Allow activity to manage lifetime of the cursor.
// DEPRECATED! Runs on the UI thread, OK for small/short queries.
startManagingCursor(cursor);
// Setup mapping from cursor to view fields:
String[] fromFieldNames = new String[]
{DBAdapter.KEY_NAME, DBAdapter.KEY_STUDENTNUM};
int[] toViewIDs = new int[]
{R.id.item_name};
// Create adapter to may columns of the DB onto elemesnt in the UI.
SimpleCursorAdapter myCursorAdapter =
new SimpleCursorAdapter(
this, // Context
R.layout.item_layout, // Row layout template
cursor, // cursor (set of DB records to map)
fromFieldNames, // DB Column names
toViewIDs // View IDs to put information in
);
// Set the adapter for the list view
ListView myList = (ListView) findViewById(R.id.favlistView1);
myList.setAdapter(myCursorAdapter);
}
private void registerListClickCallback() {
ListView myList = (ListView) findViewById(R.id.favlistView1);
//This code is for to delete the single item from the listview of favorite list
myList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
int arg2, final long arg3) {
Cursor cursor = myDb.getRow(arg3);
if (cursor.moveToFirst()) {
new AlertDialog.Builder(FavoriteDiseases.this)
.setTitle("Delete Item")
.setMessage("Do you want to delete this disease?")
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// continue with delete
myDb.deleteRow(arg3);
populateListViewFromDB();
}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// do nothing
}
})
.show();
}
return true;
}
});
If you use LoaderManager and CursorLoader to load your data from the database, it will update the cursor, and you can update your ListView automatically when the database changes. Here is a link: Loaders
Hi Stackoverflow members i created an app where user can add favorite items to the favorite list. but the problem i am facing is that when i click on add to favorite button, the item adds to the bottom of the list and not on the top.
Second when i click the same item add to favorite item many time, this add the item multiple time and not just only one time. how can i add it to the list just only one time and not multiple time.
here is my code for activity and database.
My DBAdapter.class
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
// TO USE:
// Change the package (at top) to match your project.
// Search for "TODO", and make the appropriate changes.
public class DBAdapter {
/////////////////////////////////////////////////////////////////////
// Constants & Data
/////////////////////////////////////////////////////////////////////
// For logging:
private static final String TAG = "DBAdapter";
// DB Fields
public static final String KEY_ROWID = "_id";
public static final int COL_ROWID = 0;
/*
* CHANGE 1:
*/
// TODO: Setup your fields here:
public static final String KEY_NAME = "name";
public static final String KEY_STUDENTNUM = "studentnum";
public static final String KEY_FAVCOLOUR = "favcolour";
// TODO: Setup your field numbers here (0 = KEY_ROWID, 1=...)
public static final int COL_NAME = 1;
public static final int COL_STUDENTNUM = 2;
public static final int COL_FAVCOLOUR = 3;
public static final String[] ALL_KEYS = new String[] {KEY_ROWID, KEY_NAME, KEY_STUDENTNUM, KEY_FAVCOLOUR};
// DB info: it's name, and the table we are using (just one).
public static final String DATABASE_NAME = "MyDb";
public static final String DATABASE_TABLE = "mainTable";
// Track DB version if a new version of your app changes the format.
public static final int DATABASE_VERSION = 2;
private static final String DATABASE_CREATE_SQL =
"create table " + DATABASE_TABLE
+ " (" + KEY_ROWID + " integer primary key autoincrement, "
/*
* CHANGE 2:
*/
// TODO: Place your fields here!
// + KEY_{...} + " {type} not null"
// - Key is the column name you created above.
// - {type} is one of: text, integer, real, blob
// (http://www.sqlite.org/datatype3.html)
// - "not null" means it is a required field (must be given a value).
// NOTE: All must be comma separated (end of line!) Last one must have NO comma!!
+ KEY_NAME + " text not null, "
+ KEY_STUDENTNUM + " integer not null, "
+ KEY_FAVCOLOUR + " string not null"
// Rest of creation:
+ ");";
// Context of application who uses us.
private final Context context;
private DatabaseHelper myDBHelper;
private SQLiteDatabase db;
/////////////////////////////////////////////////////////////////////
// Public methods:
/////////////////////////////////////////////////////////////////////
public DBAdapter(Context ctx) {
this.context = ctx;
myDBHelper = new DatabaseHelper(context);
}
// Open the database connection.
public DBAdapter open() {
db = myDBHelper.getWritableDatabase();
return this;
}
// Close the database connection.
public void close() {
myDBHelper.close();
}
// Add a new set of values to the database.
public long insertRow(String name, int studentNum, String favColour) {
/*
* CHANGE 3:
*/
// TODO: Update data in the row with new fields.
// TODO: Also change the function's arguments to be what you need!
// Create row's data:
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_NAME, name);
initialValues.put(KEY_STUDENTNUM, studentNum);
initialValues.put(KEY_FAVCOLOUR, favColour);
// Insert it into the database.
return db.insert(DATABASE_TABLE, null, initialValues);
}
// Delete a row from the database, by rowId (primary key)
public boolean deleteRow(long rowId) {
String where = KEY_ROWID + "=" + rowId;
return db.delete(DATABASE_TABLE, where, null) != 0;
}
public void deleteAll() {
Cursor c = getAllRows();
long rowId = c.getColumnIndexOrThrow(KEY_ROWID);
if (c.moveToFirst()) {
do {
deleteRow(c.getLong((int) rowId));
} while (c.moveToNext());
}
c.close();
}
// Return all data in the database.
public Cursor getAllRows() {
String where = null;
Cursor c = db.query(true, DATABASE_TABLE, ALL_KEYS,
where, null, null, null, null, null);
if (c != null) {
c.moveToFirst();
}
return c;
}
// Get a specific row (by rowId)
public Cursor getRow(long rowId) {
String where = KEY_ROWID + "=" + rowId;
Cursor c = db.query(true, DATABASE_TABLE, ALL_KEYS,
where, null, null, null, null, null);
if (c != null) {
c.moveToFirst();
}
return c;
}
// Change an existing row to be equal to new data.
public boolean updateRow(long rowId, String name, int studentNum, String favColour) {
String where = KEY_ROWID + "=" + rowId;
/*
* CHANGE 4:
*/
// TODO: Update data in the row with new fields.
// TODO: Also change the function's arguments to be what you need!
// Create row's data:
ContentValues newValues = new ContentValues();
newValues.put(KEY_NAME, name);
newValues.put(KEY_STUDENTNUM, studentNum);
newValues.put(KEY_FAVCOLOUR, favColour);
// Insert it into the database.
return db.update(DATABASE_TABLE, newValues, where, null) != 0;
}
/////////////////////////////////////////////////////////////////////
// Private Helper Classes:
/////////////////////////////////////////////////////////////////////
/**
* Private class which handles database creation and upgrading.
* Used to handle low-level database access.
*/
private static class DatabaseHelper extends SQLiteOpenHelper
{
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase _db) {
_db.execSQL(DATABASE_CREATE_SQL);
}
#Override
public void onUpgrade(SQLiteDatabase _db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading application's database from version " + oldVersion
+ " to " + newVersion + ", which will destroy all old data!");
// Destroy old database:
_db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
// Recreate new database:
onCreate(_db);
}
}
}
My favorite list activity..
DBAdapter myDb;
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.favoritediseases);
openDB();
populateListViewFromDB();
registerListClickCallback();
// this code is used for the action bar color change//
ActionBar bar = getActionBar();
bar.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#6B8E23")));
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
}
#Override
protected void onDestroy() {
super.onDestroy();
closeDB();
}
private void openDB() {
myDb = new DBAdapter(this);
myDb.open();
}
private void closeDB() {
myDb.close();
}
/*
* UI Button Callbacks
*/
private void populateListViewFromDB() {
Cursor cursor = myDb.getAllRows();
// Allow activity to manage lifetime of the cursor.
// DEPRECATED! Runs on the UI thread, OK for small/short queries.
startManagingCursor(cursor);
// Setup mapping from cursor to view fields:
String[] fromFieldNames = new String[]
{DBAdapter.KEY_NAME, DBAdapter.KEY_STUDENTNUM};
int[] toViewIDs = new int[]
{R.id.item_name};
// Create adapter to may columns of the DB onto elemesnt in the UI.
SimpleCursorAdapter myCursorAdapter =
new SimpleCursorAdapter(
this, // Context
R.layout.item_layout, // Row layout template
cursor, // cursor (set of DB records to map)
fromFieldNames, // DB Column names
toViewIDs // View IDs to put information in
);
// Set the adapter for the list view
ListView myList = (ListView) findViewById(R.id.favlistView1);
myList.setAdapter(myCursorAdapter);
}
private void registerListClickCallback() {
ListView myList = (ListView) findViewById(R.id.favlistView1);
//This code is for to delete the single item from the listview of favorite list
myList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
int arg2, final long arg3) {
Cursor cursor = myDb.getRow(arg3);
if (cursor.moveToFirst()) {
new AlertDialog.Builder(FavoriteDiseases.this)
.setTitle("Delete Item")
.setMessage("Do you want to delete this disease?")
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// continue with delete
myDb.deleteRow(arg3);
populateListViewFromDB();
}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// do nothing
}
})
.show();
}
return true;
}
});
//this is the code used from starting activity from the favorite list database.
myList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View viewClicked,
int position, long idInDB) {
Cursor cursor = myDb.getRow(idInDB);
if (cursor.moveToFirst()) {
String name = cursor.getString(DBAdapter.COL_NAME);
if (name.equals("Atherosclerosis")){
startActivity(new Intent(FavoriteDiseases.this,Atherosclerosis.class));
}else if
(name.equals("Coronary Heart Disease")){
startActivity(new Intent(FavoriteDiseases.this,CoronaryHeartDisease.class));
}else if (name.equals("Stable Angina")){
startActivity(new Intent(FavoriteDiseases.this,StableAngina.class));
}else if (name.equals("Acute Coronary Syndrome")){
startActivity(new Intent(FavoriteDiseases.this,AcuteCoronarySyndrome.class));
}else if (name.equals("Myocardial Infarction")){
startActivity(new Intent(FavoriteDiseases.this,MyocardialInfarction.class));
}else if (name.equals("Unstable Angina")){
startActivity(new Intent(FavoriteDiseases.this,UnstableAngina.class));
}else if (name.equals("Acute Heart Failure")){
startActivity(new Intent(FavoriteDiseases.this,AcuteHeartFailure.class));
}
}
cursor.close();
updateItemForId(idInDB);
}
});}
private void updateItemForId(long idInDB) {
Cursor cursor = myDb.getRow(idInDB);
if (cursor.moveToFirst()) {
cursor.getLong(DBAdapter.COL_ROWID);
String name = cursor.getString(DBAdapter.COL_NAME);
int studentNum = cursor.getInt(DBAdapter.COL_STUDENTNUM);
String favColour = cursor.getString(DBAdapter.COL_FAVCOLOUR);
favColour += "!";
myDb.updateRow(idInDB, name, studentNum, favColour);
}
cursor.close();
populateListViewFromDB();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.favorite_diseases, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Take appropriate action for each action item click
switch (item.getItemId()) {
case R.id.action_clear:
new AlertDialog.Builder(this)
.setTitle("Delete List")
.setMessage("Do you want to clear all?")
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// continue with delete
myDb.deleteAll();
populateListViewFromDB();
}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// do nothing
}
})
.show();
return true;
}
return true;
}}
the final code from where i adding to the list
case R.id.id_favorit:
// Add it to the DB and re-draw the ListView
myDb.insertRow("Atherosclerosis", 0, "");
Toast.makeText(getApplicationContext(), "Item Added to Favorite List!", Toast.LENGTH_SHORT).show();
favClicked=true;
invalidateOptionsMenu();
return true;
Seems like you just want to get your results from the DB in reverse order. Changing the function that retrieves them to ORDER BY your rowid in descending order will do the trick:
// Return all data in the database.
public Cursor getAllRows() {
String where = null;
Cursor c = db.query(true, DATABASE_TABLE, ALL_KEYS,
where, null, null, null, KEY_ROWID + " DESC", null);
if (c != null) {
c.moveToFirst();
}
return c;
}
Regarding your second question, you should check if the favorite exists before inserting it. The question is how you define your uniqueness. For example, if you don't want two "favorites" with the same name, you'll want to add a check in your insert function:
// Add a new set of values to the database, unless the name already exists.
public long insertRow(String name, int studentNum, String favColour) {
Cursor c = db.query(true, DATABASE_TABLE, ALL_KEYS,
KEY_NAME + "='" + name + "'", null, null, null, null, null);
if (c.getCount() > 0) {
return -1;
}
c.close();
/*
* CHANGE 3:
*/
// TODO: Update data in the row with new fields.
// TODO: Also change the function's arguments to be what you need!
// Create row's data:
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_NAME, name);
initialValues.put(KEY_STUDENTNUM, studentNum);
initialValues.put(KEY_FAVCOLOUR, favColour);
// Insert it into the database.
return db.insert(DATABASE_TABLE, null, initialValues);
}
I'm trying to code a simple randomizer app. I had the randomizer button working, but then I changed some code (which I thought was irrelevant to the randomizer button) and it started crashing and getting the "CursorIndexOutOfBoundsException Index 0 requested, with a size of 0" error. I couldn't find any fixes to this that apply to my code. Can anyone help me fix this?
Here is my main class with the button:
package com.example.randomgamechooser;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.TextView;
public class MainScreen extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_screen);
}
public void chooseGame (View view) {
GameList dbUtil = new GameList(this);
dbUtil.open();
String string = dbUtil.getRandomEntry();
//TextView textView = new TextView(this);
TextView textView = (TextView) findViewById(R.id.chosenbox);
textView.setTextSize(40);
textView.setText(string);
//setContentView (textView);
dbUtil.close();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main_screen, menu);
return true;
}
//starts the Game Selection activity
public void openGames (View view) {
Intent intent = new Intent(this, GameSelction.class);
startActivity(intent);
}
}
Here is the GameList class:
package com.example.randomgamechooser;
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;
import android.util.Log;
import java.util.Random;
public class GameList {
private static final String TAG = "GameList";
//database name
private static final String DATABASE_NAME = "game_list";
//database version
private static final int DATABASE_VERSION = 1;
//table name
private static final String DATABASE_TABLE = "game_list";
//table columns
public static final String KEY_NAME = "name";
public static final String KEY_GENRE = "genre";
public static final String KEY_ROWID = "_id";
//database creation sql statement
private static final String CREATE_GAME_TABLE =
"create table " + DATABASE_TABLE + " (" + KEY_ROWID + " integer primary key autoincrement, "
+ KEY_NAME +" text not null, " + KEY_GENRE + " text not null);";
//Context
private final Context mCtx;
private DatabaseHelper mDbHelper;
private static SQLiteDatabase mDb;
//Inner private class. Database Helper class for creating and updating database.
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// onCreate method is called for the 1st time when database doesn't exists.
#Override
public void onCreate(SQLiteDatabase db) {
Log.i(TAG, "Creating DataBase: " + CREATE_GAME_TABLE);
db.execSQL(CREATE_GAME_TABLE);
}
//onUpgrade method is called when database version changes.
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion);
}
}
//Constructor - takes the context to allow the database to be opened/created
//#param ctx the Context within which to work
public GameList(Context ctx) {
this.mCtx = ctx;
}
//This method is used for creating/opening connection
//#return instance of GameList
//#throws SQLException
public GameList open() throws SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}
//This method is used for closing the connection.
public void close() {
mDbHelper.close();
}
//This method is used to create/insert new game.
//#param name
// #param genre
// #return long
public long createGame(String name, String genre) {
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_NAME, name);
initialValues.put(KEY_GENRE, genre);
return mDb.insert(DATABASE_TABLE, null, initialValues);
}
// This method will delete game.
// #param rowId
// #return boolean
public static boolean deleteGame(long rowId) {
return mDb.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) > 0;
}
// This method will return Cursor holding all the games.
// #return Cursor
public Cursor fetchAllGames() {
return mDb.query(DATABASE_TABLE, new String[] {KEY_ROWID, KEY_NAME,
KEY_GENRE}, null, null, null, null, null);
}
// This method will return Cursor holding the specific game.
// #param id
// #return Cursor
// #throws SQLException
public Cursor fetchGame(long id) throws SQLException {
Cursor mCursor =
mDb.query(true, DATABASE_TABLE, new String[] {KEY_ROWID,
KEY_NAME, KEY_GENRE}, KEY_ROWID + "=" + id, null,
null, null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
public int getAllEntries()
{
Cursor cursor = mDb.rawQuery(
"SELECT COUNT(name) FROM game_list", null);
if(cursor.moveToFirst()) {
return cursor.getInt(0);
}
return cursor.getInt(0);
}
public String getRandomEntry()
{
//id = getAllEntries();
Random random = new Random();
int rand = random.nextInt(getAllEntries());
if(rand == 0)
++rand;
Cursor cursor = mDb.rawQuery(
"SELECT name FROM game_list WHERE _id = " + rand, null);
if(cursor.moveToFirst()) {
return cursor.getString(0);
}
return cursor.getString(0);
}
// This method will update game.
// #param id
// #param name
// #param standard
// #return boolean
public boolean updateGame(int id, String name, String standard) {
ContentValues args = new ContentValues();
args.put(KEY_NAME, name);
args.put(KEY_GENRE, standard);
return mDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + id, null) > 0;
}
}
And here is the cause part of the error log:
08-01 13:03:38.325: E/AndroidRuntime(278): Caused by: android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
08-01 13:03:38.325: E/AndroidRuntime(278): at android.database.AbstractCursor.checkPosition(AbstractCursor.java:580)
08-01 13:03:38.325: E/AndroidRuntime(278): at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:214)
08-01 13:03:38.325: E/AndroidRuntime(278): at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:41)
08-01 13:03:38.325: E/AndroidRuntime(278): at com.example.randomgamechooser.GameList.getRandomEntry(GameList.java:153)
EDIT: Here is the ListView class:
public class GameSelction extends Activity
{
GameList dbUtil = new GameList(this);
private SimpleCursorAdapter dataAdapter;
//#SuppressWarnings("deprecation")
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game_selction);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
getActionBar() .setDisplayHomeAsUpEnabled(true);
}
displayListView();
}
private void displayListView() {
dbUtil.open();
Cursor cursor = dbUtil.fetchAllGames();
// The desired columns to be bound
String[] columns = new String[] {
GameList.KEY_NAME,
GameList.KEY_GENRE,
};
// the XML defined views which the data will be bound to
int[] to = new int[] {
R.id.name,
R.id.genre,
};
// create the adapter using the cursor pointing to the desired data
//as well as the layout information
dataAdapter = new SimpleCursorAdapter(
this, R.layout.game_info,
cursor,
columns,
to,
0);
ListView listView = (ListView) findViewById(R.id.listView1);
// Assign adapter to ListView
listView.setAdapter(dataAdapter);
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> listView, View view,
int position, long rowId) {
// Get the cursor, positioned to the corresponding row in the result set
//Cursor cursor = (Cursor) listView.getItemAtPosition(position);
GameList.deleteGame(rowId);
}
});
}
/**
* Set up the {#link android.app.ActionBar}, if the API is available.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void setupActionBar() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
getActionBar().setDisplayHomeAsUpEnabled(true);
}
}
//opens the AddGame activity
public void openAddgame (View view) {
Intent intent = new Intent(this, AddGame.class);
startActivity(intent);
}
public void buttonBackMain (View view) {
Intent intent = new Intent(this, MainScreen.class);
startActivity(intent);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.game_selction, menu);
return true;
}
}
The problem is in this section of code:
public String getRandomEntry()
{
//...
Cursor cursor = mDb.rawQuery(
"SELECT name FROM game_list WHERE _id = " + rand, null);
if(cursor.moveToFirst()) {
return cursor.getString(0);
}
return cursor.getString(0);
}
What you ended up doing was saying return cursor.getString(0); whether or not there were results in the cursor. So remove the second occurrence, and it should work.
EDIT:
After scanning your code, it seems that the only place you use this method is to fill a TextView. In that case you can use this as a chance to communicate a visual error message to yourself or your users, or do anything else with it that you want. So I would suggest using something to the effect of
public String getRandomEntry()
{
//EDIT: This will make your random generator less biased toward 1.
Random random = new Random();
int rand = random.nextInt(getAllEntries()) + 1;
/* Assuming your _id starts at 1 and auto-increments, this will
* start the random digits at 1 and go as high as your highest _id */
Cursor cursor = mDb.rawQuery(
"SELECT name FROM game_list WHERE _id = " + rand, null);
if(cursor.moveToFirst()) {
return cursor.getString(0);
}
return "There were no games in the database to choose from.";
}
EDIT:
Try using this. Notice that this code uses mDb.query(), which you used elsewhere. I'm not sure why rawQuery() would refuse to work, but maybe this will do it.
public String getRandomEntry()
{
Random random = new Random();
int rand = random.nextInt(getAllEntries()) + 1;
Cursor cursor = mDb.query(true, DATABASE_TABLE, new String[] {KEY_NAME},
KEY_ROWID + "=" + rand, null, null, null, null, null);
if(cursor.moveToFirst()) {
return cursor.getString(0);
}
return "There were no games in the database to choose from.";
}
Based on the initial look, the SQLiteDatabase object represented by mDB appears to be empty, as that's what is throwing the error.
What the error is saying is that your code is requesting the item at index 0 (basically, the first item), but the size of your index is 0 (basically, there are no items in the index).
Somewhere along the line, your database object is either emptied or not populated. To test this, run your fetchAllGames method and verify the contents of the index.
Didn't read the whole code, but I guess the problem is that, you are trying to get first element, from empty database.
Just check if the size of cursor greater than 0, before getting element.
if (cursor.getColumnCount() > 0)
return cursor.getString(0);
else return "no items";
I'm trying to add site details to a database and then after I insert a row, output the result to a TextView. The record is being inserted into the database because it's being shown in a TextView, however I can only insert one record and I'm not sure why. I'm been using the tutorial here and modifying it to meet my needs.
Here is my DBAdapter:
public class DBAdapter {
// ///////////////////////////////////////////////////////////////////
// Constants & Data
// ///////////////////////////////////////////////////////////////////
// For logging:
private static final String TAG = "DBAdapter";
// DB Fields
public static final String KEY_ROWID = "_id";
public static final int COL_ROWID = 0;
/*
* CHANGE 1:
*/
// TODO: Setup your fields here:
public static final String KEY_NAME = "name";
public static final String KEY_ADDRESS = "address";
public static final String KEY_USERNAME = "username";
public static final String KEY_PASSWORD = "password";
public static final String KEY_PORT = "port";
// TODO: Setup your field numbers here (0 = KEY_ROWID, 1=...)
public static final int COL_NAME = 1;
public static final int COL_ADDRESS = 2;
public static final int COL_USERNAME = 3;
public static final int COL_PASSWORD = 4;
public static final int COL_PORT = 5;
public static final String[] ALL_KEYS = new String[] { KEY_ROWID, KEY_NAME,
KEY_ADDRESS, KEY_USERNAME, KEY_PASSWORD, KEY_PORT };
// DB info: it's name, and the table we are using (just one).
public static final String DATABASE_NAME = "Sites";
public static final String DATABASE_TABLE = "SiteTable";
// Track DB version if a new version of your app changes the format.
public static final int DATABASE_VERSION = 2;
private static final String DATABASE_CREATE_SQL = "create table "
+ DATABASE_TABLE
+ " ("
+ KEY_ROWID
+ " integer primary key autoincrement, "
/*
* CHANGE 2:
*/
// TODO: Place your fields here!
// + KEY_{...} + " {type} not null"
// - Key is the column name you created above.
// - {type} is one of: text, integer, real, blob
// (http://www.sqlite.org/datatype3.html)
// - "not null" means it is a required field (must be given a
// value).
// NOTE: All must be comma separated (end of line!) Last one must
// have NO comma!!
+ KEY_NAME + " string not null, " + KEY_ADDRESS
+ " string not null, " + KEY_USERNAME + " string not null, "
+ KEY_PASSWORD + " string not null, " + KEY_PORT
+ " integer not null"
// Rest of creation:
+ ");";
// Context of application who uses us.
private final Context context;
private DatabaseHelper myDBHelper;
private SQLiteDatabase db;
// ///////////////////////////////////////////////////////////////////
// Public methods:
// ///////////////////////////////////////////////////////////////////
public DBAdapter(Context ctx) {
this.context = ctx;
myDBHelper = new DatabaseHelper(context);
}
// Open the database connection.
public DBAdapter open() {
db = myDBHelper.getWritableDatabase();
return this;
}
// Close the database connection.
public void close() {
myDBHelper.close();
}
// Add a new set of values to the database.
public long insertRow(String name, String address, String username,
String password, int port) {
/*
* CHANGE 3:
*/
// TODO: Update data in the row with new fields.
// TODO: Also change the function's arguments to be what you need!
// Create row's data:
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_NAME, name);
initialValues.put(KEY_ADDRESS, address);
initialValues.put(KEY_USERNAME, username);
initialValues.put(KEY_PASSWORD, password);
initialValues.put(KEY_PORT, port);
// Insert it into the database.
return db.insert(DATABASE_TABLE, null, initialValues);
}
// Delete a row from the database, by rowId (primary key)
public boolean deleteRow(long rowId) {
String where = KEY_ROWID + "=" + rowId;
return db.delete(DATABASE_TABLE, where, null) != 0;
}
public void deleteAll() {
Cursor c = getAllRows();
long rowId = c.getColumnIndexOrThrow(KEY_ROWID);
if (c.moveToFirst()) {
do {
deleteRow(c.getLong((int) rowId));
} while (c.moveToNext());
}
c.close();
}
// Return all data in the database.
public Cursor getAllRows() {
String where = null;
Cursor c = db.query(true, DATABASE_TABLE, ALL_KEYS, where, null, null,
null, null, null);
if (c != null) {
c.moveToFirst();
}
return c;
}
// Get a specific row (by rowId)
public Cursor getRow(long rowId) {
String where = KEY_ROWID + "=" + rowId;
Cursor c = db.query(true, DATABASE_TABLE, ALL_KEYS, where, null, null,
null, null, null);
if (c != null) {
c.moveToFirst();
}
return c;
}
// Change an existing row to be equal to new data.
public boolean updateRow(long rowId, String name, String address,
String username, String password, String port) {
String where = KEY_ROWID + "=" + rowId;
/*
* CHANGE 4:
*/
// TODO: Update data in the row with new fields.
// TODO: Also change the function's arguments to be what you need!
// Create row's data:
ContentValues newValues = new ContentValues();
newValues.put(KEY_NAME, name);
newValues.put(KEY_ADDRESS, address);
newValues.put(KEY_USERNAME, username);
// newValues.put(KEY_PASSWORD, password);
// newValues.put(KEY_PORT, port);
// Insert it into the database.
return db.update(DATABASE_TABLE, newValues, where, null) != 0;
}
// ///////////////////////////////////////////////////////////////////
// Private Helper Classes:
// ///////////////////////////////////////////////////////////////////
/**
* Private class which handles database creation and upgrading. Used to
* handle low-level database access.
*/
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase _db) {
_db.execSQL(DATABASE_CREATE_SQL);
}
#Override
public void onUpgrade(SQLiteDatabase _db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading application's database from version "
+ oldVersion + " to " + newVersion
+ ", which will destroy all old data!");
// Destroy old database:
_db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
// Recreate new database:
onCreate(_db);
}
}
}
I'm querying the database here:
public class FTPConnector extends Activity {
DBAdapter myDb;
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.ftp);
status = (TextView) findViewById(R.id.status);
editAddress = (EditText) findViewById(R.id.editAddress);
editUser = (EditText) findViewById(R.id.editUsername);
editPassword = (EditText) findViewById(R.id.editPassword);
addsiteBtn = (Button) findViewById(R.id.addsiteBtn);
addsiteBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
siteManager();
}
});
openDb();
}
private void openDb() {
myDb = new DBAdapter(this);
myDb.open();
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
closeDb();
}
private void closeDb() {
myDb.close();
}
//Where the insertRecord() happens
public void siteManager() {
final AlertDialog customDialog = new AlertDialog.Builder(this).create();
LayoutInflater layoutInflater = (LayoutInflater) getApplicationContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = layoutInflater.inflate(R.layout.site_manager, null);
final EditText tmpname = (EditText) view
.findViewById(R.id.dialogsitename);
final EditText tmpaddress = (EditText) view
.findViewById(R.id.dialogaddress);
final EditText tmpuser = (EditText) view
.findViewById(R.id.dialogusername);
final EditText tmppass = (EditText) view
.findViewById(R.id.dialogpassword);
final EditText tmpport = (EditText) view.findViewById(R.id.dialogport);
final TextView tmpsites = (TextView) view.findViewById(R.id.textView6);
final CheckBox tmppassive = (CheckBox) view
.findViewById(R.id.dialogpassive);
final Button tmpclose = (Button) view.findViewById(R.id.closeBtn);
final Button tmptestBtn = (Button) view.findViewById(R.id.testBtn);
final Button tmpsavetsite = (Button) view.findViewById(R.id.saveSite);
customDialog.setView(tmpclose);
customDialog.setView(tmptestBtn);
customDialog.setView(tmpname);
customDialog.setView(tmpaddress);
customDialog.setView(tmpuser);
customDialog.setView(tmppass);
customDialog.setView(tmpport);
customDialog.setView(tmppassive);
customDialog.setView(tmpsavetsite);
customDialog.setView(tmpsites);
tmpclose.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
customDialog.dismiss();
}
});
tmptestBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
_name = tmpname.getText().toString();
_address = tmpaddress.getText().toString();
_user = tmpuser.getText().toString();
_pass = tmppass.getText().toString();
_port = Integer.parseInt(tmpport.getText().toString());
_passive = false;
if (tmppassive.isChecked()) {
_passive = true;
}
boolean status = ftpConnect(_address, _user, _pass, _port);
if (status == true) {
Toast.makeText(FTPConnector.this, "Connection Succesful",
Toast.LENGTH_LONG).show();
} else {
Toast.makeText(FTPConnector.this,
"Connection Failed:" + status, Toast.LENGTH_LONG)
.show();
}
}
});
tmpsavetsite.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
tmpsites.setText("");
String msg = "!";
_name = tmpname.getText().toString();
_address = tmpaddress.getText().toString();
_user = tmpuser.getText().toString();
_pass = tmppass.getText().toString();
_port = Integer.parseInt(tmpport.getText().toString());
long newId = myDb.insertRow(_name, _address, _user, _pass, 21);
Cursor c = myDb.getAllRows();
if (c.moveToFirst()) {
int id = c.getInt(0);
String _name = c.getString(1);
String _address = c.getString(2);
String _user = c.getString(3);
String _pass = c.getString(4);
int _port = c.getInt(5);
msg += "id=" + id + "\n";
msg += ", name=" + _name + "\n";
msg += ", address=" + _address + "\n";
msg += ", username=" + _user + "\n";
msg += ", password=" + _pass + "\n";
msg += ", port=" + _port + "\n";
while (c.moveToNext());
}
c.close();
// displayText(msg);
tmpsites.setText(msg);
}
});
customDialog.setView(view);
customDialog.show();
}
Why can't I add more than one record?
In here :
while (c.moveToNext()); //<<<
currently you are not using any loop like do-while for iterating through cursor(you forget to add do block with while). get all data from cursor as using for loop:
//more to the first row
c.moveToFirst();
//iterate over rows
for (int i = 0; i < c.getCount(); i++) {
// get all data here from current row..
//move to the next row
c.moveToNext();
}
//close the cursor
c.close();
and using do-while you can get all values from current row as:
c.moveToFirst(); //more to the first row
do {
// get all data here from current row..
} while (c.moveToNext());
With the help of this tutorial i have made an app that has 3 activities.
In the fisrt activity(Import) i just import some values to a sqlite database.
This is my DatabaseHelper class:
public class DatabaseHelper_bp extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "bpDB";
private static final int DATABASE_VERSION = 1;
// Database creation sql statement
private static final String DATABASE_CREATE = "create table bp_import ( _id integer primary key, datetime text not null, systolic text not null, diastolic text not null, pulses text not null, notes text not null);";
public DatabaseHelper_bp(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// 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(DatabaseHelper_bp.class.getName(),
"Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
database.execSQL("DROP TABLE IF EXISTS bp_import");
onCreate(database);
}
}
And my DAO class for my measures/values:
public class BpDAO {
private DatabaseHelper_bp dbHelper;
private SQLiteDatabase database;
/**
* Movie table related constants.
*/
public final static String bp_TABLE = "bp_import";
public final static String bp_ID = "_id";
public final static String bp_DT = "datetime";
public final static String bp_SYS = "systolic";
public final static String bp_DIA = "diastolic";
public final static String bp_PUL = "pulses";
public final static String bp_NOT = "notes";
/**
*
* #param context
*/
public BpDAO(Context context) {
dbHelper = new DatabaseHelper_bp(context);
database = dbHelper.getWritableDatabase();
}
/**
* \ Creates a new blood pressure measure
*
* #param datetime
* #param systolic
* #param diastolic
* #param pulses
* #param notes
* #return
*/
public long importBP(String datetime, String systolic, String diastolic,
String pulses, String notes) {
ContentValues values = new ContentValues();
values.put(bp_DT, datetime);
values.put(bp_SYS, systolic);
values.put(bp_DIA, diastolic);
values.put(bp_PUL, pulses);
values.put(bp_NOT, notes);
return database.insert(bp_TABLE, null, values);
}
/**
* Fetch all movies
*
* #return
*/
public Cursor fetchAll_bp() {
Cursor mCursor = database.query(true, bp_TABLE, new String[] { bp_SYS,
bp_DIA, bp_DT, bp_ID }, null, null, null, null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
}
In the second activity(History) i have a List activity with the some values of each row of my database.All work well here.The list is populated by the database,all ok
BUT my problem is when i try onListItemClick to start a new 3 Activity(Detailed Infos) and pass to it all the values of the selected measure (ListItem), the app force closes!
Here is the code of 2 Activity(history):
public class HistoryActivity extends ListActivity {
private BpDAO dao;
private SimpleCursorAdapter dbAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
dao = new BpDAO(this);
Cursor bpList = dao.fetchAll_bp();
String[] from = new String[] { BpDAO.bp_SYS, BpDAO.bp_DIA, BpDAO.bp_DT };
int[] target = new int[] { R.id.bpSysHolder, R.id.bpDiaHolder,
R.id.bpDtHolder };
dbAdapter = new SimpleCursorAdapter(this, R.layout.history_bp, bpList,
from, target);
setListAdapter(dbAdapter);
}
//above is all good!
// try to make new activity on click - let's
// see...down here is the problem!
#Override
public void onListItemClick(ListView l, View view, int position, long id) {
// TODO Auto-generated method stub
super.onListItemClick(l, view, position, id);
Log.d("BPT", "Selected bp id =" + id);
// log says that i have selected an item with id : 11
Cursor selectedBpDetails = (Cursor) l.getItemAtPosition(position);
String bp_DT = selectedBpDetails.getString(selectedBpDetails
.getColumnIndex(BpDAO.bp_DT));
String bp_SYS = selectedBpDetails.getString(selectedBpDetails
.getColumnIndex(BpDAO.bp_SYS));
String bp_DIA = selectedBpDetails.getString(selectedBpDetails
.getColumnIndex(BpDAO.bp_DIA));
String bp_PUL = selectedBpDetails.getString(selectedBpDetails
.getColumnIndex(BpDAO.bp_PUL));
String bp_NOT = selectedBpDetails.getString(selectedBpDetails
.getColumnIndex(BpDAO.bp_NOT));
Log.d("BPT", "Selected bp details = { date=" + bp_DT + ", systolic="
+ bp_SYS + ", diastolic=" + bp_DIA + ", pulses=" + bp_PUL
+ ", notes=" + bp_NOT + " }");
Intent intent = new Intent(HistoryActivity.this, FromHistory.class);
intent.putExtra("bp_SYS", bp_SYS);
intent.putExtra("bp_DIA", bp_DIA);
intent.putExtra("bp_DT", bp_DT);
intent.putExtra("bp_PUL", bp_PUL);
intent.putExtra("bp_NOT", bp_NOT);
startActivity(intent);
}
// ----------------------------------------------------------------------------
}
This is the logcat:
16:50:48.513: D/BPT(562): Selected bp id =11
16:50:48.513: **E/CursorWindow(562): Failed to read row 1, column -1 from a CursorWindow which has 13 rows, 4 columns.**
In your database query method fetchAll_bp() in the BpDAO class, it looks like you forgot to include notes (bp_NOT) in the query. So suspect it is failing because your onClickListener is looking for bp_NOT in the cursor, which it does not contain.
Try this
Cursor selectedBpDetails = (Cursor) l.getItemAtPosition(position);
if (selectedBpDetails.getCursor() > 0) {
selectedBpDetails.moveToFirst();
String bp_DT = selectedBpDetails.getString(selectedBpDetails
.getColumnIndex(BpDAO.bp_DT));
String bp_SYS = selectedBpDetails.getString(selectedBpDetails
.getColumnIndex(BpDAO.bp_SYS));
String bp_DIA = selectedBpDetails.getString(selectedBpDetails
.getColumnIndex(BpDAO.bp_DIA));
String bp_PUL = selectedBpDetails.getString(selectedBpDetails
.getColumnIndex(BpDAO.bp_PUL));
String bp_NOT = selectedBpDetails.getString(selectedBpDetails
.getColumnIndex(BpDAO.bp_NOT));
}
The function fetchAll_bp in the database table doesn't contain any entry for notes, it might be the reason for getting the error.