gilione
gilione

Reputation: 59

ListView custom filter gives wrong item selected when filtered

I am new to Android programming and I have a ListView when filtered always return me the first item in the list, so how do I fix this?

For instance, my list contains A.A, A.B, A.C, B.C, B.D. When I want to search the list for things starting with B, I will get B.C, B.D but when I click B.C, it returns me A.A and B.D, it returns me A.B

I am weeks I'm looking for a solution! please help me !!

public class MainActivity extends Activity implements
    SearchView.OnQueryTextListener, AdapterView.OnItemClickListener {

ListView lv;
SearchView search_view;

String[] country_names , iso_codes ;
TypedArray country_flags ;

ArrayList<Country> countrylist ;
CustomAdapter adapter;

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

    lv = (ListView) findViewById(R.id.list_view);
    search_view = (SearchView) findViewById(R.id.search_view);

    country_names = getResources().getStringArray(R.array.country_names);
    iso_codes = getResources().getStringArray(R.array.iso_Code);
    country_flags = getResources().obtainTypedArray(R.array.country_flags);

    countrylist = new ArrayList<Country>();
    for (int i = 0; i < country_names.length; i++) {
        Country country = new Country(country_names[i] , iso_codes[i] ,
                country_flags.getResourceId(i, -1) );
        countrylist.add(country);
    }

    adapter = new CustomAdapter(getApplicationContext(), countrylist );
    lv.setAdapter(adapter);

    search_view.setOnQueryTextListener(this);
    lv.setOnItemClickListener(this);










}

@Override
public boolean onQueryTextChange(String newText) {
    adapter.getFilter().filter(newText);
    return false;
}

@Override
public boolean onQueryTextSubmit(String query) {
    return false;
}

public void onItemClick(AdapterView<?> l, View v, int position, long id) {
    Log.i("HelloListView", "You clicked Item: " + id + " at position:" + position);
    // Then you start a new Activity via Intent
    Intent intent = new Intent();
    intent.setClass(this, ListItemDetail.class);
    intent.putExtra("position", position);
    // Or / And
    intent.putExtra("id", id);
    startActivity(intent);
}

list item detail

public class ListItemDetail extends Activity {

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

    Intent intent = getIntent();
    int position = intent.getIntExtra("position", 0);

    // Here we turn your string.xml in an array
    String[] myKeys = getResources().getStringArray(R.array.sections);
    String[] myKeys2 = getResources().getStringArray(R.array.testo2);

    String[] myKeys3 = getResources().getStringArray(R.array.testo3);

    String[] myKeys4 = getResources().getStringArray(R.array.testo4);



    TextView myTextView = (TextView) findViewById(R.id.my_textview);
    myTextView.setText(myKeys[position]);

    TextView myTextView2 = (TextView) findViewById(R.id.testo2);
    myTextView2.setText(myKeys2[position]);

    TextView myTextView3 = (TextView) findViewById(R.id.testo3);
    myTextView3.setText(myKeys3[position]);

    TextView myTextView4 = (TextView) findViewById(R.id.testo4);
    myTextView4.setText(myKeys4[position]);

customlistAdapter

public class CustomAdapter extends BaseAdapter implements Filterable {

Context context;
ArrayList<Country> countrylist;
ArrayList<Country> mStringFilterList;
ValueFilter valueFilter;



CustomAdapter(Context context , ArrayList<Country> countrylist) {
    this.context = context;
    this.countrylist = countrylist;
    mStringFilterList = countrylist;
}

@Override
public int getCount() {
    return countrylist.size();
}

@Override
public Object getItem(int position) {
    return countrylist.get(position);
}

@Override
public long getItemId(int position) {
    return countrylist.indexOf(getItem(position));
}

@Override
public View getView(int position , View convertView , ViewGroup parent ) {

    LayoutInflater mInflater = (LayoutInflater) context
            .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);

    convertView = null;
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.list_item, null);

        TextView name_tv = (TextView) convertView.findViewById(R.id.name);
        TextView iso_tv = (TextView) convertView.findViewById(R.id.code);
        ImageView iv = (ImageView) convertView.findViewById(R.id.flag);

        Country country = countrylist.get(position);

        name_tv.setText(country.getName());
        iso_tv.setText(country.getIso_code());



        Picasso
                .with(context)
                .load(url[position])
                .fit() // will explain later
                .centerCrop()
                .into(iv);
    }
    return convertView;
}

@Override
public Filter getFilter() {
    if (valueFilter == null) {
        valueFilter = new ValueFilter();
    }
    return valueFilter;
}

private class ValueFilter extends Filter {
    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        FilterResults results = new FilterResults();

        if (constraint != null && constraint.length() > 0) {
            ArrayList<Country> filterList = new ArrayList<Country>();
            for (int i = 0; i < mStringFilterList.size(); i++) {
                if ( (mStringFilterList.get(i).getName().toUpperCase() )
                        .contains(constraint.toString().toUpperCase())) {

                    Country country = new Country(mStringFilterList.get(i)
                            .getName() ,  mStringFilterList.get(i)
                            .getIso_code() ,  mStringFilterList.get(i)
                            .getFlag());

                    filterList.add(country);
                }
            }
            results.count = filterList.size();
            results.values = filterList;
        } else {
            results.count = mStringFilterList.size();
            results.values = mStringFilterList;
        }
        return results;

    }

    @Override
    protected void publishResults(CharSequence constraint,
                                  FilterResults results) {
        countrylist = (ArrayList<Country>) results.values;
        notifyDataSetChanged();
    }

}

contry

public class Country {

String name;
String iso_code;
int flag;

Country(String name, String iso_code, int flag) {
    this.name = name;
    this.iso_code = iso_code;
    this.flag = flag;
}

public String getIso_code() {
    return iso_code;
}

public void setIso_code(String iso_code) {
    this.iso_code = iso_code;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public int getFlag() {

    return flag;
}

public void setFlag(int flag) {

    this.flag = flag;
}

Upvotes: 2

Views: 1248

Answers (1)

kris larson
kris larson

Reputation: 30985

I notice you're using the position as input to the ListItemDetail activity. This will cause you problems as the position for a given item will change as the list is filtered.

You should just put the item values into the Intent then use those values and not look anything up in ListItemDetail

public void onItemClick(AdapterView<?> l, View v, int position, long id) {

    Country country = (Country) ((CustomAdapter ) l.getAdapter()).getItem(position);

    Intent intent = new Intent(this, ListItemDetail.class);
    intent.putExtra("name", country.getName());
    intent.putExtra("iso_code", country.getIso_code());
    intent.putExtra("flag", country.getFlag());
    startActivity(intent);
}

Now change your ListDetailActivity to use these values:

public class ListItemDetail extends Activity {

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

        Intent intent = getIntent();
        String name = intent.getStringExtra("name");
        String iso_code = intent.getStringExtra("iso_code");
        int flagResId = intent.getIntExtra("flag");

        // make a TextView in activity_list_item_detail.xml called "name"
        TextView nameTextView = (TextView) findViewById(R.id.name);
        nameTextView .setText(name);

        // make a TextView in activity_list_item_detail.xml called "iso_code"
        TextView isoCodeTextView = (TextView) findViewById(R.id.iso_code);
        isoCodeTextView .setText(iso_code);

        // make an ImageView in activity_list_item_detail.xml called "flag" 
        ImageView flagImageView = (ImageView) findViewById(R.id.flag);
        flagImageView.setImageResource(flagResId);
    }
}

Note this activity won't work until you update your activity_list_item_detail.xml as suggested in the comments

Upvotes: 3

Related Questions