Как реализовать getFilter на BaseAdapter?

Я пытаюсь реализовать getFilter() на базовом адаптере, чтобы отфильтровать результаты поиска в списке. Есть ли пример реализации getFilter()?

MainActivity.java

   final AppInfoAdapter adapter = new AppInfoAdapter(this, Utilities.getSystemFilteredApplication(this), getPackageManager());


        public void onTextChanged(CharSequence s, int start, int before,
                int count) {
           adapter.getFilter().filter(s); //Filter from my adapter
           adapter.notifyDataSetChanged(); //Update my view
        }

AppInfoAdapter.java

package com.example.permission;

import java.util.List;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.TextView;

public class AppInfoAdapter extends BaseAdapter implements Filterable{
    private Context mContext;
    private List mListAppInfo;
    PackageManager mPackManager;

    public AppInfoAdapter(Context c, List list, PackageManager pm) {
        mContext = c;
        mListAppInfo = list;
        mPackManager = pm;
    }

    public int getCount() {
        return mListAppInfo.size();
    }


    public Object getItem(int position) {
        return mListAppInfo.get(position);
    }


    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        // get the selected entry
        ApplicationInfo entry = (ApplicationInfo) mListAppInfo.get(position);

        // reference to convertView
        View v = convertView;

        // inflate new layout if null
        if(v == null) {
            LayoutInflater inflater = LayoutInflater.from(mContext);
            v = inflater.inflate(R.layout.layout_appinfo, null);
        }

        // load controls from layout resources
        ImageView ivAppIcon = (ImageView)v.findViewById(R.id.ivIcon);
        TextView tvAppName = (TextView)v.findViewById(R.id.tvName);
        TextView tvPkgName = (TextView)v.findViewById(R.id.tvPack);

        // set data to display
        ivAppIcon.setImageDrawable(entry.loadIcon(mPackManager));
        tvAppName.setText(entry.loadLabel(mPackManager));
        tvPkgName.setText(entry.packageName);

        // return view
        return v;
    }

    public Filter getFilter() {
        // TODO Auto-generated method stub
        return null;
    }


}

РЕДАКТИРОВАТЬ: отредактировал код и добавил полный AppInfoAdapter.java


person dythe    schedule 23.07.2012    source источник


Ответы (7)


поместите этот класс в свой адаптер, чтобы использовать его в методе getfilter

//this is a simple class that filtering the ArrayList of strings used in adapter

public class filter_here extends Filter{

        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            // TODO Auto-generated method stub

            FilterResults Result = new FilterResults();
            // if constraint is empty return the original names
            if(constraint.length() == 0 ){
                Result.values = Original_Names;
                Result.count = Original_Names.size();
                return Result;
            }

            ArrayList<String> Filtered_Names = new ArrayList<String>();
            String filterString = constraint.toString().toLowerCase();
            String filterableString;

            for(int i = 0; i<Original_Names.size(); i++){
                filterableString = Original_Names.get(i);
                if(filterableString.toLowerCase().contains(filterString)){
                    Filtered_Names.add(filterableString);
                }
            }
            Result.values = Filtered_Names;
            Result.count = Filtered_Names.size();

            return Result;
        }

        @Override
        protected void publishResults(CharSequence constraint,FilterResults results) {
            // TODO Auto-generated method stub
            Names = (ArrayList<String>) results.values;
            notifyDataSetChanged();
        }

    }

возврат экземпляра из него в getfilter

@Override
    public Filter getFilter() {
        // TODO Auto-generated method stub
        return filter;
    }

полный пример

person Omar Abdan    schedule 16.01.2013

это меня чуть не убило :)

  1. реализовать свой BaseAdapter следующим образом:
  2. определите ArrayList of List в вашем общедоступном классе адаптера, который будет содержать временные элементы вашего исходного списка.

    public class MyAdapter extends BaseAdapter implements Filterable{
    
        public static ArrayList<String> temporarylist;
        public static ArrayList<String> OriginalList;
        private Activity activity;
    
        public MyAdapter(Activity activity, ArrayList<String> OriginalList) {
             super();
             this.activity=activity;
             this.OriginalList = OriginalList;
             temporarylist=OriginalList;
    
        }
        .
        .
        .
    
  3. создайте метод getFilter() со следующим кодом [в качестве примера]:

    public Filter getFilter() {
        Filter filter = new Filter() {
    
        @SuppressWarnings("unchecked")
        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            temporarylist=(ArrayList<String>)results.values;
            notifyDataSetChanged();
        }
    
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            FilterResults results = new FilterResults();
            ArrayList<String> FilteredList= new ArrayList<String>();
            if (constraint == null || constraint.length() == 0) {
                // No filter implemented we return all the list
                results.values = OriginalList;
                results.count = OriginalList.size();
            }
            else {
                for (int i = 0; i < OriginalList.size(); i++) {
                    String data = OriginalList.get(i);
                    if (data.toLowerCase().contains(constraint.toString()))  {
                        FilteredList.add(data);
                    }
                }
                results.values = FilteredList;
                results.count = FilteredList.size();
            }
            return results;
        }
    };
    return filter;
    }
    

И, наконец, в вашей деятельности для вашего EditText:

MyAdapter adapter;
ArrayList<String> items;


ListView list = (ListView) findViewById(R.id.list);
items = new ArrayList<String>();
for (int i=0;i<30;i++){
     items.add("Hello world "+String.valueof(i));
}
adapter = new GameAdapter(this, items);
list.setAdapter(adapter);


EditText inputSearch = (EditText) findViewById(R.id.Search_txt);
     inputSearch.addTextChangedListener(new TextWatcher() {

            @Override
            public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
                // When user changed the Text
                MyActivity.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                          
            }
        });
person rezam    schedule 31.07.2013

Можете ли вы опубликовать свой полный AppInfoAdapter? Также есть ли какая-либо причина, выходящая из BaseAdapter, а не ArrayAdapter? Если у вас есть ArrayList объектов, используйте ArrayAdapter, он уже реализует интерфейс Filterable.

На самом деле вы используете List, ваш адаптер можно переписать для расширения ArrayAdapter, который уже является Filterable.

public class AppInfoAdapter extends ArrayAdapter<ApplicationInfo> {

    private Context mContext;
    PackageManager mPackManager;

    public AppInfoAdapter(Context c, List<ApplicationInfo> list, PackageManager pm) {
        super(c, 0, new ArrayList<ApplicationInfo>());
        mContext = c;
        mPackManager = pm;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // get the selected entry
        ApplicationInfo entry = (ApplicationInfo) getItem(position);

        // reference to convertView
        View v = convertView;

        // inflate new layout if null
        if(v == null) {
            LayoutInflater inflater = LayoutInflater.from(mContext);
            v = inflater.inflate(R.layout.layout_appinfo, null);
        }

        // load controls from layout resources
        ImageView ivAppIcon = (ImageView)v.findViewById(R.id.ivIcon);
        TextView tvAppName = (TextView)v.findViewById(R.id.tvName);
        TextView tvPkgName = (TextView)v.findViewById(R.id.tvPack);

        // set data to display
        ivAppIcon.setImageDrawable(entry.loadIcon(mPackManager));
        tvAppName.setText(entry.loadLabel(mPackManager));
        tvPkgName.setText(entry.packageName);

        // return view
        return v;
    }
}
person biegleux    schedule 23.07.2012
comment
Я отредактировал ответ, чтобы ваш адаптер extends Filterable ArrayAdapter. - person biegleux; 24.07.2012
comment
В вашем коде нет ошибок, но теперь я не вижу свой список установленных приложений уже только EditText - person dythe; 24.07.2012
comment
Замените super(c, 0, new ArrayList<ApplicationInfo>()); на super(c, 0, list); Моя вина. - person biegleux; 24.07.2012
comment
Поиск работает частично, не очень понимаю как работает сейчас немного глючит пока работает только по ключевому слову "андроид" - person dythe; 24.07.2012
comment
См. ArrayAdapter источник, чтобы узнать, как работает ArrayFilter github. com/android/platform_frameworks_base/blob/master/core/ или это также может помочь stackoverflow.com/a/4027085/1300995 - person biegleux; 24.07.2012
comment
Да, видел эти примеры пару раз, но не могу понять, что не так с моим кодом atm, моим текущим mainactivity.java - pastebin .com/BJWiWgcd - person dythe; 24.07.2012
comment
Скорее всего, это потому, что ArrayFilter использует toString() для фильтрации, а ApplicationInfo.toString() может дать вам не то, что вы хотите. - person biegleux; 24.07.2012
comment
Добавлено несколько отладочных сообщений, ontextchanged работает нормально, но я действительно не знаю, как проверить, дает ли мне ApplicationInfo.toString() правильную информацию. Я только что сделал запись ApplicationInfo = (ApplicationInfo) getItem(position); Log.e(TAG, entry.toString()); и куча отладочных сообщений появилась, когда я набрал несколько символов. Любые предложения по устранению этой проблемы? - person dythe; 24.07.2012

Вам нужно вернуть экземпляр Filter. Чтобы написать фильтр, создайте подкласс Filter и реализуйте performFiltering и publishResults. См. документацию.

person ᆼᆺᆼ    schedule 23.07.2012

Общая процедура

  1. Включить фильтрацию текста в вашем ListView
  2. Измените базовый адаптер для хранения двух копий списка, одной исходной и одной отфильтрованной.
  3. Измените все ссылки доступа в BaseAdapter, чтобы они ссылались на отфильтрованный список, а не на исходный.
  4. Реализуйте свою функцию фильтра в BaseAdapter.

Шаг 1:
listview.setTextFilterEnabled(true);

Шаг 2:

public class AppInfoAdapter extends BaseAdapter implements Filterable{
    private List mListAppInfo;
    private List mListAppInfoFiltered;

public AppInfoAdapter(Context c, List list, PackageManager pm) {
    mContext = c;
    mListAppInfo = list;
    mPackManager = pm;
    mPackManagerFiltered = pm; //added line
}

Шаг 3:

public int getCount() {
    return mListAppInfoFiltered.size();
}
public Object getItem(int position) {
    return mListAppInfoFiltered.get(position);
}
public View getView(int position, View convertView, ViewGroup parent) {
    // get the selected entry
    ApplicationInfo entry = (ApplicationInfo) mListAppInfoFiltered.get(position);

}

Шаг 4: Я не уверен, какого типа ваш список, поэтому предположим, что это список String:

@Override
public Filter getFilter() {
    return new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            FilterResults results = new FilterResults();
            if (constraint == null || constraint.length() == 0) {
                //no search, so just return all the data
                results.count = mListAppInfo.size();
                results.values = mListAppInfo;
            } else {//do the search
                List<String> resultsData = new ArrayList<>();
                String searchStr = constraint.toString().toUpperCase();
                for (String s : mListAppInfo)
                        if (s.toUpperCase().contains(searchStr)) resultsData.add(s);
                    results.count = resultsData.size();
                    results.values = resultsData;
                }
                return results;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                mListAppInfoFiltered = (ArrayList<MyObject>) results.values;
                notifyDataSetChanged();
            }
        };
    }
}
person Mtl Dev    schedule 16.03.2016

getFilter() можно переопределить в адаптерах и вернуть объект фильтра, который содержит отфильтрованный список. В классе Filter() есть два ключевых метода; выполнить фильтрацию и опубликовать результаты. Первый метод выполняет фильтрацию в рабочем потоке, а второй возвращает отфильтрованный список объектов.

Вы можете обратиться к примеру кода ниже

@Override
public Filter getFilter() {

        return new Filter() {

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                // TODO Auto-generated method stub
                if (results.count == 0) {
                    notifyDataSetInvalidated();
                }else{
                    mListAppInfo = (ArrayList<SampleItem>) results.values;
                    notifyDataSetChanged();
                }
            }

            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                // TODO Auto-generated method stub
                FilterResults results = new FilterResults();

                if (constraint == null || constraint.length() == 0) {
                    results.values = mListAppInfo;
                    results.count = mListAppInfo.size();
                }else{
                    ArrayList<SampleItem> filter_items = new ArrayList<>(); 
                    for (SampleItem item : mListAppInfo) {
                        if (item.getItemName().toLowerCase().startsWith(constraint.toString().toLowerCase())) {
                            filter_items.add(item);
                        }
                    }
                    results.values =  filter_items ;
                    results.count = filter_items.size();
                }
                return results;
            }
        };
    }

Надеюсь, вы найдете ее полезной .

person Sanny Singhs    schedule 07.09.2014

расширьте свой класс с помощью ArrayAdapter, затем переопределите методы и создайте объект класса фильтра и вернитесь с ним.

person Community    schedule 26.09.2014