0

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!

4

1 回答 1

1

I have solved my own problem. As I was using getMediaList to get the item to display, I forgotten that I have no update my getMediaList to the "after-filtered" list.

Thus, on the publishResult method, before notifyDataSetChanged();, I basically just assign the getMediaList = list.

@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;
                    // HERE
                    getMediaList = list;
                    notifyDataSetChanged();
                }
            }

Checked through it for quite a long time before I realize this stupid mistake. Hope it helps someone in the future.

于 2013-04-29T17:29:48.673 回答