Related
I have an AutoCompleteTextView, which shows dropdown list of suggestions taken from a SQLiteDatabase query. At the moment it uses SimpleCursorAdapter, however there are several problems with it (I have a separate question about the issue here: SimpleCursorAdapter issue - "java.lang.IllegalStateException: trying to requery an already closed cursor").
Nevertheless, I was advised to look in the direction of CursorLoader and LoaderManager, and I've tried it, yet couldn't make it work. I'd be grateful if someone would guide/recommend/show the right way of migrating my code below to CursorLoader/LoaderManager concept. Any kind of help very appreciated!
mAdapter = new SimpleCursorAdapter(this,
R.layout.dropdown_text,
null,
new String[]{CITY_COUNTRY_NAME},
new int[]{R.id.text}, 0);
mAutoCompleteTextView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> listView, View view, int position, long id) {
Cursor cursor = (Cursor) listView.getItemAtPosition(position);
cityCountryName = cursor.getString(cursor.getColumnIndexOrThrow(CITY_COUNTRY_NAME));
mAutoCompleteTextView.setText(cityCountryName);
JSONWeatherTask task = new JSONWeatherTask();
task.execute(new String[]{cityCountryName});
}
});
mAdapter.setFilterQueryProvider(new FilterQueryProvider() {
public Cursor runQuery(CharSequence sequence) {
String constraint = sequence.toString();
String queryString = "SELECT " + ID + ", " + CITY_ID + ", " + CITY_COUNTRY_NAME + " FROM " + TABLE_1;
constraint = constraint.trim() + "%";
queryString += " WHERE " + CITY_COUNTRY_NAME + " LIKE ?";
String params[] = {constraint};
try {
Cursor cursor = database.rawQuery(queryString, params);
if (cursor != null) {
startManagingCursor(cursor);
cursor.moveToFirst();
return cursor;
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
});
mAutoCompleteTextView.setAdapter(mAdapter);
Here is the whole project for the reference (you can make a pull request there, if you wish): Open Weather App
Unfortunately, here on SO nobody came up with a solution, yet a colleague (he doesn't have an SO account) made a pull request with the migration fixes. It works perfectly, and I decided to post the correct answer here as well.
If you're interested in how these improvements look inside the actual code, you're welcome to visit the original open source project page on GitHub: Open Weather App
This is the new adapter:
mAdapter = new SimpleCursorAdapter(this,
R.layout.dropdown_text,
null,
new String[]{CITY_COUNTRY_NAME},
new int[]{R.id.text},0);
mAdapter.setFilterQueryProvider(new FilterQueryProvider() {
#Override
public Cursor runQuery(CharSequence constraint) {
if (constraint != null) {
if (constraint.length() >= 3 && !TextUtils.isEmpty(constraint)) {
Bundle bundle = new Bundle();
String query = charArrayUpperCaser(constraint);
bundle.putString(CITY_ARGS, query);
getLoaderManager().restartLoader(0, bundle, MainActivity.this).forceLoad();
}
}
return null;
}
});
This is the onCreateLoader() callback:
#Override
public android.content.Loader<Cursor> onCreateLoader(int id, Bundle args) {
String s = args.getString(CITY_ARGS);
WeatherCursorLoader loader = null;
if (s != null && !TextUtils.isEmpty(s)) {
loader = new WeatherCursorLoader(this, database, s);
}
return loader;
}
Custom CursorLoader itself:
private static class WeatherCursorLoader extends CursorLoader {
private SQLiteDatabase mSQLiteDatabase;
private String mQuery;
WeatherCursorLoader(Context context, SQLiteDatabase cDatabase, String s) {
super(context);
mSQLiteDatabase = cDatabase;
mQuery = s + "%";
Log.d(TAG, "WeatherCursorLoader: " + mQuery);
}
#Override
public Cursor loadInBackground() {
return mSQLiteDatabase.query(TABLE_1, mProjection,
CITY_COUNTRY_NAME + " like ?", new String[] {mQuery},
null, null, null, "50");
}
}
I want to save DatabaseTableDay to my SQLite in anndroid applicatin but something gones wrong.
My DatabaseDAODay is:
public class DatabaseDAODay {
public static final String TAG = "DaysDAO";
// Database fields
private SQLiteDatabase mDatabase;
private DatabaseHelper mDbHelper;
private Context mContext;
private String[] mAllColumns = { DatabaseHelper.COLUMN_DAY_ID,
DatabaseHelper.COLUMN_DAY_NAME, DatabaseHelper.COLUMN_DAY_WEIGHT};
public DatabaseDAODay(Context context) {
this.mContext = context;
mDbHelper = new DatabaseHelper(context);
// open the database
try {
open();
} catch (SQLException e) {
Log.e(TAG, "SQLException on openning database " + e.getMessage());
e.printStackTrace();
}
}
public void open() throws SQLException {
mDatabase = mDbHelper.getWritableDatabase();
}
public void close() {
mDbHelper.close();
}
public DatabaseTableDay createDay(String name, float weight, Long id) {
ContentValues values = new ContentValues();
values.put(DatabaseHelper.COLUMN_DAY_NAME, name);
values.put(DatabaseHelper.COLUMN_DAY_WEIGHT, weight);
long insertId = id;
Cursor cursor = mDatabase.query(DatabaseHelper.TABLE_DAYS, mAllColumns,
DatabaseHelper.COLUMN_DAY_ID + " = " + insertId, null, null,
null, null);
DatabaseTableDay newDay = new DatabaseTableDay();
if(cursor != null && cursor.moveToFirst()){
newDay = cursorToDay(cursor);
cursor.close();
Toast.makeText(mContext,"im here",Toast.LENGTH_LONG).show();
}
return newDay;
}
public void deleteDay(DatabaseTableDay databaseTableDay) {
long id = databaseTableDay.getId();
// delete all employees of this company
DatabaseDAOActivity databaseDAOActivity = new DatabaseDAOActivity(mContext);
List<DatabaseTableActivity> databaseTableActivities = databaseDAOActivity.getActivitiesOfDay(id);
if (databaseTableActivities != null && !databaseTableActivities.isEmpty()) {
for (DatabaseTableActivity e : databaseTableActivities) {
databaseDAOActivity.deleteActivity(e);
}
}
System.out.println("the deleted day has the id: " + id);
mDatabase.delete(DatabaseHelper.TABLE_DAYS, DatabaseHelper.COLUMN_DAY_ID
+ " = " + id, null);
}
public List<DatabaseTableDay> getAllDays() {
List<DatabaseTableDay> listDays = new ArrayList<DatabaseTableDay>();
Cursor cursor = mDatabase.query(DatabaseHelper.TABLE_DAYS, mAllColumns,
null, null, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
DatabaseTableDay day = cursorToDay(cursor);
listDays.add(day);
cursor.moveToNext();
}
// make sure to close the cursor
cursor.close();
}
return listDays;
}
public DatabaseTableDay getDayById(long id) {
Cursor cursor = mDatabase.query(DatabaseHelper.TABLE_DAYS, mAllColumns,
DatabaseHelper.COLUMN_DAY_ID + " = ?",
new String[] { String.valueOf(id) }, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
}
DatabaseTableDay databaseTableDay = cursorToDay(cursor);
return databaseTableDay;
}
protected DatabaseTableDay cursorToDay(Cursor cursor) {
DatabaseTableDay databaseTableDay = new DatabaseTableDay();
databaseTableDay.setId(cursor.getLong(0));
databaseTableDay.setName(cursor.getString(1));
databaseTableDay.setWeight(cursor.getLong(2));
return databaseTableDay;
}
}
and I try to save it by:
saveButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DatabaseTableDay databaseTableDay = databaseDAODay.createDay(
editText.getText().toString(), 100f, new Long(myId));
List<DatabaseTableDay> list = databaseDAODay.getAllDays();
}
});
but list is empty anyway.
Probably the problem is createDay() method in DatabaseDAODay because if condition is always null and application doesn' run cursorToDay() method.
I had problem without condition and if there was only cursot.moveToFirst() and then cursorToDay() there was NullPoinerException - because coursor was null. I followed this and put condition !=null but actually nothing happens and List is always empty...
How should I solve my problem?
You are right about the problem being createDay(): instead of inserting a new day by using insert() you try to read from the database by using query()
Change your method like this:
public DatabaseTableDay createDay(String name, float weight, Long id) {
DatabaseTableDay dayToReturn;
ContentValues values = new ContentValues();
values.put(DatabaseHelper.COLUMN_DAY_NAME, name);
values.put(DatabaseHelper.COLUMN_DAY_WEIGHT, weight);
values.put(DatabaseHelper.COLUMN_DAY_ID, id);
long resID = mDatabase.insert(DatabaseHelper.TABLE_DAYS, null, values);
if (resID == -1)
{
// something went wrong, do error handling here
dayToReturn = null;
}
else
{
// no error: resID is "the row ID of the newly inserted row"
// you only need this info if you are using autoincrement
// not if you set the ID yourself
// all right, this will work -
// but somehow it hurts a little to retrieve an entry I just added.
// I'd like much more to simply use a constructor with all the values
// and create a new DatabaseTableDay instance
dayToReturn = getDayById(id);
}
return dayToReturn;
}
See also this link to documentation for SQLiteDatabase insert()
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());
public class SearchViewActivity extends Activity {
private TextView resultText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search_view);
resultText = (TextView)findViewById(R.id.searchViewResult);
setupSearchView();
}
private void setupSearchView() {
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
final SearchView searchView = (SearchView) findViewById(R.id.searchView);
SearchableInfo searchableInfo = searchManager.getSearchableInfo(getComponentName());
searchView.setSearchableInfo(searchableInfo);
}
#Override
protected void onNewIntent(Intent intent) {
if (ContactsContract.Intents.SEARCH_SUGGESTION_CLICKED.equals(intent.getAction())) {
//handles suggestion clicked query
String displayName = getDisplayNameForContact(intent);
resultText.setText(displayName);
} else if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
// handles a search query
String query = intent.getStringExtra(SearchManager.QUERY);
resultText.setText("should search for query: '" + query + "'...");
}
}
private String getDisplayNameForContact(Intent intent) {
Cursor phoneCursor = getContentResolver().query(intent.getData(), null, null, null, null);
phoneCursor.moveToFirst();
int idDisplayName = phoneCursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
String name = phoneCursor.getString(idDisplayName);
phoneCursor.close();
return name;
}
}
my goal is to get the contact name and number but my code just prints the name so how i can also gets the contact number. although my code fetching the contacts by name but when i click on particular name it just display the name . plz edit my code which gets the name and number also. thanks in advance
To get phone number
Cursor phones = getContentResolver()
.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
null, null, null);
while (phones.moveToNext()) {
phoneNumber = phones
.getString(phones
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
}
Try this code
phoneNumber = phoneCursor.getString(phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
So I know this is a little late but I ran into the same problem and fixed it like this.
private String getDisplayPhoneForContact(Intent intent){
Cursor phoneCursor = getContentResolver().query(intent.getData(), null,null,null,null);
String phoneNum= "0";
phoneCursor.moveToFirst();
String id = phoneCursor.getString(phoneCursor.getColumnIndex(ContactsContract.Contacts._ID));
Cursor pCur= getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=?", new String[]{id},null);
while(pCur.moveToNext()){
phoneNum = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
}
return phoneNum;
}
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);
}