Adapter is not displaying data, only after search - android

Thanks for your time in advance. I'm new to android and I'd like to learn more. I have a code that is displaying data from sql only after search is clicked and I don't know how can I make it display all the data from sql with let's say alfabetical order at first and later on if search is used it will display data matching to search request.
public class EmployeeList extends ListActivity {
protected EditText searchText;
protected SQLiteDatabase db;
protected Cursor cursor;
protected ListAdapter adapter;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
searchText = (EditText) findViewById(R.id.searchText);
db = (new DatabaseHelper(this)).getWritableDatabase();
}
public void onListItemClick(ListView parent, View view, int position, long id) {
Intent intent = new Intent(this, EmployeeDetails.class);
Cursor cursor = (Cursor) adapter.getItem(position);
intent.putExtra("EMPLOYEE_ID", cursor.getInt(cursor.getColumnIndex("_id")));
startActivity(intent);
}
public void search(View view) {
// || is the concatenation operation in SQLite
cursor = db.rawQuery("SELECT _id, firstName, lastName, title FROM employee WHERE firstName || ' ' || lastName LIKE ?",
new String[]{"%" + searchText.getText().toString() + "%"});
adapter = new SimpleCursorAdapter(
this,
R.layout.employee_list_item,
cursor,
new String[] {"firstName", "lastName", "title"},
new int[] {R.id.firstName, R.id.lastName, R.id.title});
setListAdapter(adapter);
}
}
Thanks.

i see you are using onClick in XML layout , right?
any ways, no problem.
add new method populateList() as following
public void populateList(boolean useWhere) {
// || is the concatenation operation in SQLite
if(useWhere){
cursor = db.rawQuery("SELECT _id, firstName, lastName, title FROM employee WHERE firstName || ' ' || lastName LIKE ?", new String[]{"%" + searchText.getText().toString() + "%"});
}else{
cursor = db.rawQuery("SELECT _id, firstName, lastName, title FROM employee");
}
adapter = new SimpleCursorAdapter(
this,
R.layout.employee_list_item,
cursor,
new String[] {"firstName", "lastName", "title"},
new int[] {R.id.firstName, R.id.lastName, R.id.title});
setListAdapter(adapter);
}
change search() as following:
public void search(View view){
populateList(true);
}
add a call populateList(false); to onCreate() of the activity.
so oncreate activity, will call search to execuste without WHERE and when c alled from button click, it will execute the WHERE sql
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
searchText = (EditText) findViewById(R.id.searchText);
db = (new DatabaseHelper(this)).getWritableDatabase();
populateList(false);
}

Related

How to fetch data for a specific category in listview?

My MainActivity have a listview with some categories,If I click a particular category in my listview,it's need to redirect to another activity,which need to have the details of that particular category.
Eg: IF I select FOOD in Mainactivity,I want to redirect to another activity where the activity want to have the budget amount of food.
public class addbudget extends ActionBarActivity implements View.OnClickListener{
SimpleCursorAdapter adapter;
DBhelper helper;
SQLiteDatabase db;
EditText txtBudget;
TextView txr;
ListView rldlist,list;
Button btn66;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addbudget);
btn66=(Button)findViewById(R.id.btn_addBudget);
btn66.setOnClickListener(this);
helper=new DBhelper(addbudget.this);
txr=(TextView)findViewById(R.id.addbud);
txtBudget=(EditText)findViewById(R.id.etBudget);
rldlist = (ListView) findViewById(R.id.rldlist);
list = (ListView) findViewById(R.id.list);
Bundle data_from_list= getIntent().getExtras();
String value_in_tv= data_from_list.getString("passed data key");
txr.setText(value_in_tv);
fetchData2();
}
private void clearfield(){
txtBudget.setText("");
}
public void onClick(View v) {
if (btn66 == v) {
ContentValues value = new ContentValues();
value.put(DBhelper.Amount, txtBudget.getText().toString());
value.put(DBhelper.Description,txr.getText().toString());
if (txtBudget.length() == 0) {
txtBudget.requestFocus();
txtBudget.setError("Field Cannot Be Empty");
} else {
db = helper.getWritableDatabase();
db.insert(DBhelper.TABLE2, null, value);
db.close();
clearfield();
Toast.makeText(this, "Budget add Successfully", Toast.LENGTH_LONG).show();
fetchData2();
}
}
}
private void fetchData2() {
db = helper.getReadableDatabase();
Cursor c = db.query(DBhelper.TABLE2, null, null, null, null, null, null);
adapter = new SimpleCursorAdapter(
this,
R.layout.row2,
c,
new String[]{DBhelper.Amount},
new int[]{R.id.lbl});
list.setAdapter(adapter);
}
}
This is how ,I'm fetching data to a listview from database.Here I'm fetching Amount from database.
How can I change the fetchdata method to get the BudgetAmount of a specific category ?(I'm using bundle to get the name of the category from the listview of MainActivity)
You can use sql syntax:
String sql = "select * from DBhelper.TABLE2 where category_name_column = " + category";
Cursor c = db.rawQuery(sql.toString(), null);
Or if you want to use params:
String whereClause = "your_category_column = ?";
String[] whereArgs = new String[] {
"category_name"
};
Cursor c = db.query(DBhelper.TABLE2, null, whereClause, whereArgs, null, null, null);
So your method can be as such:
private void fetchData2(String category) {
db = helper.getReadableDatabase();
String whereClause = "your_category_column = ?";
String[] whereArgs = new String[] {"category"};
Cursor c = db.query(DBhelper.TABLE2, null, whereClause, whereArgs, null, null, null);
adapter = new SimpleCursorAdapter(
this,
R.layout.row2,
c,
new String[]{DBhelper.Amount},
new int[]{R.id.lbl});
list.setAdapter(adapter);
}

How to search the data in listview by more than one thing?

Right now, my app filters the data in a listview when somethings is entered into the editText, but it can only filter by one thing at a time. I want it to be able to filter by more than value. For example, if someone types in "chicken" it should filter the recipes by the word 'chicken'. But, if someone then types in "dinner", I want it to filter the recipes by both "chicken" and "dinner." Eventually, I want to make it so those values appear as checkboxes above the listview so they can be easily removed.
I can't figure out how to do this. I played around with loops at first but didn't really get anywhere.
public class SearchActivity extends NavDrawerActivity {
private DBHandler dbHelper;
private SimpleCursorAdapter dataAdapter;
ArrayList<String> filters = new ArrayList<String>();
//String[] filters;
FrameLayout frameLayout;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main_activity3);
frameLayout = (FrameLayout) findViewById(R.id.activity_frame);
// inflate the custom activity layout
LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View activityView = layoutInflater.inflate(R.layout.activity_main_activity3, null, false);
// add the custom layout of this activity to frame layout.
frameLayout.addView(activityView);
dbHelper = new DBHandler(this, null, null, 1);
//dbHelper.open();
//Clean all data
dbHelper.deleteAllRecipes();
//Add some data
dbHelper.insertSomeRecipes();
//Generate ListView from SQLite Database
displayListView();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
private void displayListView() {
final Cursor cursor = dbHelper.fetchAllRecipes();
// The desired columns to be bound
String[] columns = new String[]{
//DBHandler.COLUMN_CODE,
DBHandler.COLUMN_NAME,
DBHandler.COLUMN_TYPE,
DBHandler.COLUMN_INGRED
};
// the XML defined views which the data will be bound to
int[] to = new int[]{
//R.id.code,
R.id.name,
R.id.type,
R.id.ingredient,
};
// create the adapter using the cursor pointing to the desired data
//as well as the layout information
dataAdapter = new SimpleCursorAdapter(
this, R.layout.recipeinfo,
cursor,
columns,
to,
0);
ListView listView = (ListView) findViewById(R.id.listView1);
// Assign adapter to ListView
listView.setAdapter(dataAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> listView, View view,
int position, long id) {
// Get the cursor, positioned to the corresponding row in the result set
Cursor cursor = (Cursor) listView.getItemAtPosition(position);
String recipeName = cursor.getString(cursor.getColumnIndexOrThrow("name"));
Intent n = new Intent(getApplicationContext(), RecipeActivity.class);
//n.putExtra("position", position);
n.putExtra("recipeName", recipeName);
startActivity(n);
}
});
//final GridView gridView = (GridView)findViewById(R.id.gridView);
final TextView tv = (TextView)findViewById(R.id.textView14);
final EditText myFilter = (EditText) findViewById(R.id.myFilter);
myFilter.setImeActionLabel("Filter",1);
myFilter.setPrivateImeOptions("actionUnspecified");
myFilter.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
if (id == 1 || id == EditorInfo.IME_NULL) {
String filter = textView.getText().toString();
dataAdapter.getFilter().filter(filter);
filters.add(filter);
tv.append(filter);
myFilter.setText("");
}
return false;
}
});
dataAdapter.setFilterQueryProvider(new FilterQueryProvider() {
public Cursor runQuery(CharSequence constraint) {
return dbHelper.fetchRecipesByName(constraint.toString());
}
});
}
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// Then you start a new Activity via Intent
Intent intent = new Intent();
intent.setClass(this, RecipeActivity.class);
intent.putExtra("position", position);
// Or / And
intent.putExtra("id", id);
startActivity(intent);
}
}
fetchRecipesByName in DBHandler
public Cursor fetchRecipesByName(String inputText) throws SQLException {
SQLiteDatabase mDb = this.getWritableDatabase();
Log.w(TAG, inputText);
Cursor mCursor = null;
if (inputText == null || inputText.length () == 0) {
mCursor = mDb.query(SQLITE_TABLE, new String[] {COLUMN_ROWID,
COLUMN_NAME, COLUMN_TYPE, COLUMN_INGRED, COLUMN_IMGPATH},
null, null, null, null, null);
}
else {
mCursor = mDb.query(true, SQLITE_TABLE, new String[] {COLUMN_ROWID,
COLUMN_NAME, COLUMN_TYPE, COLUMN_INGRED, COLUMN_IMGPATH},
COLUMN_NAME + " like '%" + inputText + "%'" + " or " +
COLUMN_TYPE + " like '%" + inputText + "%'" + " or " +
COLUMN_INGRED + " like '%" + inputText + "%'",
null, null, null, null, null);
}
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
What is the implementation of dbHelper.fetchReccipesByName()? I think, as of now, it queries the table only by one thing. You should change its logic and implement your complex need in this method (obviously, it should be an SQL query execution).
As a best practice, you should call listView.setFilterText() instead of dataAdapter.getFilter().filter(), because this method is supposed to run in secondary thread for the reason that DB queries are time consuming. If you call listView.setFilterText(), the framework will take care of threading and calls filter.filter() in secondary thread.
And finally, since you are searching by more than one keyword, but setFilterText() accepts only one CharSequence param, you should encode somehow many keywords into single String (say comma separated). And while querying you could decode the constraint to get the keywords.

Reapeated columns using setFilterQueryProvider

I have a listview with a problem. I want to implement the classic search with the edittext, i am using the addTextChangedListener with TextWatcher(). The Listview gets the elements from a database so I use cursor and simplecursoradapter so i have to use the setFilterQueryProvider. The problem appears when I write something in the edittext, if I write the name of a product it changes all the names of the elements in the list.So i dont know what to do. Appreciate the help.
here is my java code with the listview:
public class Lista_general extends ListActivity {
SimpleCursorAdapter adapter;
ListView list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lista_general);
list = getListView();
EditText edit =(EditText)findViewById(R.id.edit);
// open database
AdminSQLiteOpenHelper dbhelper = new AdminSQLiteOpenHelper(
getBaseContext());
SQLiteDatabase db = dbhelper.getReadableDatabase();
// array for SimpleCursorAdapter
String columns[] = new String[] { "PRODUCTO._id",
"nombre","category","CATEGORIAS._id","categoryid" };
String orderBy = "category";
// query database
Cursor c = db.query("PRODUCTO, CATEGORIAS WHERE CATEGORIAS._id = categoryid ",
columns,null,null, null, null, orderBy);
c.moveToFirst();
// array for SimpleCursorAdapter
String from[] = new String[] { "nombre", "category", };
//String from[] = new String[] { "nombre", "categoria", };
int to[] = new int[] { R.id.name, R.id.cate, };
// Adapter
adapter = new SimpleCursorAdapter(getBaseContext(),
R.layout.productos, c, from, to,
SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
setListAdapter(adapter);
list.setTextFilterEnabled(true);
//Listener edit text
edit.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
#Override
public void afterTextChanged(Editable s) {
adapter.getFilter().filter(s.toString());
}
});
adapter.setFilterQueryProvider(new FilterQueryProvider() {
#Override
public Cursor runQuery(CharSequence constraint) {
// TODO Auto-generated method stub
AdminSQLiteOpenHelper dbhelper = new AdminSQLiteOpenHelper(
getBaseContext());
SQLiteDatabase db = dbhelper.getReadableDatabase();
Cursor mCursor = null;
if (constraint == null || constraint.length () == 0) {
mCursor = db.query("PRODUCTO, CATEGORIAS", new String[] {
"PRODUCTO._id", "nombre","CATEGORIAS._id","category"},
null, null, null, null, null);
}
else {
mCursor = db.query(true,"PRODUCTO, CATEGORIAS", new String[]
{"PRODUCTO._id", "nombre", "category","CATEGORIAS._id"},
"nombre" + " like '%" + constraint + "%'", null,
null, null, null, null);
}
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
});
}
Here is a visual of my error:
first my normal list:
http://i40.tinypic.com/2111k0p.png
after I wrote:
http://i44.tinypic.com/23j04kg.png
It looks like the queries generated in the FilterQueryProvider are not joining the tables properly, so that you end up with every possible combination of PRODUCTO and CATEGORIAS (which are then filtered by PRODUCTO.nombre to give the impression that all the names have changed).
There's also a potential security risk with inserting constraint directly into the query, this opens the door to SQL injection attacks. I'm not sure how serious this is in the context of Android apps, but in for example a PHP web application this would allow anyone to execute any SQL they wished by entering a carefully crafted constraint.
From the answers to this question it looks like a rawQuery() call is needed in order to use SQL JOIN so I would change your queries as follows...
For querying with no filter (i.e. in onCreate(); and in runQuery() where there is no constraint):
cursor = db.rawQuery("SELECT PRODUCTO._id, nombre, category, CATEGORIAS._id FROM PRODUCTO INNER JOIN CATEGORIAS ON PRODUCTO.categoryid = CATEGORIAS._id", null);
For querying with a filter:
String[] params = { constraint.toString() };
cursor = db.rawQuery("SELECT PRODUCTO._id, nombre, category, CATEGORIAS._id FROM PRODUCTO INNER JOIN CATEGORIAS ON PRODUCTO.categoryid = CATEGORIAS._id WHERE nombre LIKE ('%' || ? || '%')", params);

Edittext only adding first item to arraylist<string>

I'm at a lose with this one. Trying to take edittext from a list view and put them into an arraylist to use on another activity.
public class editpage extends ListActivity {
public static String editString;
private dbadapter mydbhelper;
public static ArrayList<String> editTextList = new ArrayList<String>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.edit_list);
mydbhelper = new dbadapter(this);
mydbhelper.open();
fillData();
}
public void fillData() {
Cursor e = mydbhelper.getUserWord();
startManagingCursor(e);
String[] from = new String[] {dbadapter.KEY_USERWORD,};
int[] to = new int[] {R.id.textType,};
SimpleCursorAdapter editadapter =
new SimpleCursorAdapter(this, R.layout.edit_row, e, from, to);
ListView list = getListView();
View footer = getLayoutInflater().inflate(R.layout.footer_layout, list, false);
list.addFooterView(footer);
setListAdapter(editadapter);
}
public void onClick(View footer){
final MediaPlayer editClickSound = MediaPlayer.create(this, R.raw.button50);
final EditText editText = (EditText) findViewById(R.id.editText);
for (int i = 0; i < getCount(); i++){
editTextList.add(editText.getText().toString());
}
editClickSound.start();
startActivity(new Intent("wanted.pro.madlibs.OUTPUT"));
};
//can't get my getcount to work dynamically. I want it to be based off how many items are shown in next code showing my cursor but can't get to work atm unless I set statically to prevent errors and move to next activity
private int getCount() {
// TODO Auto-generated method stub
return 10;
}
Cursor to filter data pulled from database
public Cursor getUserWord()
{
return myDataBase.query(USER_WORD_TABLE, new String[] {
KEY_ID,
KEY_CATEGORY,
KEY_SOURCE, KEY_TITLE, KEY_USERWORD
},
KEY_CATEGORY+ "=" + categories.categoryClick + " AND " + KEY_SOURCE+ "="
+source.sourceClick + " AND " + KEY_TITLE+ "=" + title.titleClick,
null, null, null, KEY_ID);
Cursor to filter data from database to show in listview
public Cursor getUserWord()
{
return myDataBase.query(USER_WORD_TABLE, new String[] {
KEY_ID,
KEY_CATEGORY,
KEY_SOURCE, KEY_TITLE, KEY_USERWORD
},
KEY_CATEGORY+ "=" + categories.categoryClick + " AND " + KEY_SOURCE+ "="
+source.sourceClick + " AND " + KEY_TITLE+ "=" + title.titleClick,
null, null, null, KEY_ID);
}
My next activity will be showing the edittext merged with a string from my database. I take this string and replace edit01, edit02 etc with the users input from edittext fields on previous activity
public class output extends ListActivity {
private dbadapter mydbhelper;
#Override
public void onCreate(Bundle savedInstantState){
super.onCreate(savedInstantState);
setContentView(R.layout.outview);
mydbhelper = new dbadapter(this);
mydbhelper.open();
fillData();
}
private final Runnable mTask = new Runnable(){
public void run(){
TextView textView = (TextView)findViewById(R.id.outputText);
String story = textView.getText().toString();
CharSequence modifitedText1 = Replacer.replace(story,
"edit01", Html.fromHtml("<font color=\"red\">"+ editpage.editTextList.get(0) +"</font>"));
CharSequence modifitedText2 = Replacer.replace(modifitedText1,
"edit02", Html.fromHtml("<font color=\"red\">"+ editpage.editTextList.get(1) +"</font>"));
textView.setText(modifitedText2);
}
};
private final Handler mHandler = new Handler();
private void fillData() {
Cursor st = mydbhelper.getStory();
startManagingCursor(st);
String[] from = new String[] {dbadapter.KEY_TITLESTORY};
int[] to = new int[] {R.id.outputText};
SimpleCursorAdapter adapter =
new SimpleCursorAdapter(this, R.layout.out_row, st, from, to);
setListAdapter(adapter);
}
#Override
protected void onResume() {
mydbhelper.open();
mHandler.postDelayed(mTask, 10);
super.onResume();
}
#Override
protected void onPause() {
mydbhelper.close();
super.onPause();
}
}
The furthest I can get this to work is with one item. I will be having anywhere from 4-10 edittexts on the first activity I show here. But no matter what I've tried it will only display the text entered into the first edittext field. In it's current state it will fill edit01 & edit02 in the string from database with what was put in first edittext in previous activity.
Well was finally able to get this to work without changing to much. I had to fight with it and try a bunch of things. Figured I would share the answer in case someone tries something like this. It came down to changing (R.id.editText) to have its own unique id.
private void editId(){
if(findViewById(R.id.editText) == null){
}else{
for(int editI= 0; editI<getCount(); editI++){
EditText editText = (EditText) findViewById(R.id.editText);
editText.setId(editI);
m_edit.add(editI, editText);
}}
}
and calling editId() in my onclick for my footer button
I had to change my runnable to work dynamically but that is another issue.

SimpleCursorAdapter isnt binding data to listView

How do I bind information from my database to a TextView? The ListView Isnt showing the information from the Cursor. Do I need to use the adapter I have created?
I'm trying to display the results in TextViews withing the List.
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.contactform);
Cursor cursor = getCursor();
SimpleCursorAdapter adapter = new SimpleCursorAdapter(
this, //Context
R.layout.contactform, //xml definintion of each listView item
cursor, //Cursor
new String[] {"FirstName", "LastName", "Phone", "Email"}, //Columns to select From
new int[] {R.id.contact_firstname, R.id.contact_lastname, R.id.contact_phone, R.id.contact_email} //Object to bind to
);
}
private Cursor getCursor()
{
String TABLE_NAME = "exampleContacts";
String[] FROM = {"_id", ""FirstName", "LastName", "Phone", "Email"} ;
dbManager = new DatabaseManager(this);
SQLiteDatabase db = dbManager.getReadableDatabase();
Cursor cursor = db.query(TABLE_NAME, FROM, "ContactID=?", new String[] {PrContactID}, null, null, null);
startManagingCursor(cursor);
return cursor;
}
It looks like you're pulling back a single record. In that case, you don't need to be using the SimpleCursorAdapter, as that is generally used for assigning multiple records to a ListView. Why not just grab the info you need and manually set them to your TextView(s)?
Also, you shouldn't need to use a manage cursor. Just get the values you need and then close the cursor like so:
TextView textView = (TextView) findViewById(R.id.textView01);
Cursor cursor = db.query("exampleContacts", new String[] {"FirstName", "LastName", "Phone", "Email"}, "ContactID=?", new String[] {PrContactID}, null, null, null);
cursor.moveToFirst();
String text = cursor.getString(0) + " " + cursor.getString(1) + " " + cursor.getString(2) + " " + cursor.getString(3);
textView.setText(text);
cursor.close();
Sorry for any typos... this code is just for example and hasn't been tested.
The reason it wasnt being mapped to the ListView is because setListAdapter(); wasnt being used.
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.contactform);
Cursor cursor = getCursor();
SimpleCursorAdapter adapter = new SimpleCursorAdapter(
this, //Context
R.layout.contactform, //xml definintion of each listView item
cursor, //Cursor
new String[] {"FirstName", "LastName", "Phone", "Email"}, //Columns to select From
new int[] {R.id.contact_firstname, R.id.contact_lastname, R.id.contact_phone, R.id.contact_email} //Object to bind to
);
setListAdapter(adapter);
}

Categories

Resources