Implementing better search from sqlite android - android

I am currently using a SearchView to take input and whenever the input changes i call searchVideo()
this is my searchVideo function :
public void searchVideo(String s)
{
videos.clear();
SQLiteDatabase sqLiteDatabase = getActivity().openOrCreateDatabase("CodifyData", MODE_PRIVATE, null);
String sql = "SELECT * FROM appdata_videos WHERE subcode='"+dbName+"' AND title LIKE '%"+s+"%'";
Cursor c = sqLiteDatabase.rawQuery(sql,null);
int idID = c.getColumnIndex("id");
int linkID = c.getColumnIndex("link");
int titleID = c.getColumnIndex("title");
while(c.moveToNext())
{
videos.add(new VideoDataModel(c.getString(idID), c.getString(titleID), c.getString(linkID)));
}
c.close();
videoAdapter.notifyDataSetChanged();
}
But when user inputs two words and those two works are contained by the title but not next to each other or in a way they are input by the user, the search fails, so what can i do to make this better, don't need a complicated solution but something simpler and easier to implement.

split your string by space to get array of words
and concat the values with query like that:
String[] splitedValues = str.split("\\s+");
String query="SELECT * FROM appdata_videos WHERE subcode='"+dbName+"' ";
for(int i=0;i<splitedValues .length;i++){
query+="AND title LIKE '%"+splitedValues[i]+"%' ";
}

Related

Update on Content Provider does nothing

I'm trying to make an Android app to help people suffering from headaches. I have a sqlite database to store the crisis, and users can add a crisis by pushing a button. The same button is used to indicate the crisis is over. In other words, when you feel the headache coming, you push the button ; then, when it's over, you press it again and the application updates the corresponding entry whith the "end date".
But if my insert does well, my update does not update at all. Here is how it is supposed to work :
I first retrieve the latest entry in my database (which is the one with the greatest id), then I get the actual date, and put it in a ContentValue. Finally I update the entry.
Here is the button code :
public void onClickStartStop(View v){
Log.v("andromed", "Starting/Stopping crisis");
String d = new Date().toString();
ContentValues cv = new ContentValues();
String user_info = "";
String[] projection = {CriseContract.COLUMN_NAME_CRISE_ID, CriseContract.COLUMN_NAME_CRISE_DEBUT,CriseContract.COLUMN_NAME_CRISE_FIN};
Cursor criseCursor = getContentResolver().query(CriseContract.CONTENT_URI, projection,"SELECT MAX("+CriseContract.COLUMN_NAME_CRISE_ID+") FROM "+CriseContract.TABLE_NAME, null, null);
Log.v("andromed",""+criseCursor.getCount());
if(criseCursor.getCount()>=0){
while(criseCursor.moveToNext()){
String date_fin = criseCursor.getString(criseCursor.getColumnIndex(CriseContract.COLUMN_NAME_CRISE_FIN));
if(!(date_fin==(null))){
Log.v("andromed","Date exists "+date_fin);
user_info = "Crise enregistrée";
cv.put(CriseContract.COLUMN_NAME_CRISE_DEBUT, d);
Uri u = getContentResolver().insert(CriseContract.CONTENT_URI, cv);
}else{
String date_deb = criseCursor.getString(criseCursor.getColumnIndex(CriseContract.COLUMN_NAME_CRISE_DEBUT));
if(date_deb==null){
Log.v("andromed","No date in db");
user_info = "Crise enregistrée";
cv.put(CriseContract.COLUMN_NAME_CRISE_DEBUT, d);
Uri u = getContentResolver().insert(CriseContract.CONTENT_URI, cv);
}else{
Log.v("andromed", "Need to close the crisis");
cv.put(CriseContract.COLUMN_NAME_CRISE_FIN, d);
int tmp = getMaxId();
String where = CriseContract.COLUMN_NAME_CRISE_ID+"="+tmp;
String[] st = {""+tmp};
int nup = getContentResolver().update(CriseContract.CONTENT_URI,cv, where, null);
Log.v("andromed", nup+" rows updated");
user_info = "Crise terminée";
}
}
}
}else{
user_info = "Erreur lors de la lecture";
}
Toast t = Toast.makeText(getApplicationContext(),user_info, Toast.LENGTH_LONG);
t.show();
}
(Don't mind the Log and the toast stuff, just for me).
Here is my function to retrieve the maximum id :
private int getMaxId(){
String[] projection = {CriseContract.COLUMN_NAME_CRISE_ID};
String selection = "SELECT MAX("+CriseContract.COLUMN_NAME_CRISE_ID+") FROM "+CriseContract.TABLE_NAME;
Cursor c = getContentResolver().query(CriseContract.CONTENT_URI, projection, selection, null, null);
Log.v("andromed", ""+c.getCount());
int maxid=-1;
if(c!=null){
while(c.moveToNext()){
maxid = c.getInt(c.getColumnIndex(CriseContract.COLUMN_NAME_CRISE_ID));
}
}
Log.v("andromed", "Greatest id in table Crise : "+maxid);
return maxid;
}
And of course, my contract class :
public final static class CriseContract{
public static final String AUTHORITY = "com.piertris.andromed";
public static final String BASE_PATH = "database";
public static final Uri CONTENT_URI = Uri.parse("content://"+AUTHORITY+"/"+BASE_PATH);
public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE+"/"+BASE_PATH;
public static final String CONTENT_ITEM_TYPE= ContentResolver.CURSOR_ITEM_BASE_TYPE+"/andromed";
public static final String TABLE_NAME = "crises";
public static final String COLUMN_NAME_CRISE_ID = "criseid";
public static final String COLUMN_NAME_CRISE_DEBUT = "date_debut";
public static final String COLUMN_NAME_CRISE_FIN = "date_fin";
public static final String COLUMN_NAME_INTENSITE = "intensite";
public static final String COLUMN_NAME_SYMPTOM = "symptome";
public static final String COLUMN_NAME_MED = "prise_med";
public static final String COLUMN_NAME_MEDS = "type_med";
public static final String COLUMN_NAME_AURA = "aura";
public static final String COLUMN_NAME_COMMENT = "comments";
}
When I try to end the current crisis, my Logcat tells me that 0 rows were updated.
Thanks to SO, I already corrected other problems due to a wrong use of the function, but this time, the only link I found was this one : Android content provider not updating database and the OP just added a comment saying he updated his ContentProvider, but nothing more.
What am I doing wrong ? Did I "misnamed" my column names ? Do I misuse the update function ?
Thanks for your help.
EDIT
Thanks to Jozua, I realized that I didn't implement the update function in my ContentProvider file. Alright, I feel extremely dumb right now. I'll keep you informed on how does it work once the update() function is written.
Once again, thanks Jozua.
Alright, I kind of solved the problem, but in a really bad way.
Considering the fact that I retrieve the crisis just once in order to add almost everything that is needed but the beginning date and the id, I simply turned my update() request into a delete() followed by an update() in which I pass a ContentValue containing the values of the row I previously deleted.
I know it is really bad programming, but at least it works.
I won't accept my answer, in case someone find out what was wrong with my update() function and could possibly help someone else (and even me, so that I can improve my code).
That's it :)
Here is the portion of relevant code :
public void onClickStartStop(View v){
//go straight to relevant part
String date_deb = criseCursor.getString(criseCursor.getColumnIndex(CriseContract.COLUMN_NAME_CRISE_DEBUT));
Log.v("andromed", "Need to close the crisis");
cv.put(CriseContract.COLUMN_NAME_CRISE_ID, criseCursor.getInt(criseCursor.getColumnIndex(CriseContract.COLUMN_NAME_CRISE_ID)));
cv.put(CriseContract.COLUMN_NAME_CRISE_DEBUT, date_deb);
cv.put(CriseContract.COLUMN_NAME_CRISE_FIN, d);
int ndel = getContentResolver().delete(CriseContract.CONTENT_URI, CriseContract.COLUMN_NAME_CRISE_ID+"=?", new String[] {""+criseCursor.getInt(criseCursor.getColumnIndex(CriseContract.COLUMN_NAME_CRISE_ID))});
Log.v("andromed", ndel+" rows deleted");
Uri u = getContentResolver().insert(CriseContract.CONTENT_URI, cv);
user_info = "Crise terminée";
//End of relevant code
}
Thanks to those who might have searched anyway.

Android GridView with database

I've got problem with my grid view. I would like to store images in table and then display them in grid view.
// ImageAdapter
String[] strings = db.getPictures();
Integer[] ints = new Integer[strings.length];
for (int i=0; i < strings.length; i++) {
ints[i] = Integer.parseInt(strings[i]);
}
imageView.setImageResource(ints[position]);
return imageView;
//DatabaseHandler
public String[] getPictures(){
int i=0;
String selectQuery = "SELECT pictureName FROM Category";
SQLiteDatabase db = this.getReadableDatabase();
Cursor c = db.rawQuery(selectQuery, null);
int rowsNumber=c.getCount();
String[] mThumbIds;
mThumbIds= new String[rowsNumber];
if (c.moveToFirst()) {
do {
mThumbIds[i]=c.getString(0);
i++;
} while (c.moveToNext());
}
return mThumbIds;
}
And when i run my app it crush at starting. Single string I save like R.drawable.ic_work
In most scenarios, your device wont be able to load a single original image into memory leave alone a list. You need to scale your image before you display it.
As you said you are saving R.drawable.ic_work as string.
The problem is you are using imageView.setImageResource(ints[position]); while R.drawable.ic_work is String.
Solution is instead of storing R.drawable.ic_work as String store it as int because your R.drawable.ic_work represents with an int ID.

Sorting the contents of ArrayAdapter or ArrayList

I am working on android project and am making using of a ListView that retrieves data from the SQLite database.
I am making a dataset using an ArrayList and then adding this ArrayList into an ArrayAdapter.
When the data is being retrieved from the database, I am telling SQLite to do the sorting so everything is in alphabetical order when it is added into the ListView. At certain times, the information will be added dynamically to to the ListView without it requiring to re-fetch everythin from the database again. However, I want to keep everything in alphabetical order.
How would I do this, do I sort the DataSet and then call the notifyDataSet Changes or do I do the sort directly on the ArrayAdapter. I've looked into performing the sort on the ArrayAdapter but this wants an argument that uses a Comparator but not sure what this is and can't find any working examples that may be of any help for what I want to achieve.
Below is the code that populates the array and sets the list adapter
ArrayList<Spanned> passwords = managePasswordList.getPasswordList();
if (passwords != null && passwords.size() > 0)
{
passwordArrayAdapter = new ArrayAdapter<Spanned>(getActivity().getApplicationContext(),
android.R.layout.simple_list_item_activated_1, passwords);
setListAdapter(passwordArrayAdapter);
myListView.setTextFilterEnabled(true);
txtNoRecords.setVisibility(View.GONE);
}
else
{
txtNoRecords.setVisibility(View.VISIBLE);
}
I am then adding data to the dataset and refreshing the list view using the following
String company = Encryption.decrypt(passwords.get(i).company);
String username = Encryption.decrypt(passwords.get(i).username);
details = Html.fromHtml(company + "<br />" + "<small><font color=\"#767676\">" + username + "</b></small>");
passwords.add(details);
passwordArrayAdapter.notifyDataSetChanged();
Thanks for any help you can provide.
UPDATE 1
I've tried doing what Nick Bradbury suggested but I am having a problem with the comparator. I have the following code but I don't know where to go from here.
SQLiteDatabase myDb = null;
Cursor cursor = null;
ArrayList<Spanned> passwords = new ArrayList<Spanned>();
try
{
myDb = context.openOrCreateDatabase("PasswordManager", Context.MODE_PRIVATE, null);
cursor = myDb.rawQuery("SELECT * FROM password ASC", null);
while (cursor.moveToNext())
{
final String company = Encryption.decrypt(cursor.getString(2));
final String username = Encryption.decrypt(cursor.getString(4));
Spanned details = Html.fromHtml(company + "<br />" + "<small><font color=\"#767676\">" + username + "</b></small>");
passwords.add(details);
Collections.sort(passwords, new Comparator<Spanned>() {
public int compare(Spanned lhs, Spanned rhs) {
return 0;
}
});
}
}
catch (SQLiteException ex)
{
common.showBasicAlertDialog("Unfortunately something has gone wrong.\n\nWe will fix this as soon as we can", false);
Log.e("Database Error", ex.toString());
return null;
}
In the return statement I have no idea what to do, I've tried return lhs.compareTo but the lhs and rhs variables don't have the compareTo function so I have not got a clue what to do.
Here's a simple example of sorting an ArrayList using Comparator. In this example, the ArrayList is defined as:
public class StatusList extends ArrayList<Status>
A sort routine for this ArrayList could look like this:
public void sort() {
Collections.sort(this, new Comparator<Status>() {
#Override
public int compare(Status item1, Status item2) {
return item2.getDate().compareTo(item1.getDate());
}
});
}
Replace <Status> with whatever object your ArrayList contains, then change the comparison to compare the values of the object you wish to sort by.

ORMLite Select Distinct Fields

I have a SQLite table (on Android) that has numerous fields, but certain fields are repeated/denormalized. I would like to select a distinct set of this data and use them as actual objects.
Example
books table
title summary author
Little Johnny A funny kid Johnny Himself
Big Johnny A funny adult Johnny Himself
I would like to extract one author from this list ("Johnny Himself") and would expect I should be able to do this with ORMLite instead of manually with Java.
I would like to select a distinct set of this data and use them as actual objects.
ORMLite supports a distinct() method on the QueryBuilder that should do what you want. So your code would look something like:
List<Book> results = booksDao.queryBuilder()
.distinct().selectColumns("author").query();
In this case, the resulting Book objects would only have the author field set and not the id field or anything else. If you just wanted the author names instead of objects then you could do:
GenericRawResults<String[]> rawResults =
booksDao.queryRaw("SELECT DISTINCT author FROM books");
for (String[] resultColumns : rawResults) {
String author = resultColumns[0];
...
}
This is my application code
public class DbHelper<T> {
private Class<T> c;
private DatabaseHelper db;
public DbHelper(Class<T> c) {
this.c = c;
db = DatabaseHelper.getInstance();
}
This is a good idea
public List<T> queryForBuilderDistinct(int offset, int limit, String ColumnsName,
String orderName, boolean isAsc) {
try {
Dao<T, Integer> dao = db.getDao(c);
QueryBuilder<T, Integer> queryBuilder = dao.queryBuilder();
if (offset != 0) {
queryBuilder.offset((long) offset);
}
if (limit != 0) {
queryBuilder.limit((long) limit);
}
if (orderName != null) {
queryBuilder.orderBy(orderName, isAsc);
}
queryBuilder.distinct().selectColumns(ColumnsName);
return dao.query(queryBuilder.prepare());
} catch (SQLException e) {
LogUtil.e(TAG, "queryForBuilderDistinct", e);
}
return new ArrayList<T>();
}

Insert TextView at Certain Spots in ListView

I have a List View that Displays songs in alphebetical order being populated by this method
public void updatelist(){
Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null,null);
int j =0;
if(cursor.moveToFirst()){
do{
int ALBUM_ID = cursor.getInt((cursor.getColumnIndex(MediaStore.Audio.AlbumColumns.ALBUM_ID)));
int pathcolumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
String path1 = cursor.getString(pathcolumn);
String album_url = null;
Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
Uri uri = ContentUris.withAppendedId(sArtworkUri, ALBUM_ID);
album_url = uri.toString();
ContentResolver res = this.getContentResolver();
// Album
String album_name = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.AlbumColumns.ALBUM));
String year = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.AudioColumns.YEAR));
// String year = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.AlbumColumns.NUMBER_OF_SONGS));
// artist
String artist_name = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.ArtistColumns.ARTIST));
// display name
String DisplayName = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME));
//title
String Title = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.TITLE));
songtitle.add(Title);
Collections.sort(songtitle);
artistname.add(songtitle.indexOf(Title), artist_name);
albumname.add(songtitle.indexOf(Title), album_name);
path.add(songtitle.indexOf(Title),path1);
albumartwork.add(songtitle.indexOf(Title),album_url);
j++;
}while(cursor.moveToNext());
}
Collections.sort(songtitle);
adapter = new ArrayAdapter<String>(this,R.layout.song,songtitle);
setListAdapter(adapter);
}
My Question is i want to insert Dividers whenever the first letter of the SongName Changes.
I have this method to get the first letter of the songname if it is different than the previous..
private void alphebetdividers(ArrayList<String> songtitle2) {
String newString = null;
// TODO Auto-generated method stub
ArrayList<Character> letters = new ArrayList<Character>();
int i = 0;
int j = 0;
while( j < songtitle.size()-1){
if(songtitle2.get(i).charAt(0) == songtitle2.get(i+1).charAt(0)){
Toast.makeText(getApplication(), songtitle2.get(i).charAt(0) + "== " + songtitle2.get(i+1).charAt(0), Toast.LENGTH_LONG).show();
}else{
// Display Char with TextView
String songName = songtitle2.get(i);
newString = songName.substring(0, 1);
}
j++;
i++;
}
How would i display this in the list view at the appropriate spots. Thank you and i will give u a good rating if u know the answer.
You probably want an Adapter that implements SectionIndexer, specifically AlphabetIndexer. See this or this.
You really should be using an Adapter... there are libraries that do all of this work for you, you shouldn't have to do it yourself in a massive loop!
Here is some sample code to help you get started... note that it is a little out-dated in that it makes use of some deprecated methods (such as managedQuery, etc.). If you wanted to be entirely 100% correct you would want to make use of the LoaderManager.LoaderCallbacks<Cursor interface introduced in the Honeycomb release, but it's a good start.
To sort the displayed views, you can make use of the sortOrder argument in the ContentProvider's query method.

Categories

Resources