Android SimpleAdapter源码解析

SimpleAdapter:

public class SimpleAdapter extends BaseAdapter implements Filterable {
    private int[] mTo; // 指向布局里面控件的id 比如:R.id.btn
    private String[] mFrom; // 数据来源,来自Map里面的key
    private ViewBinder mViewBinder;// 接口类型,里面有个setViewValue方法,用于出现特殊类型控件比如:drawable的时候在外部初始化接口,实现具体方法  

    private List<? extends Map<String, ?>> mData;// 用List打包的Map数据源  

    private int mResource;// 布局
    private int mDropDownResource;// 资源文件
    private LayoutInflater mInflater;//LayoutInflater用来载入界面  

    private SimpleFilter mFilter;// 过滤器
    private ArrayList<Map<String, ?>> mUnfilteredData;  

    // SimpleAdapter初始化,将传进了的参数都赋给本地的对应变量
    public SimpleAdapter(Context context, List<? extends Map<String, ?>> data,
        int resource, String[] from, int[] to) {
        mData = data;
        mResource = mDropDownResource = resource;
        mFrom = from;
        mTo = to;
        mInflater = (LayoutInflater) context
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }  

    /*
     * ListView 针对每个item,要求 adapter “返回一个视图” (getView),
     * 也就是说ListView在开始绘制的时候,系统首先调用getCount()函数,根据他的返回值得到ListView的长度,
     * 然后根据这个长度,调用getView()一行一行的绘制ListView的每一项。如果你的getCount()返回值是0的话,
     * 列表一行都不会显示,如果返回1,就只显示一行。返回几则显示几行。如果我们有几千几万甚至更多的item要显示怎么办?
     * 为每个Item创建一个新的View?不可能!!!实际上Android早已经缓存了这些视图,大家可以看下下面这个截图来理解下,
     * 其实Android中有个叫做Recycler的构件
     */
    public int getCount() {
        return mData.size();
    }  

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

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

    public View getView(int position, View convertView, ViewGroup parent) {
        // 调用createViewFromResource来优化内存
        return createViewFromResource(position, convertView, parent, mResource);
    }  

    /*
     * ListView的机制在这里再说一下,当第一个数据来getView的时候convertView肯定是null,
     * 那么就用mInflater.inflate(resource, parent,
     * false)给它初始化一个View,但是当一屏滑到底了,第一个item,滑出了屏幕,那么它将
     * 从底部出来,那时候convertView就不为null,这个方法的好处就是当convertView不为null
     * 的时候不用加载布局,直接使用convertView, 节省了一步,这也是所说的优化ListView的第一个步骤。
     */
    private View createViewFromResource(int position, View convertView,
        ViewGroup parent, int resource) {
        View v;
        if (convertView == null) {
            v = mInflater.inflate(resource, parent, false);
        } else {
            v = convertView;
        }
        // 这个方法是核心
        bindView(position, v);  

        return v;
    }  

    public void setDropDownViewResource(int resource) {
        this.mDropDownResource = resource;
    }  

    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        return createViewFromResource(position, convertView, parent,
            mDropDownResource);
    }  

    // 这个方法的主要功能就是按照 to数组里面控件的顺序挨个赋值,比如new int[]{R.id.tv_name,R.id.tv_pwd}。
    private void bindView(int position, View view) {
        final Map dataSet = mData.get(position);// 找到对应的position位置的map数据
        // 如果没找到跳出
        if (dataSet == null) {
            return;
        }
        /*
         * 将外部实现的ViewBinder,赋值给本地,SimpleAdapter能够实现:
         * checkBox,CheckedTextView,TextView
         * ,ImageView,数据类型也就是Boolean,Integer,Stirng, 所以特殊数据类型的时候才用到ViewBinder
         * ,如果没用到就不需要外部实现ViewBinder接口和里面的方法
         */
        final ViewBinder binder = mViewBinder;
        final String[] from = mFrom;
        final int[] to = mTo;
        final int count = to.length;
//view.findViewById(to[i]),循环找控件
        for (int i = 0; i < count; i++) {
            final View v = view.findViewById(to[i]);
            //如果v不为空的话,找到对应的数据,Object类型的data转换为String,因为boolean在map里面纯的也是true或者false
            if (v != null) {
                final Object data = dataSet.get(from[i]);
                String text = data == null ? "" : data.toString();
                if (text == null) {
                    text = "";
                }
//标志变量bound,判断外部有没有实现ViewBinder,如果实现了,就执行binder.setViewValue(v, data, text),如果符合特殊条件,就返回true
                boolean bound = false;
                if (binder != null) {
                    bound = binder.setViewValue(v, data, text);
                }
//如果满足if (!bound)那么bound就还是false,说明是普通数据
                if (!bound) {
                    //查看v是不是Checkable的实例化类型,满足的情况可能是CheckBox,CheckedTextView
                    if (v instanceof Checkable) {
                        //如果数据类型是boolean,那么就是CheckBox
                        if (data instanceof Boolean) {
                            ((Checkable) v).setChecked((Boolean) data);
                            //如果不是CheckBox,那么判断是不是继承TextView的CheckedTextView,是的话赋值,不是就抛出异常
                        } else if (v instanceof TextView) {
                            setViewText((TextView) v, text);
                        } else {
                            throw new IllegalStateException(v.getClass()
                                .getName()
                                + " should be bound to a Boolean, not a "
                                + (data == null ? "<unknown type>"
                                    : data.getClass()));
                        }
                        //如果不是Checkable的实例化类型,判断是不是TextView的实例化类型
                    } else if (v instanceof TextView) {
                        setViewText((TextView) v, text);
                        //都不是以上情况,就判断一下是不是ImageView的实例化类型
                    } else if (v instanceof ImageView) {
                        //这里只满足数据类型为int也就是R.drawable.ic,和String类型的url,如果想实现直接用drawbale,就要实现ViewBinder
                        if (data instanceof Integer) {
                            setViewImage((ImageView) v, (Integer) data);
                        } else {
                            setViewImage((ImageView) v, text);
                        }
                    } else {
                        throw new IllegalStateException(
                            v.getClass().getName()
                            + " is not a "
                            + " view that can be bounds by this SimpleAdapter");
                    }
                }
            }
        }
    }  

    public ViewBinder getViewBinder() {
        return mViewBinder;
    }  

    public void setViewBinder(ViewBinder viewBinder) {
        mViewBinder = viewBinder;
    }  

    public void setViewImage(ImageView v, int value) {
        v.setImageResource(value);
    }  

    public void setViewImage(ImageView v, String value) {
        try {
            v.setImageResource(Integer.parseInt(value));
        } catch (NumberFormatException nfe) {
            v.setImageURI(Uri.parse(value));
        }
    }  

    public void setViewText(TextView v, String text) {
        v.setText(text);
    }  

    public Filter getFilter() {
        if (mFilter == null) {
            mFilter = new SimpleFilter();
        }
        return mFilter;
    }  

    public static interface ViewBinder {
        boolean setViewValue(View view, Object data, String textRepresentation);
    }  

//这里是数据过滤器,根据前缀过滤
    private class SimpleFilter extends Filter {  

        @Override
        protected FilterResults performFiltering(CharSequence prefix) {
            FilterResults results = new FilterResults();  

            if (mUnfilteredData == null) {
                mUnfilteredData = new ArrayList<Map<String, ?>>(mData);
            }  

            if (prefix == null || prefix.length() == 0) {
                ArrayList<Map<String, ?>> list = mUnfilteredData;
                results.values = list;
                results.count = list.size();
            } else {
                String prefixString = prefix.toString().toLowerCase();  

                ArrayList<Map<String, ?>> unfilteredValues = mUnfilteredData;
                int count = unfilteredValues.size();  

                ArrayList<Map<String, ?>> newValues = new ArrayList<Map<String, ?>>(
                    count);  

                for (int i = 0; i < count; i++) {
                    Map<String, ?> h = unfilteredValues.get(i);
                    if (h != null) {  

                        int len = mTo.length;  

                        for (int j = 0; j < len; j++) {
                            String str = (String) h.get(mFrom[j]);  

                            String[] words = str.split(" ");
                            int wordCount = words.length;  

                            for (int k = 0; k < wordCount; k++) {
                                String word = words[k];  

                                if (word.toLowerCase().startsWith(prefixString)) {
                                    newValues.add(h);
                                    break;
                                }
                            }
                        }
                    }
                }  

                results.values = newValues;
                results.count = newValues.size();
            }  

            return results;
        }  

  //最后这里是对过滤结果通过notifyDataSetChanged()更新UI
        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            // noinspection unchecked
            mData = (List<Map<String, ?>>) results.values;
            if (results.count > 0) {
                notifyDataSetChanged();
            } else {
                notifyDataSetInvalidated();
            }
        }
    }
}
} 

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-06 00:41:24

Android SimpleAdapter源码解析的相关文章

Android xUtils3源码解析之数据库模块

xUtils3源码解析系列 一. Android xUtils3源码解析之网络模块 二. Android xUtils3源码解析之图片模块 三. Android xUtils3源码解析之注解模块 四. Android xUtils3源码解析之数据库模块 配置数据库 DbManager.DaoConfig daoConfig = new DbManager.DaoConfig() .setDbName("test.db") .setDbVersion(1) .setDbOpenListe

Android xUtils3源码解析之注解模块

xUtils3源码解析系列 一. Android xUtils3源码解析之网络模块 二. Android xUtils3源码解析之图片模块 三. Android xUtils3源码解析之注解模块 四. Android xUtils3源码解析之数据库模块 初始化 public class BaseActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { su

Android设计模式源码解析之观察者模式

Android设计模式源码解析之观察者模式 本文为 Android 设计模式源码解析 中 观察者模式 分析 Android系统版本: 2.3 分析者:Mr.Simple,分析状态:未完成,校对者:Mr.Simple,校对状态:未开始 1. 模式介绍 模式的定义 定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新. 模式的使用场景 关联行为场景.需要注意的是,关联行为是可拆分的,而不是"组合"关系: 事件多级触发场景: 跨系统的消息交换

Android -- AsyncTask源码解析

1,前段时间换工作的时候,关于AsyncTask源码这个点基本上大一点的公司都会问,所以今天就和大家一起来总结总结.本来早就想写这篇文章的,当时写<Android -- 从源码解析Handle+Looper+MessageQueue机制>的时候就是想为这篇文章做铺垫的,因为AsyncTask说里面还是使用的handle,所以先就写了handle这一篇.记得15年底去美团面试的时候,面试官就问我既然存在handle为什么google还要出AsyncTask(毕竟底层还是用的handle+Exec

Android EventBus源码解析, 带你深入理解EventBus

上一篇带大家初步了解了EventBus的使用方式,详见:Android EventBus实战 没听过你就out了,本篇博客将解析EventBus的源码,相信能够让大家深入理解该框架的实现,也能解决很多在使用中的疑问:为什么可以这么做?为什么这么做不好呢? 1.概述 一般使用EventBus的组件类,类似下面这种方式: [java] view plain copy public class SampleComponent extends Fragment { @Override public vo

Android AsyncTask 源码解析

1. 官方介绍 public abstract class AsyncTask extends Object  java.lang.Object    ? android.os.AsyncTask<Params, Progress, Result> AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish resul

Android xUtils3源码解析之图片模块

初始化 x.Ext.init(this); public static void init(Application app) { TaskControllerImpl.registerInstance(); if (Ext.app == null) { Ext.app = app; } } public final class TaskControllerImpl implements TaskController { public static void registerInstance()

Android EventBus源码解析 带你深入理解EventBus

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40920453,本文出自:[张鸿洋的博客] 上一篇带大家初步了解了EventBus的使用方式,详见:Android EventBus实战 没听过你就out了,本篇博客将解析EventBus的源码,相信能够让大家深入理解该框架的实现,也能解决很多在使用中的疑问:为什么可以这么做?为什么这么做不好呢? 1.概述 一般使用EventBus的组件类,类似下面这种方式: public cl

Android setContentView()源码解析

前言 在Activity中一般第一句就是调用setContentView(R.layout.XXX),但这其中系统做了那些工作? 我们知道,在ClassLoader装载了MainActivity之后,首先创建了Application,之后依次调用Application对象的onAttach和onCreate()方法.然后顺序调用第一个Activity的onAttach和onCreate()方法.大概有个印象即可,后文会涉及到.具体参考:Launcher启动应用程序流程源码解析. 新建测试工程Te