android filter

一、何谓Android的过滤机制?

 Android对数据的处理是分层的,从上到下,可以分为:数据层、提供层、Cursor层(不好意思,没找到一个词来表示)、适配层、显示层。每个层次通过一定的机制,可以使数据发生变化时能够上下通知。如下图:   
   显示层(ListView,GridView,AutoCompleteTextView等)
   适配层(Adpater)
   Cursor层(Cursor)
   提供层(ContentProvider)
   数据层(文件、sqlite、SharedPreference) 

数据层是数据具体的存储方式,它可以包括文件、sqlite数据库以及SharedPreference。提供层向上层提供了统一的数据调用方式,并负责向其它应用共享数据。Cursor层将查询的数据统一成Cursor的形式来使用。适配层用来连接Cursor层和显示层,将数据和界面连接起来。显示层负责数据的显示。
另外,Andriod提供了数据的过滤机制,也就是在不改变数据存储的情况下,异步或同步的过滤符合条件的数据,并即时的显示在界面上。
Android数据过滤器:Filter
android原生时钟页面CityAdapter实例:

     /***
     * Adapter for a list of cities with the respected time zone. The Adapter
     * sorts the list alphabetically and create an indexer.
     ***/
    private class CityAdapter extends BaseAdapter implements Filterable, SectionIndexer {
        private static final int VIEW_TYPE_CITY = 0;
        private static final int VIEW_TYPE_HEADER = 1;

        private static final String DELETED_ENTRY = "C0";

        private List<CityObj> mDisplayedCitiesList;

        private CityObj[] mCities;
        private CityObj[] mSelectedCities;

        private final int mLayoutDirection;

        // A map that caches names of cities in local memory.  The names in this map are
        // preferred over the names of the selected cities stored in SharedPreferences, which could
        // be in a different language.  This map gets reloaded on a locale change, when the new
        // language's city strings are read from the xml file.
        private HashMap<String, String> mCityNameMap = new HashMap<String, String>();

        private String[] mSectionHeaders;
        private Integer[] mSectionPositions;

        private CityNameComparator mSortByNameComparator = new CityNameComparator();
        private CityGmtOffsetComparator mSortByTimeComparator = new CityGmtOffsetComparator();

        private final LayoutInflater mInflater;
        private boolean mIs24HoursMode; // AM/PM or 24 hours mode

        private final String mPattern12;
        private final String mPattern24;

        private int mSelectedEndPosition = 0;

        private Filter mFilter = new Filter() {

            @Override
            protected synchronized FilterResults performFiltering(CharSequence constraint) {
                FilterResults results = new FilterResults();
                String modifiedQuery = constraint.toString().trim().toUpperCase();

                ArrayList<CityObj> filteredList = new ArrayList<>();
                ArrayList<String> sectionHeaders = new ArrayList<>();
                ArrayList<Integer> sectionPositions = new ArrayList<>();

                // Update the list first when user using search filter
                final Collection<CityObj> selectedCities = mUserSelectedCities.values();
                mSelectedCities = selectedCities.toArray(new CityObj[selectedCities.size()]);
                // If the search query is empty, add in the selected cities
                if (TextUtils.isEmpty(modifiedQuery) && mSelectedCities != null) {
                    if (mSelectedCities.length > 0) {
                        sectionHeaders.add("+");
                        sectionPositions.add(0);
                        filteredList.add(new CityObj(mSelectedCitiesHeaderString,
                                mSelectedCitiesHeaderString, null, null));
                    }
                    for (CityObj city : mSelectedCities) {
                        city.isHeader = false;
                        filteredList.add(city);
                    }
                }

                final HashSet<String> selectedCityIds = new HashSet<>();
                for (CityObj c : mSelectedCities) {
                    selectedCityIds.add(c.mCityId);
                }
                mSelectedEndPosition = filteredList.size();

                long currentTime = System.currentTimeMillis();
                String val = null;
                int offset = -100000; //some value that cannot be a real offset
                for (CityObj city : mCities) {

                    // If the city is a deleted entry, ignore it.
                    if (city.mCityId.equals(DELETED_ENTRY)) {
                        continue;
                    }

                    // If the search query is empty, add section headers.
                    if (TextUtils.isEmpty(modifiedQuery)) {
                        if (!selectedCityIds.contains(city.mCityId)) {
                            // If the list is sorted by name, and the city has an index
                            // different than the previous city's index, update the section header.
                            if (mSortType == SORT_BY_NAME
                                    && !city.mCityIndex.equals(val)) {
                                val = city.mCityIndex.toUpperCase();
                                sectionHeaders.add(val);
                                sectionPositions.add(filteredList.size());
                                city.isHeader = true;
                            } else {
                                city.isHeader = false;
                            }

                            // If the list is sorted by time, and the gmt offset is different than
                            // the previous city's gmt offset, insert a section header.
                            if (mSortType == SORT_BY_GMT_OFFSET) {
                                TimeZone timezone = TimeZone.getTimeZone(city.mTimeZone);
                                int newOffset = timezone.getOffset(currentTime);
                                if (offset != newOffset) {
                                    offset = newOffset;
                                    // Because JB fastscroll only supports ~1 char strings
                                    // and KK ellipsizes strings, trim section headers to the
                                    // nearest hour.
                                    final String offsetString = Utils.getGMTHourOffset(timezone,
                                            Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT
                                            /* useShortForm */ );
                                    sectionHeaders.add(offsetString);
                                    sectionPositions.add(filteredList.size());
                                    city.isHeader = true;
                                } else {
                                    city.isHeader = false;
                                }
                            }

                            filteredList.add(city);
                        }
                    } else {
                        // If the city name begins with the non-empty query, add it into the list.
                        String cityName = city.mCityName.trim().toUpperCase();
                        if (city.mCityId != null && cityName.startsWith(modifiedQuery)) {
                            city.isHeader = false;
                            filteredList.add(city);
                        }
                    }
                }

                mSectionHeaders = sectionHeaders.toArray(new String[sectionHeaders.size()]);
                mSectionPositions = sectionPositions.toArray(new Integer[sectionPositions.size()]);

                results.values = filteredList;
                results.count = filteredList.size();
                return results;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                mDisplayedCitiesList = (ArrayList<CityObj>) results.values;
                if (mPosition >= 0) {
                    mCitiesList.setSelectionFromTop(mPosition, 0);
                    mPosition = -1;
                }
                notifyDataSetChanged();
            }
        };

        public CityAdapter(
                Context context, LayoutInflater factory) {
            super();
            mCalendar = Calendar.getInstance();
            mCalendar.setTimeInMillis(System.currentTimeMillis());
            mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(Locale.getDefault());
            mInflater = factory;

            // Load the cities from xml.
            mCities = Utils.loadCitiesFromXml(context);

            // Reload the city name map with the recently parsed city names of the currently
            // selected language for use with selected cities.
            mCityNameMap.clear();
            for (CityObj city : mCities) {
                mCityNameMap.put(city.mCityId, city.mCityName);
            }

            // Re-organize the selected cities into an array.
            Collection<CityObj> selectedCities = mUserSelectedCities.values();
            mSelectedCities = selectedCities.toArray(new CityObj[selectedCities.size()]);

            // Override the selected city names in the shared preferences with the
            // city names in the updated city name map, which will always reflect the
            // current language.
            for (CityObj city : mSelectedCities) {
                String newCityName = mCityNameMap.get(city.mCityId);
                if (newCityName != null) {
                    city.mCityName = newCityName;
                }
            }

            mPattern24 = Utils.isJBMR2OrLater()
                    ? DateFormat.getBestDateTimePattern(Locale.getDefault(), "Hm")
                    : getString(R.string.time_format_24_mode);

            // There's an RTL layout bug that causes jank when fast-scrolling through
            // the list in 12-hour mode in an RTL locale. We can work around this by
            // ensuring the strings are the same length by using "hh" instead of "h".
            String pattern12 = Utils.isJBMR2OrLater()
                    ? DateFormat.getBestDateTimePattern(Locale.getDefault(), "hma")
                    : getString(R.string.time_format_12_mode);

            if (mLayoutDirection == View.LAYOUT_DIRECTION_RTL) {
                pattern12 = pattern12.replaceAll("h", "hh");
            }
            mPattern12 = pattern12;

            sortCities(mSortType);
            set24HoursMode(context);
        }

        public void toggleSort() {
            if (mSortType == SORT_BY_NAME) {
                sortCities(SORT_BY_GMT_OFFSET);
            } else {
                sortCities(SORT_BY_NAME);
            }
        }

        private void sortCities(final int sortType) {
            mSortType = sortType;
            Arrays.sort(mCities, sortType == SORT_BY_NAME ? mSortByNameComparator
                    : mSortByTimeComparator);
            if (mSelectedCities != null) {
                Arrays.sort(mSelectedCities, sortType == SORT_BY_NAME ? mSortByNameComparator
                        : mSortByTimeComparator);
            }
            mPrefs.edit().putInt(PREF_SORT, sortType).commit();
            mFilter.filter(mQueryTextBuffer.toString());
        }

        @Override
        public int getCount() {
            return mDisplayedCitiesList != null ? mDisplayedCitiesList.size() : 0;
        }

        @Override
        public Object getItem(int p) {
            if (mDisplayedCitiesList != null && p >= 0 && p < mDisplayedCitiesList.size()) {
                return mDisplayedCitiesList.get(p);
            }
            return null;
        }

        @Override
        public long getItemId(int p) {
            return p;
        }

        @Override
        public boolean isEnabled(int p) {
            return mDisplayedCitiesList != null && mDisplayedCitiesList.get(p).mCityId != null;
        }

        @Override
        public synchronized View getView(int position, View view, ViewGroup parent) {
            if (mDisplayedCitiesList == null || position < 0
                    || position >= mDisplayedCitiesList.size()) {
                return null;
            }
            CityObj c = mDisplayedCitiesList.get(position);
            // Header view: A CityObj with nothing but the "selected cities" label
            if (c.mCityId == null) {
                if (view == null) {
                    view = mInflater.inflate(R.layout.city_list_header, parent, false);
                }
            } else { // City view
                // Make sure to recycle a City view only
                if (view == null) {
                    view = mInflater.inflate(R.layout.city_list_item, parent, false);
                    final CityViewHolder holder = new CityViewHolder();
                    holder.index = (TextView) view.findViewById(R.id.index);
                    holder.name = (TextView) view.findViewById(R.id.city_name);
                    holder.time = (TextView) view.findViewById(R.id.city_time);
                    holder.selected = (CheckBox) view.findViewById(R.id.city_onoff);
                    view.setTag(holder);
                }
                view.setOnClickListener(CitiesActivity.this);
                CityViewHolder holder = (CityViewHolder) view.getTag();

                holder.selected.setTag(c);
                holder.selected.setChecked(mUserSelectedCities.containsKey(c.mCityId));
                holder.selected.setOnCheckedChangeListener(CitiesActivity.this);
                holder.name.setText(c.mCityName, TextView.BufferType.SPANNABLE);
                holder.time.setText(getTimeCharSequence(c.mTimeZone));
                if (c.isHeader) {
                    holder.index.setVisibility(View.VISIBLE);
                    if (mSortType == SORT_BY_NAME) {
                        holder.index.setText(c.mCityIndex);
                        holder.index.setTextSize(TypedValue.COMPLEX_UNIT_SP, 24);
                    } else { // SORT_BY_GMT_OFFSET
                        holder.index.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
                        holder.index.setText(Utils.getGMTHourOffset(
                                TimeZone.getTimeZone(c.mTimeZone), false));
                    }
                } else {
                    // If not a header, use the invisible index for left padding
                    holder.index.setVisibility(View.INVISIBLE);
                }
                // skip checkbox and other animations
                view.jumpDrawablesToCurrentState();
            }
            return view;
        }

        private CharSequence getTimeCharSequence(String timeZone) {
            mCalendar.setTimeZone(TimeZone.getTimeZone(timeZone));
            return DateFormat.format(mIs24HoursMode ? mPattern24 : mPattern12, mCalendar);
        }

        @Override
        public int getViewTypeCount() {
            return 2;
        }

        @Override
        public int getItemViewType(int position) {
            return (mDisplayedCitiesList.get(position).mCityId != null)
                    ? VIEW_TYPE_CITY : VIEW_TYPE_HEADER;
        }

        private class CityViewHolder {
            TextView index;
            TextView name;
            TextView time;
            CheckBox selected;
        }

        public void set24HoursMode(Context c) {
            mIs24HoursMode = DateFormat.is24HourFormat(c);
            notifyDataSetChanged();
        }

        @Override
        public int getPositionForSection(int section) {
            return !isEmpty(mSectionPositions) ? mSectionPositions[section] : 0;
        }


        @Override
        public int getSectionForPosition(int p) {
            final Integer[] positions = mSectionPositions;
            if (!isEmpty(positions)) {
                for (int i = 0; i < positions.length - 1; i++) {
                    if (p >= positions[i]
                            && p < positions[i + 1]) {
                        return i;
                    }
                }
                if (p >= positions[positions.length - 1]) {
                    return positions.length - 1;
                }
            }
            return 0;
        }

        @Override
        public Object[] getSections() {
            return mSectionHeaders;
        }

        @Override
        public Filter getFilter() {
            return mFilter;
        }

        private boolean isEmpty(Object[] array) {
            return array == null || array.length == 0;
        }
    }
Android编译过程中,filter(过滤)是一个常用的操作,用于选择要编译的特定模块或文件。通过使用filter,可以减少编译时间和生成的输出大小。 要在Android编译中使用filter,可以按照以下步骤进行操作: 1. 打开终端或命令提示符,并进入Android源码根目录。 2. 使用lunch命令选择要编译的目标设备。例如,使用以下命令选择编译Pixel 3设备: ``` $ lunch aosp_blueline-userdebug ``` 3. 运行make命令来开始编译过程。在make命令中,可以使用以下参数来指定filter: - `MODULES-INCLUDE=<模块1,模块2>`:指定要包含的模块列表。 - `MODULES-EXCLUDE=<模块1,模块2>`:指定要排除的模块列表。 - `TARGET_FILES=<文件1,文件2>`:指定要编译的特定文件列表。 例如,以下命令将只编译名为"Module1"和"Module2"的模块: ``` $ make MODULES-INCLUDE=Module1,Module2 ``` 或者,以下命令将编译除了名为"Module3"之外的所有模块: ``` $ make MODULES-EXCLUDE=Module3 ``` 还可以使用通配符来匹配多个模块或文件。例如,以下命令将编译所有以"Module_"开头的模块: ``` $ make MODULES-INCLUDE=Module_* ``` 注意:filter参数的具体用法可能因不同的Android版本和构建系统而有所差异。请根据你使用的具体情况进行适当的调整。 通过使用filter,你可以选择性地编译Android源码中的模块或文件,以满足你的特定需求。这可以提高编译效率并减少生成的输出大小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值