Reputation: 1224
I want to search through the list and display the result in the list again so I used addtextchangelistener, but can't find a way to make it work with listview with subtext
Here's my code:
package com.android;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import android.app.ListActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
public class MyListDemoActivity extends ListActivity {
/** Called when the activity is first created. */
TextView tv;
//** List<String> content;
EditText actv;
List<String> arr_sort;
//** ArrayAdapter<String> adapter;
SimpleAdapter simpleadapter;
ListView lv;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String line = " ";
LineNumberReader linenoreader = null;
StringTokenizer stringtokanixer = null;
//** content = new ArrayList<String>();
List<Map<String,String>> data= new ArrayList<Map<String,String>>();
lv = (ListView) findViewById(android.R.id.list);
try {
InputStream istream = getResources().openRawResource(R.raw.grelist);
InputStreamReader streamreader = new InputStreamReader(istream);
linenoreader = new LineNumberReader(streamreader);
linenoreader.mark(15);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}// try catch ends here
Log.v("getting", "working");
for(int i=0;i<8;i++)
{
Map<String,String> datum= new HashMap<String,String>(2);
try {
line = linenoreader.readLine();
Log.v("item",line);
} catch (IOException e) {
e.printStackTrace();
}
Log.v("getting", line);
stringtokanixer = new StringTokenizer(line);
String st = stringtokanixer.nextToken();
String meaning="";
while (stringtokanixer.hasMoreTokens()) {
meaning +=" " +stringtokanixer.nextToken();
}// for ends
// map is used to add word and meaning
datum.put("word",st);
datum.put("meaning",meaning);
data.add(datum);
//List<String> is usedto add
//** content.add(st);
}
simpleadapter = new SimpleAdapter(this, data, android.R.layout.simple_list_item_2, new String[]{"word","meaning"}, new int[]{android.R.id.text1,android.R.id.text2});
// setListAdapter(adapter);
lv.setAdapter(simpleadapter);
tv = (TextView) findViewById(R.id.textView1);
actv = (EditText) findViewById(R.id.editText1);
/*
actv.addTextChangedListener(new TextWatcher() {
int len = 0;
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
arr_sort = new ArrayList<String>();
len = actv.getText().length();
for (int i = 0; i < content.size(); i++) {
if (len <= content.get(i).length()) {
if (actv.getText()
.toString()
.trim()
.equalsIgnoreCase(
(String) content.get(i).subSequence(0,
len))) {
arr_sort.add(content.get(i));
Log.v("infor loop afterTextChanged", s.toString());
}
}
}
// adapter.notifyDataSetChanged();
adapter = new ArrayAdapter<String>(MyListDemoActivity.this,
android.R.layout.simple_list_item_1, arr_sort);
setListAdapter(adapter);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
Log.v("beforetextchange","hello here");
}
@Override
public void afterTextChanged(Editable s) {
Log.v("aftertextchange","hello here");
}
}); // text watcher class ends here
*/
}// on create ends here
public void onListItemClick(ListView ls, View v, int position, long id) {
//tv.setText(content.get(position));
// tv.setText(content[position]) // in case of string
}// endsd here onListItemClick(
}
Upvotes: 4
Views: 6003
Reputation: 67286
I have answered already in two of the StackOverflow questions itself you can them,
First is using getFilter()
that android provides for Filtering using Filterable interface to the Adapter class. You can check it from here
.
Second is using an external jar Lambdaj
which is the best and efficient way of filtering a huge data from a List. You can check that also from here
.
Upvotes: 4
Reputation: 30594
What I understood is:- Simply you want to filter the ListView
. Right?
Let me know If I've misunderstood the question!!!
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<EditText android:id="@+id/search" android:layout_width="fill_parent" android:layout_height="wrap_content"
android:inputType="text" />
<ListView android:id="@+id/list" android:layout_width="fill_parent" android:layout_height="fill_parent" />
</LinearLayout>
ListViewSearchActivity
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.app.Activity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleAdapter;
public class ListViewSearchActivity extends Activity implements TextWatcher {
private SimpleAdapter simpleAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
EditText search = (EditText) findViewById(R.id.search);
search.addTextChangedListener(this);
List<Map<String, String>> data = new ArrayList<Map<String, String>>();
for(int i=0;i<8;i++) {
Map<String,String> map = new HashMap<String, String>(2);
map.put("word", "word " + i);
map.put("meaning", "meaning " + (i + 10));
data.add(map);
}
ListView listView = (ListView) findViewById(R.id.list);
this.simpleAdapter = new SimpleAdapter(this, data, android.R.layout.simple_list_item_2, new String[]{"word","meaning"}, new int[]{android.R.id.text1,android.R.id.text2});
listView.setAdapter(this.simpleAdapter);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
this.simpleAdapter.getFilter().filter(s.toString());
}
}
Upvotes: 3
Reputation: 35946
ArrayList<String> tempList ;
edtText.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
if (!edtText.getText().toString().equalsIgnoreCase("")){
tempList = new ArrayList<String>();
tempList.clear();
String text = filterText.getText().toString();
for(int i=0 ;i< listname.size();i++){
//if(globalconstant.mosq_list.get(globalconstant.hashformosq.get(globalconstant.tempList.get(i))).name.toUpperCase().toString().contains(text.toUpperCase())){
if(listname.get(i).toUpperCase().toString().contains(text.toUpperCase())){
tempList.add(listname.get(i));
}
}
used changed tempList
}else{
unchaged tempList
}
}
});
}
Upvotes: 1
Reputation: 19220
Here is how I'd change your code to make it work:
1. I would remove the arr_sort
variable, and add an other ArrayList
of Maps
for holding the filtered values:
// List<String> arr_sort;
final ArrayList<Map<String, String>> data =
new ArrayList<Map<String, String>>();
final ArrayList<Map<String, String>> filteredData =
new ArrayList<Map<String, String>>();
I'd also make them final, since there is no point to assign completely new values to them while we can modify their content.
2. The simpleadapter
should always display the filtered data, so it has to be modified:
filteredData.addAll(data); // fill up filteredData initially with the whole list
simpleadapter = new SimpleAdapter(this, filteredData,
android.R.layout.simple_list_item_2,
new String[] { "word", "meaning" },
new int[] {android.R.id.text1, android.R.id.text2 });
3. Next I'd move the filtering code from the onTextChanged
method to the afterTextChanged
method, to perform the filtering based on the whole text entered. Using Regexp is also less resource consuming than all the String manipulations (+ , substring...)
This way your TextWatcher
implementation would look like:
actv.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)
{
Log.v("MLDA", "afterTextChanged");
// a temporary source list for better performance:
// if it's possible, use the smaller filtered list
final ArrayList<Map<String, String>> tmpSource =
new ArrayList<Map<String,String>>();
tmpSource.addAll(
(filterText.length() > 0 && s.toString().contains(filterText))
? filteredData : data);
filterText = s.toString();
// a temporary result list to fill with the filtered data
final ArrayList<Map<String, String>> tmpResult =
new ArrayList<Map<String,String>>();
if (filterText.length() == 0)
tmpResult.addAll(data); //if no filter, return the base data
else
{
final Pattern pattern =
Pattern.compile("(?i)" + Pattern.quote(s.toString()));
Matcher matcher;
for (final Map<String, String> map : tmpSource)
{
//first match against the "word":
matcher = pattern.matcher(map.get("word"));
if (!matcher.find())
{
//if no matches were found, try to match the "meaning"
matcher = pattern.matcher(map.get("meaning"));
if (!matcher.find())
continue; //if no match, move to the next map
}
tmpResult.add(map); //match found: add to new list
}
}
filteredData.clear();
filteredData.addAll(tmpResult);
simpleadapter.notifyDataSetChanged(); // update display
}
});
Working with temporary lists lets you build up the whole filtered data without gui updates (if removing / adding items to the filteredData
list directly, the adapter would trigger update methods).
Also notice, that by examining whether the new filter text contains the old one, we can use the current filteredData
list as source.
Similarly, if the filterText
is an empty string, there's no point to perform any matches, we can simply return the base
list.
Upvotes: 2