So I have a custom adapter, which I tries to implement a filter search where user key search item from edittext. And the filtering works just fine. However, in my list, I do also implement checkbox.
Let's say I have a list
Bar
Tar
Foo
Kay
Default list would get the position correctly, so no issue here. The issue starts when I search for say a and the list will becomes.
Bar
Tar
Kay
And if I check on Kay after search, it returns me Foo instead.
And the following is my code for my adapter and filter, what is wrong?
public class MyMediaAdapter extends ArrayAdapter<Media> implements Filterable {
private List<Media> list;
private final Activity context;
private Filter mediaFilter;
private List<Media> origMediaList;
public MyMediaAdapter(Activity context, List<Media> list) {
super(context, R.layout.media_view, list);
this.context = context;
this.list = list;
this.origMediaList = list;
}
public int getCount() {
return list.size();
}
public Media getItem(int position) {
return list.get(position);
}
public long getItemId(int position) {
return list.get(position).hashCode();
}
private class ViewHolder {
protected TextView fName, fSub, fDuration, fSize;
protected CheckBox checkbox;
// protected CheckBox checkbox1;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
// Moved here to ensure the checkbox is persistent
ViewHolder viewHolder = new ViewHolder();
if (convertView == null) {
LayoutInflater inflator = context.getLayoutInflater();
view = inflator.inflate(R.layout.media_view, null);
// Moved out of the if-else to solve the problem
// view being recycled each time it scrolls
// final ViewHolder viewHolder = new ViewHolder();
viewHolder.fName = (TextView) view.findViewById(R.id.tvfname);
viewHolder.fSub = (TextView) view.findViewById(R.id.tvsub);
viewHolder.fDuration = (TextView) view.findViewById(R.id.tvduration);
viewHolder.fSize = (TextView) view.findViewById(R.id.tvsize);
viewHolder.checkbox = (CheckBox) view.findViewById(R.id.check);
view.setTag(viewHolder);
// Moved out of the if-else to solve the problem
// view being recycled each time it scrolls
// viewHolder.checkbox.setTag(list.get(position));
} else {
view = convertView;
// Moved out of the if-else to solve the problem
// view being recycled each time it scrolls
// ((ViewHolder) view.getTag()).checkbox.setTag(list.get(position));
viewHolder = (ViewHolder) view.getTag();
}
// Moved here to ensure the checkbox is persistent
viewHolder.checkbox.setId(position);
viewHolder.checkbox.setTag(list.get(position));
ViewHolder holder = (ViewHolder) view.getTag();
holder.fName.setText(list.get(position).getName());
holder.fSub.setText(list.get(position).getPath());
// Converting duration from String to Long
long milli = Long.valueOf(list.get(position).getDuration());
// Put it in % min, % sec format to display
holder.fDuration.setText(util.readableTime(milli));
// Convert data size from String to Long
long datasize = Long.valueOf(list.get(position).getData());
// Put in human readable format
holder.fSize.setText(util.readableFileSize(datasize));
holder.checkbox.setChecked(list.get(position).isSelected());
// viewHolder.checkbox.setId(position);
viewHolder.checkbox.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
CheckBox cb = (CheckBox) v;
int id = cb.getId();
if (selection[id]) {
cb.setChecked(false);
selection[id] = false;
list.get(id).setSelected(false);
} else {
cb.setChecked(true);
selection[id] = true;
list.get(id).setSelected(true);
}
}
});
// Implement SelectAll/DeselectAll feature
final CheckBox checkbox1 = (CheckBox) findViewById(R.id.cb_selectall);
checkbox1.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton button, boolean checked) {
// TODO Auto-generated method stub
if (checked) {
checkbox1.setText("Click to Deselect All");
for (int i = 0; i < list.size(); i++) {
selection[i] = true;
list.get(i).setSelected(true);
}
// Called to notify checkbox changes so the view gets updated immediately
notifyDataSetChanged();
Toast.makeText(getApplicationContext(), "All files are selected", Toast.LENGTH_LONG).show();
} else {
checkbox1.setText("Click to Select All");
for (int i = 0; i < list.size(); i++) {
selection[i] = false;
list.get(i).setSelected(false);
}
notifyDataSetChanged();
Toast.makeText(getApplicationContext(), "All files are deselected", Toast.LENGTH_LONG).show();
}
}
});
return view;
}
public void resetData() {
list = origMediaList;
}
@Override
public Filter getFilter() {
if (mediaFilter == null)
mediaFilter = new mediaFilter();
return mediaFilter;
}
private class mediaFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
// We implement here the filter logic
if (constraint == null || constraint.length() == 0) {
// No filter implemented we return all the list
results.values = origMediaList;
results.count = origMediaList.size();
}
else {
// We perform filtering operation
List<Media> nMediaList = new ArrayList<Media>();
for (Media m : list) {
if (m.getName().toUpperCase().contains(constraint.toString().toUpperCase()))
nMediaList.add(m);
}
results.values = nMediaList;
results.count = nMediaList.size();
}
return results;
}
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
// Now we have to inform the adapter about the new list filtered
if (results.count == 0)
notifyDataSetInvalidated();
else {
list = (List<Media>) results.values;
notifyDataSetChanged();
}
}
}
}
I have the following setup so I know which has been selected.
private boolean[] selection;
private int count;
// After I fetch my list
count = getMediaList.size();
selection = new boolean[count];
// Inside onOptionsItemSelected
@Override
public boolean onOptionsItemSelected(MenuItem item) {
final ArrayList<Integer> posSel = new ArrayList<Integer>();
posSel.clear();
storeSelectedMedia.clear();
/*
* Construct the list of selected items
*/
boolean noSelect = false;
//Log.i("MediaSelection", "" + selection.length);
for (int i = 0; i < selection.length; i++) {
//Log.i("MediaSelect", "" + getMediaList.get(i).isSelected());
if (selection[i] == true) {
//if (getMediaList.get(i).isSelected() == true) {
noSelect = true;
Log.e("Mediasel pos thu-->", "" + i);
posSel.add(i);
storeSelectedMedia.add(getMediaList.get(i).getPath());
}
}
switch (item.getItemId()) {
case R.id.action_sfd:
if (noSelect) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final ScrollView s_view = new ScrollView(getApplicationContext());
final TextView t_view = new TextView(getApplicationContext());
StringBuilder sBuilder = new StringBuilder();
sBuilder.append("\n Name: \t " + getMediaList.get(posSel.get(0)).getName());
sBuilder.append("\n Parent: \t " + getMediaList.get(posSel.get(0)).getParent());
sBuilder.append("\n Type: \t " + getMediaList.get(posSel.get(0)).getType());
sBuilder.append("\n Size: \t\t " + util.readableFileSize(getMediaList.get(posSel.get(0)).getSize()));
sBuilder.append("\n ");
t_view.setText(sBuilder);
t_view.setTextSize(14);
s_view.addView(t_view);
builder.setTitle("File Properties")
.setView(s_view);
AlertDialog dialog = builder.create();
dialog.show();
Toast.makeText(this,
"Selected Items:" + storeSelectedMedia.toString(),
Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this,
"No files selected",
Toast.LENGTH_SHORT).show();
}
break;
Hopefully that would be enough information.
Anyone has any idea on this? Appreciate it greatly!