How to Implement Search in Customlistview Based on Class Item of Pojo Class in Android

How to implement search in CustomListView based on class item of POJO class in Android?

You want your adapter to implement Filterable. Then override getFilter to perform the search

@Override
public Filter getFilter() {
return new Filter() {
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results != null && results.count >= 0) {
setData(results.values);
} else {
setData(mPostingData);
}

notifyDataSetInvalidated();
}

@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults result = new FilterResults();
if (!TextUtils.isEmpty(constraint)) {
constraint = constraint.toString().toLowerCase();
ArrayList<PostData> currentItems = new ArrayList<PostData>();
ArrayList<PostData> foundItems = new ArrayList<PostData>();

currentItems.addAll(mPostingData);

for (PostData post: currentItems){
// Search for the items here. If we get a match, add to the list
if (post.mType.toLowerCase().contains(constraint)) {
foundItems.add(m);
} else if .... {
}
}

result.count = foundItems.size();
result.values = foundItems;
} else {
result.count = -1;
}

return result;
}
};
}

You would then call the search from the activity with adapter.getFilter().filter("Search Query").

This will replace the list of items in your listview with the search results too.

Filtering listview of custom POJO's by their fields

After OP's request I post my comment as an answer for future reference, giving more details. Here are some possible solutions:

  1. Destructive update: Loop through the list, filtering out what you don't need. Implement adapter based on this list.

  2. Virtual view: Implement logic for a "virtual view" over the original list. Here you keep only the original list, but in all adapter's methods you skip items that don't match the filter. For instance, in getItem(int pos) you loop through the list keeping a counter, but you increment it only if the item matches the filter: when the counter equals pos you return the item. Similar for the other methods.

  3. Concrete View: Use an additional list to keep the "view" over the original list, so to cache the computation done in 2. When the filter is set/updated, a loop through the original list builds the "view" and then you implement the adapter based on the "view". More time efficient, but also more memory consumed.

Search in a Custom listView, from the toolbar - Kotlin

I hope this will work for you

In Activity on Create() method get data from local Database instead of in Adapter.

so onCreate() method is:

 override fun onCreate(savedInstanceState: Bundle?) {
...
setSupportActionBar(toolbar)
supportActionBar!!.setDisplayHomeAsUpEnabled(true)

var db = DataBaseHandler(context)
var data = db.DataExample() //this method must be return interms of your pojo class type.

var listView = findViewById<ListView>(R.id.listView)
val customAdptor = CustomAdapterBJCP(this,data)
listView.adapter=customAdptor
}

override fun onCreateOptionsMenu(menu: Menu): Boolean {

menuInflater.inflate(R.menu.menu_main,menu)
val searchItem = menu.findItem(R.id.action_search)
if(searchItem!=null){
val searchView=searchItem.actionView as SearchView
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
return true
}

override fun onQueryTextChange(newText: String?): Boolean {
if (newText != null) {
/* var dataList : List<Your Pojo Class> = list.filter { it.name.startsWith(newText) }
.sortedBy { it.name }*/

var dataList: MutableList<Your Pojo Class> = data.filter { it.name.startsWith(newText) }.toMutableList() // data is list (i.e you get data from db)

if (dataList.size.equals(0)) {
Toast.makeText(this@MainActivity, "No Record Found", Toast.LENGTH_SHORT).show()
}

for (item in dataList) {
System.out.println("Searched Data: " + item.name)
}

customAdptor = CustomAdapterBJCP(dataList , this@Your Activity)
listView.adapter = customAdptor
customAdptor?.notifyDataSetChanged

}
return true

}

})
}
return super.onCreateOptionsMenu(menu)
}

Modify your adapter

class CustomAdapterBJCP(private val context: Context, var data: MutableList<Your Pojo Class>)BaseAdapter(){

// var db = DataBaseHandler(context)
//var data = db.DataExample()

override fun getView(p0: Int, p1: View?, p2: ViewGroup?): View {
val inflater = context.layoutInflater
val view1 = inflater.inflate(R.layout.CustomList,null)
var fName= view1.findViewById<TextView>(R.id.txtOne)
var FDetail= view1.findViewById<TextView>(R.id.txtTwo)
var fCount = view1.findViewById<TextView>(R.id.txtThree)

fName.text = data.get(p0).name
FDetail.text = data.get(p0).detail
fCount .text= data.get(p0).count
return view1
}

override fun getItem(p0: Int): Any {
return data.get(p0).name
}

override fun getItemId(p0: Int): Long {
return p0.toLong()
}

override fun getCount(): Int {
return data.count()
}
}

implement search filter on listview filled from database

I had to implement this for an App I made a while ago. Since it's open source you can take a look at the code. I used SearchView for this.

https://github.com/royale1223/HwaSettings

Search Bar in application

Have a editext at the top of your listview. I suggest you to have a custom list adapter.

Have a list of original values for database.

Have another list to set temporary data to match the search criteria.

If your search criteria matches one in the list add those to founditmes and display the data in the list. If it does not match display original data in the list.

I have given a general idea. The below code can be modified according to your needs. I have implemented the search myself and it works.

I asked a question in SO and i got the answer from How to implement search in CustomListView based on class item of POJO class in Android?.

Try the below and if you are not able to get it working you can always post a question in SO.

     search= (EditText) findViewById(R.id.search);
//look for text changing in edittext.
search.addTextChangedListener(new TextWatcher() {

public void onTextChanged(CharSequence s, int start, int before, int count) {
youradapter.getFilter().filter(s);
youradapter.notifyDataSetChanged();

}

public void beforeTextChanged(CharSequence s, int start, int count,
int after) {

}

public void afterTextChanged(Editable s) {
}
});

Implement a filter on your list

 public void setData(ArrayList mPpst) {   
set data either searched data or original values from database
mPostingData = mPpst;//contains class items data.
}

@Override
public Filter getFilter() {
return new Filter() {
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results != null && results.count >= 0) {
setData( results.values);//if results match set data
} else {
setData(mOri);// set data for listview original values.
}

notifyDataSetInvalidated();
}

@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults result = new FilterResults();
if (!TextUtils.isEmpty(constraint)) {
ArrayList foundItems = new ArrayList();
constraint = constraint.toString().toLowerCase();
if(listitems!=null)
{
if(listitems.equals(constarint))//matching
foundItems.add(listitems);

}
else
{

}
}
}
result.count = foundItems.size();//search results found return count
result.values = foundItems;// return values
}
else
{
result.count=-1;// no search results found
}

return result;
}
};
}

Edit 1

how to set json parsed data in a listview and then adding search functionality in it. The answer in the link works. I have used temporary data and did a search function on it. You can display data form database and modify the same.

Edit 2:

 public class MainActivity extends Activity {

// List view
private ListView lv;

// Listview Adapter
ArrayAdapter<String> adapter;

// Search EditText
EditText inputSearch;

// ArrayList for Listview
ArrayList<HashMap<String, String>> productList;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// Listview Data
String products[] = {"aaa","bbbb","cccc","dddd"};

lv = (ListView) findViewById(R.id.list_view);
inputSearch = (EditText) findViewById(R.id.inputSearch);

// Adding items to listview
adapter = new ArrayAdapter<String>(this, R.layout.list_item, R.id.product_name, products);
lv.setAdapter(adapter);

/**
* Enabling Search Filter
* */
inputSearch.addTextChangedListener(new TextWatcher() {

@Override
public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
// When user changed the Text
MainActivity.this.adapter.getFilter().filter(cs);
}

@Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub

}

@Override
public void afterTextChanged(Editable arg0) {
// TODO Auto-generated method stub
}
});
}

}

Edit 3 Search with data from Database

 public class SearchActivity extends ListActivity {
ArrayAdapter<String> dataAdapter = null;

private ArrayList<String> results = new ArrayList<String>();
private String tableName = DatabaseHandler.TABLE_SEARCH;
private SQLiteDatabase newDB;
ArrayAdapter<String> adapter = null;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.page_search);

DatabaseHandler dbHelper = new DatabaseHandler(this.getApplicationContext());
newDB = dbHelper.getWritableDatabase();
Cursor c = newDB.rawQuery("SELECT skeys FROM " +
tableName, null);
if (c != null ) {
if (c.moveToFirst()) {
do {
String skeys = c.getString(c.getColumnIndex("skeys"));
results.add(skeys);
}while (c.moveToNext());
}
}

dataAdapter = new ArrayAdapter<String>(this,
R.layout.listviews_search, results);

setListAdapter(new ArrayAdapter<String>(this,
R.layout.listviews_search, results));

ListView listView = (ListView) findViewById(android.R.id.list);
listView.setAdapter(dataAdapter);
listView.setTextFilterEnabled(true);

listView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Toast.makeText(getApplicationContext(),
((TextView) view).getText(), Toast.LENGTH_SHORT).show();
}
});

EditText myFilter = (EditText) findViewById(R.id.search);
myFilter.addTextChangedListener(new TextWatcher(){
public void afterTextChanged(Editable s) {
}

public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}

public void onTextChanged(CharSequence s, int start, int before, int count) {
dataAdapter.getFilter().filter(s.toString());
}
});
}
}

Android Search in ListView not working properly

Realize that when you filter you are replacing your unfiltered results in your ArrayList with your filtered results. When you hit backspace to delete characters you are trying to now filter based on your already filtered list which is why your results won't change. You will need to keep a reference to your original data set that doesn't have any filter applied to it and always filter using that, but never change/replace it.

how to store value of checkboxes when creating a custom listView android

Your Custom Adapter must implement CompoundButton.OnCheckedChangeListener. Use a SparseBooleanArray.

Drawing from Romain guy's solution @

https://groups.google.com/forum/?fromgroups#!topic/android-developers/No0LrgJ6q2M

Then

     cb.setChecked(mCheckStates.get(position, false)); 
cb.setOnCheckedChangeListener(this);

Then use the checked state to set text to check box

      public boolean isChecked(int position) {
return mCheckStates.get(position, false);
}

public void setChecked(int position, boolean isChecked) {
mCheckStates.put(position, isChecked);

}

public void toggle(int position) {
setChecked(position, !isChecked(position));
}
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
mCheckStates.put((Integer) buttonView.getTag(), isChecked);

}

Use the below example as reference and modify according your requirements. I have not used a viewholder in the sample. Use a view holder as you used in your code.

Example

public class MainActivity extends Activity implements
AdapterView.OnItemClickListener {
int count;
private CheckBoxAdapter mCheckBoxAdapter;

String[] GENRES = new String[] {
"Action", "Adventure", "Animation", "Children", "Comedy",
"Documentary", "Drama",
"Foreign", "History", "Independent", "Romance", "Sci-Fi",
"Television", "Thriller"
};

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ListView listView = (ListView) findViewById(R.id.lv);

listView.setItemsCanFocus(false);
listView.setTextFilterEnabled(true);
listView.setOnItemClickListener(this);
mCheckBoxAdapter = new CheckBoxAdapter(this, GENRES);
listView.setAdapter(mCheckBoxAdapter);
Button b= (Button) findViewById(R.id.button1);
b.setOnClickListener(new OnClickListener()
{

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
StringBuilder result = new StringBuilder();
for(int i=0;i<GENRES.length;i++)
{
if(mCheckBoxAdapter.mCheckStates.get(i)==true)
{
result.append(GENRES[i]);
result.append("\n");
}

}
Toast.makeText(MainActivity.this, result, 1000).show();
}

});

}

public void onItemClick(AdapterView parent, View view, int
position, long id) {
mCheckBoxAdapter.toggle(position);
}

class CheckBoxAdapter extends ArrayAdapter implements CompoundButton.OnCheckedChangeListener
{ private SparseBooleanArray mCheckStates;
LayoutInflater mInflater;
TextView tv1,tv;
CheckBox cb;
String[] gen;
CheckBoxAdapter(MainActivity context, String[] genres)
{
super(context,0,genres);
mCheckStates = new SparseBooleanArray(genres.length);
mInflater = (LayoutInflater)MainActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
gen= genres;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return gen.length;
}

@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return position;
}

@Override
public long getItemId(int position) {
// TODO Auto-generated method stub

return 0;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View vi=convertView;
if(convertView==null)
vi = mInflater.inflate(R.layout.checkbox, null);
tv= (TextView) vi.findViewById(R.id.textView1);

cb = (CheckBox) vi.findViewById(R.id.checkBox1);
tv.setText("Name :"+ gen [position]);
cb.setTag(position);
cb.setChecked(mCheckStates.get(position, false));
cb.setOnCheckedChangeListener(this);
return vi;
}
public boolean isChecked(int position) {
return mCheckStates.get(position, false);
}

public void setChecked(int position, boolean isChecked) {
mCheckStates.put(position, isChecked);

}

public void toggle(int position) {
setChecked(position, !isChecked(position));
}
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {

mCheckStates.put((Integer) buttonView.getTag(), isChecked);

}

}

}

checkbox.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="15dp"
android:layout_marginTop="34dp"
android:text="TextView" />

<CheckBox
android:id="@+id/checkBox1"
android:focusable="false"
android:focusableInTouchMode="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="@+id/textView1"
android:layout_marginRight="22dp"
android:layout_marginTop="23dp" />

</RelativeLayout>


Related Topics



Leave a reply



Submit