ArrayAdapter源碼

  1. /* 
  2.  * Copyright (C) 2006 The Android Open Source Project 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */ 
  16.  
  17. package qianlong.qlmobile.ui; 
  18.  
  19. import android.content.Context; 
  20. import android.util.Log; 
  21. import android.view.LayoutInflater; 
  22. import android.view.View; 
  23. import android.view.ViewGroup; 
  24. import android.widget.BaseAdapter; 
  25. import android.widget.Filter; 
  26. import android.widget.Filterable; 
  27. import android.widget.TextView; 
  28.  
  29. import java.util.ArrayList; 
  30. import java.util.Arrays; 
  31. import java.util.Collection; 
  32. import java.util.List; 
  33. import java.util.Comparator; 
  34. import java.util.Collections; 
  35.  
  36. /** 
  37.  * A ListAdapter that manages a ListView backed by an array of arbitrary 
  38.  * objects.  By default this class expects that the provided resource id references 
  39.  * a single TextView.  If you want to use a more complex layout, use the constructors that 
  40.  * also takes a field id.  That field id should reference a TextView in the larger layout 
  41.  * resource. 
  42.  * 
  43.  * However the TextView is referenced, it will be filled with the toString() of each object in 
  44.  * the array. You can add lists or arrays of custom objects. Override the toString() method 
  45.  * of your objects to determine what text will be displayed for the item in the list. 
  46.  * 
  47.  * To use something other than TextViews for the array display, for instance, ImageViews, 
  48.  * or to have some of data besides toString() results fill the views, 
  49.  * override {@link #getView(int, View, ViewGroup)} to return the type of view you want. 
  50.  */ 
  51. public class ArrayAdapter<T> extends BaseAdapter implements Filterable { 
  52.     /** 
  53.      * Contains the list of objects that represent the data of this ArrayAdapter. 
  54.      * The content of this list is referred to as "the array" in the documentation. 
  55.      */ 
  56.     private List<T> mObjects; 
  57.  
  58.     /** 
  59.      * Lock used to modify the content of {@link #mObjects}. Any write operation 
  60.      * performed on the array should be synchronized on this lock. This lock is also 
  61.      * used by the filter (see {@link #getFilter()} to make a synchronized copy of 
  62.      * the original array of data. 
  63.      */ 
  64.     private final Object mLock = new Object(); 
  65.  
  66.     /** 
  67.      * The resource indicating what views to inflate to display the content of this 
  68.      * array adapter. 
  69.      */ 
  70.     private int mResource; 
  71.  
  72.     /** 
  73.      * The resource indicating what views to inflate to display the content of this 
  74.      * array adapter in a drop down widget. 
  75.      */ 
  76.     private int mDropDownResource; 
  77.  
  78.     /** 
  79.      * If the inflated resource is not a TextView, {@link #mFieldId} is used to find 
  80.      * a TextView inside the inflated views hierarchy. This field must contain the 
  81.      * identifier that matches the one defined in the resource file. 
  82.      */ 
  83.     private int mFieldId = 0
  84.  
  85.     /** 
  86.      * Indicates whether or not {@link #notifyDataSetChanged()} must be called whenever 
  87.      * {@link #mObjects} is modified. 
  88.      */ 
  89.     private boolean mNotifyOnChange = true
  90.  
  91.     private Context mContext; 
  92.  
  93.     private ArrayList<T> mOriginalValues; 
  94.     private ArrayFilter mFilter; 
  95.  
  96.     private LayoutInflater mInflater; 
  97.  
  98.     /** 
  99.      * Constructor 
  100.      * 
  101.      * @param context The current context. 
  102.      * @param textViewResourceId The resource ID for a layout file containing a TextView to use when 
  103.      *                 instantiating views. 
  104.      */ 
  105.     public ArrayAdapter(Context context, int textViewResourceId) { 
  106.         init(context, textViewResourceId, 0new ArrayList<T>()); 
  107.     } 
  108.  
  109.     /** 
  110.      * Constructor 
  111.      * 
  112.      * @param context The current context. 
  113.      * @param resource The resource ID for a layout file containing a layout to use when 
  114.      *                 instantiating views. 
  115.      * @param textViewResourceId The id of the TextView within the layout resource to be populated 
  116.      */ 
  117.     public ArrayAdapter(Context context, int resource, int textViewResourceId) { 
  118.         init(context, resource, textViewResourceId, new ArrayList<T>()); 
  119.     } 
  120.  
  121.     /** 
  122.      * Constructor 
  123.      * 
  124.      * @param context The current context. 
  125.      * @param textViewResourceId The resource ID for a layout file containing a TextView to use when 
  126.      *                 instantiating views. 
  127.      * @param objects The objects to represent in the ListView. 
  128.      */ 
  129.     public ArrayAdapter(Context context, int textViewResourceId, T[] objects) { 
  130.         init(context, textViewResourceId, 0, Arrays.asList(objects)); 
  131.     } 
  132.  
  133.     /** 
  134.      * Constructor 
  135.      * 
  136.      * @param context The current context. 
  137.      * @param resource The resource ID for a layout file containing a layout to use when 
  138.      *                 instantiating views. 
  139.      * @param textViewResourceId The id of the TextView within the layout resource to be populated 
  140.      * @param objects The objects to represent in the ListView. 
  141.      */ 
  142.     public ArrayAdapter(Context context, int resource, int textViewResourceId, T[] objects) { 
  143.         init(context, resource, textViewResourceId, Arrays.asList(objects)); 
  144.     } 
  145.  
  146.     /** 
  147.      * Constructor 
  148.      * 
  149.      * @param context The current context. 
  150.      * @param textViewResourceId The resource ID for a layout file containing a TextView to use when 
  151.      *                 instantiating views. 
  152.      * @param objects The objects to represent in the ListView. 
  153.      */ 
  154.     public ArrayAdapter(Context context, int textViewResourceId, List<T> objects) { 
  155.         init(context, textViewResourceId, 0, objects); 
  156.     } 
  157.  
  158.     /** 
  159.      * Constructor 
  160.      * 
  161.      * @param context The current context. 
  162.      * @param resource The resource ID for a layout file containing a layout to use when 
  163.      *                 instantiating views. 
  164.      * @param textViewResourceId The id of the TextView within the layout resource to be populated 
  165.      * @param objects The objects to represent in the ListView. 
  166.      */ 
  167.     public ArrayAdapter(Context context, int resource, int textViewResourceId, List<T> objects) { 
  168.         init(context, resource, textViewResourceId, objects); 
  169.     } 
  170.  
  171.     /** 
  172.      * Adds the specified object at the end of the array. 
  173.      * 
  174.      * @param object The object to add at the end of the array. 
  175.      */ 
  176.     public void add(T object) { 
  177.         if (mOriginalValues != null) { 
  178.             synchronized (mLock) { 
  179.                 mOriginalValues.add(object); 
  180.                 if (mNotifyOnChange) notifyDataSetChanged(); 
  181.             } 
  182.         } else { 
  183.             mObjects.add(object); 
  184.             if (mNotifyOnChange) notifyDataSetChanged(); 
  185.         } 
  186.     } 
  187.  
  188.     /** 
  189.      * Adds the specified Collection at the end of the array. 
  190.      * 
  191.      * @param collection The Collection to add at the end of the array. 
  192.      */ 
  193.     public void addAll(Collection<? extends T> collection) { 
  194.         if (mOriginalValues != null) { 
  195.             synchronized (mLock) { 
  196.                 mOriginalValues.addAll(collection); 
  197.                 if (mNotifyOnChange) notifyDataSetChanged(); 
  198.             } 
  199.         } else { 
  200.             mObjects.addAll(collection); 
  201.             if (mNotifyOnChange) notifyDataSetChanged(); 
  202.         } 
  203.     } 
  204.  
  205.     /** 
  206.      * Adds the specified items at the end of the array. 
  207.      * 
  208.      * @param items The items to add at the end of the array. 
  209.      */ 
  210.     public void addAll(T ... items) { 
  211.         if (mOriginalValues != null) { 
  212.             synchronized (mLock) { 
  213.                 for (T item : items) { 
  214.                     mOriginalValues.add(item); 
  215.                 } 
  216.                 if (mNotifyOnChange) notifyDataSetChanged(); 
  217.             } 
  218.         } else { 
  219.             for (T item : items) { 
  220.                 mObjects.add(item); 
  221.             } 
  222.             if (mNotifyOnChange) notifyDataSetChanged(); 
  223.         } 
  224.     } 
  225.  
  226.     /** 
  227.      * Inserts the specified object at the specified index in the array. 
  228.      * 
  229.      * @param object The object to insert into the array. 
  230.      * @param index The index at which the object must be inserted. 
  231.      */ 
  232.     public void insert(T object, int index) { 
  233.         if (mOriginalValues != null) { 
  234.             synchronized (mLock) { 
  235.                 mOriginalValues.add(index, object); 
  236.                 if (mNotifyOnChange) notifyDataSetChanged(); 
  237.             } 
  238.         } else { 
  239.             mObjects.add(index, object); 
  240.             if (mNotifyOnChange) notifyDataSetChanged(); 
  241.         } 
  242.     } 
  243.  
  244.     /** 
  245.      * Removes the specified object from the array. 
  246.      * 
  247.      * @param object The object to remove. 
  248.      */ 
  249.     public void remove(T object) { 
  250.         if (mOriginalValues != null) { 
  251.             synchronized (mLock) { 
  252.                 mOriginalValues.remove(object); 
  253.             } 
  254.         } else { 
  255.             mObjects.remove(object); 
  256.         } 
  257.         if (mNotifyOnChange) notifyDataSetChanged(); 
  258.     } 
  259.  
  260.     /** 
  261.      * Remove all elements from the list. 
  262.      */ 
  263.     public void clear() { 
  264.         if (mOriginalValues != null) { 
  265.             synchronized (mLock) { 
  266.                 mOriginalValues.clear(); 
  267.             } 
  268.         } else { 
  269.             mObjects.clear(); 
  270.         } 
  271.         if (mNotifyOnChange) notifyDataSetChanged(); 
  272.     } 
  273.  
  274.     /** 
  275.      * Sorts the content of this adapter using the specified comparator. 
  276.      * 
  277.      * @param comparator The comparator used to sort the objects contained 
  278.      *        in this adapter. 
  279.      */ 
  280.     public void sort(Comparator<? super T> comparator) { 
  281.         Collections.sort(mObjects, comparator); 
  282.         if (mNotifyOnChange) notifyDataSetChanged(); 
  283.     } 
  284.  
  285.     /** 
  286.      * {@inheritDoc} 
  287.      */ 
  288.     @Override 
  289.     public void notifyDataSetChanged() { 
  290.         super.notifyDataSetChanged(); 
  291.         mNotifyOnChange = true
  292.     } 
  293.  
  294.     /** 
  295.      * Control whether methods that change the list ({@link #add}, 
  296.      * {@link #insert}, {@link #remove}, {@link #clear}) automatically call 
  297.      * {@link #notifyDataSetChanged}.  If set to false, caller must 
  298.      * manually call notifyDataSetChanged() to have the changes 
  299.      * reflected in the attached view. 
  300.      * 
  301.      * The default is true, and calling notifyDataSetChanged() 
  302.      * resets the flag to true. 
  303.      * 
  304.      * @param notifyOnChange if true, modifications to the list will 
  305.      *                       automatically call {@link 
  306.      *                       #notifyDataSetChanged} 
  307.      */ 
  308.     public void setNotifyOnChange(boolean notifyOnChange) { 
  309.         mNotifyOnChange = notifyOnChange; 
  310.     } 
  311.  
  312.     private void init(Context context, int resource, int textViewResourceId, List<T> objects) { 
  313.         mContext = context; 
  314.         mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
  315.         mResource = mDropDownResource = resource; 
  316.         mObjects = objects; 
  317.         mFieldId = textViewResourceId; 
  318.     } 
  319.  
  320.     /** 
  321.      * Returns the context associated with this array adapter. The context is used 
  322.      * to create views from the resource passed to the constructor. 
  323.      * 
  324.      * @return The Context associated with this adapter. 
  325.      */ 
  326.     public Context getContext() { 
  327.         return mContext; 
  328.     } 
  329.  
  330.     /** 
  331.      * {@inheritDoc} 
  332.      */ 
  333.     public int getCount() { 
  334.         return mObjects.size(); 
  335.     } 
  336.  
  337.     /** 
  338.      * {@inheritDoc} 
  339.      */ 
  340.     public T getItem(int position) { 
  341.         return mObjects.get(position); 
  342.     } 
  343.  
  344.     /** 
  345.      * Returns the position of the specified item in the array. 
  346.      * 
  347.      * @param item The item to retrieve the position of. 
  348.      * 
  349.      * @return The position of the specified item. 
  350.      */ 
  351.     public int getPosition(T item) { 
  352.         return mObjects.indexOf(item); 
  353.     } 
  354.  
  355.     /** 
  356.      * {@inheritDoc} 
  357.      */ 
  358.     public long getItemId(int position) { 
  359.         return position; 
  360.     } 
  361.  
  362.     /** 
  363.      * {@inheritDoc} 
  364.      */ 
  365.     public View getView(int position, View convertView, ViewGroup parent) { 
  366.         return createViewFromResource(position, convertView, parent, mResource); 
  367.     } 
  368.  
  369.     private View createViewFromResource(int position, View convertView, ViewGroup parent, 
  370.             int resource) { 
  371.         View view; 
  372.         TextView text; 
  373.  
  374.         if (convertView == null) { 
  375.             view = mInflater.inflate(resource, parent, false); 
  376.         } else { 
  377.             view = convertView; 
  378.         } 
  379.  
  380.         try { 
  381.             if (mFieldId == 0) { 
  382.                 //  If no custom field is assigned, assume the whole resource is a TextView 
  383.                 text = (TextView) view; 
  384.             } else { 
  385.                 //  Otherwise, find the TextView field within the layout 
  386.                 text = (TextView) view.findViewById(mFieldId); 
  387.             } 
  388.         } catch (ClassCastException e) { 
  389.             Log.e("ArrayAdapter""You must supply a resource ID for a TextView"); 
  390.             throw new IllegalStateException( 
  391.                     "ArrayAdapter requires the resource ID to be a TextView", e); 
  392.         } 
  393.  
  394.         T item = getItem(position); 
  395.         if (item instanceof CharSequence) { 
  396.             text.setText((CharSequence)item); 
  397.         } else { 
  398.             text.setText(item.toString()); 
  399.         } 
  400.  
  401.         return view; 
  402.     } 
  403.  
  404.     /** 
  405.      * <p>Sets the layout resource to create the drop down views.</p> 
  406.      * 
  407.      * @param resource the layout resource defining the drop down views 
  408.      * @see #getDropDownView(int, android.view.View, android.view.ViewGroup) 
  409.      */ 
  410.     public void setDropDownViewResource(int resource) { 
  411.         this.mDropDownResource = resource; 
  412.     } 
  413.  
  414.     /** 
  415.      * {@inheritDoc} 
  416.      */ 
  417.     @Override 
  418.     public View getDropDownView(int position, View convertView, ViewGroup parent) { 
  419.         return createViewFromResource(position, convertView, parent, mDropDownResource); 
  420.     } 
  421.  
  422.     /** 
  423.      * Creates a new ArrayAdapter from external resources. The content of the array is 
  424.      * obtained through {@link android.content.res.Resources#getTextArray(int)}. 
  425.      * 
  426.      * @param context The application's environment. 
  427.      * @param textArrayResId The identifier of the array to use as the data source. 
  428.      * @param textViewResId The identifier of the layout used to create views. 
  429.      * 
  430.      * @return An ArrayAdapter<CharSequence>. 
  431.      */ 
  432.     public static ArrayAdapter<CharSequence> createFromResource(Context context, 
  433.             int textArrayResId, int textViewResId) { 
  434.         CharSequence[] strings = context.getResources().getTextArray(textArrayResId); 
  435.         return new ArrayAdapter<CharSequence>(context, textViewResId, strings); 
  436.     } 
  437.  
  438.     /** 
  439.      * {@inheritDoc} 
  440.      */ 
  441.     public Filter getFilter() { 
  442.         if (mFilter == null) { 
  443.             mFilter = new ArrayFilter(); 
  444.         } 
  445.         return mFilter; 
  446.     } 
  447.  
  448.     /** 
  449.      * <p>An array filter constrains the content of the array adapter with 
  450.      * a prefix. Each item that does not start with the supplied prefix 
  451.      * is removed from the list.</p> 
  452.      */ 
  453.     private class ArrayFilter extends Filter { 
  454.         @Override 
  455.         protected FilterResults performFiltering(CharSequence prefix) { 
  456.             FilterResults results = new FilterResults(); 
  457.  
  458.             if (mOriginalValues == null) { 
  459.                 synchronized (mLock) { 
  460.                     mOriginalValues = new ArrayList<T>(mObjects); 
  461.                 } 
  462.             } 
  463.  
  464.             if (prefix == null || prefix.length() == 0) { 
  465.                 synchronized (mLock) { 
  466.                     ArrayList<T> list = new ArrayList<T>(mOriginalValues); 
  467.                     results.values = list; 
  468.                     results.count = list.size(); 
  469.                 } 
  470.             } else { 
  471.                 String prefixString = prefix.toString().toLowerCase(); 
  472.  
  473.                 final ArrayList<T> values = mOriginalValues; 
  474.                 final int count = values.size(); 
  475.  
  476.                 final ArrayList<T> newValues = new ArrayList<T>(count); 
  477.  
  478.                 for (int i = 0; i < count; i++) { 
  479.                     final T value = values.get(i); 
  480.                     final String valueText = value.toString().toLowerCase(); 
  481.  
  482.                     // First match against the whole, non-splitted value 
  483.                     if (valueText.startsWith(prefixString)) { 
  484.                         newValues.add(value); 
  485.                     } else { 
  486.                         final String[] words = valueText.split(" "); 
  487.                         final int wordCount = words.length; 
  488.  
  489.                         for (int k = 0; k < wordCount; k++) { 
  490.                             if (words[k].startsWith(prefixString)) {//源碼 ,匹配開頭 
  491.                                 newValues.add(value); 
  492.                                 break
  493.                             } 
  494.                         } 
  495.                     } 
  496.                 } 
  497.  
  498.                 results.values = newValues; 
  499.                 results.count = newValues.size(); 
  500.             } 
  501.  
  502.             return results; 
  503.         } 
  504.  
  505.         @Override 
  506.         protected void publishResults(CharSequence constraint, FilterResults results) { 
  507.             //noinspection unchecked 
  508.             mObjects = (List<T>) results.values; 
  509.             if (results.count > 0) { 
  510.                 notifyDataSetChanged(); 
  511.             } else { 
  512.                 notifyDataSetInvalidated(); 
  513.             } 
  514.         } 
  515.     } 
  516.   

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章