Andorid ListView和Adapter优化

来源:互联网 发布:软件改变生活 编辑:程序博客网 时间:2024/05/17 11:04

今天来说一下Android 中ListView控件 和使用Adapter 绑定数据。
现在分别列出两个对象的说明:

ListView

  • 通常我们如果加载比较多相同类型的数据,会使用ListView,使用ListView有说明好处呢。ListView是一个可以滚动的视图控件,加载一条一条的Item数据是很好的选择。为什么说它好。原因就是ListView 只有在可见的范围内才加载数据,一但数据被划出屏幕之外,数据就会进入缓存或者销毁,可以节省很多内存。如果传统做法的话,就需要一次性把所有数据加载到内存,系统负荷比较重。

Adapter

  • Adapter又是怎么东西呢?
  • 在我们需要使用ListView这样展示相同结构 Item 的时候,就需要用到Adapter来进行数据匹配,说通俗点就是:把数据绑定到一个列表类的视图中去。

    下面我先个简单Adapter

SimpleAdapter adapter; adapter=newSimpleAdapter(context,data,resource,from,to);`

这个Adapter传进来5个参数,下面分别对这些参数进行讲解:

  • context ——上下文对象(这个在这里我不详细讲解,网上很多资料)
  • data——这个参数要求的是一个List<Map<String,Object>>集合,里面装的数据是Map<String,Object>集合,通常我们需要把数据装到Map集合里面,再把Map集合装到List集合里面去即可。
  • resource ——指的是自定义的布局文件,里面需要设好对应控件的id
  • form ——是一个String数组,里面放的是你定义Map集合时用到的key值,数据顺序和后面一个参数要一一匹配
  • to ——resource参数对对应的布局文件中的控件 id ,和前一个参数一一对应。

可能有人还不不明白上面所说,下面给一个例子。

List<Map<String,Object>> data=new ArrayList<Map<String,Object>>();        Map<String,Object> map = new HashMap<String, Object>();        map.put("name", "haha");        data.add(map);        SimpleAdapter adapter = new SimpleAdapter(this, data, R.layout.test, new String[]{"name"},new int[]{R.id.name});

上面一段代码的意思是将你放进map里面的key为name的值放到R.layout.test 布局中的 id 为 name 的控件中,如果有多条数据,就用for循环创建多个Map集合,把它添加到List集合即可,ListView会用布局文件作为一个Item的布局显示出来一个列表。

其实在开发中,用的最多的还是自定义Adapter ,自定义Adapter需要自定义一个类继承BaseAdapter,BaseAdapter有几个方法需要你实现:

假设我要放在listview数据已经存在一个List集合里面,名为list

  • public int getCount() ——返回你需要显示的数据条目的数量(list.size())
  • public Object getItem(int position )——返回要显示的数据中的第position个数据(list.get(position))
  • public long getItemId(int position)——-返回条目ID (position)
  • public View getView(int position, View convertView, ViewGroup parent) 该方法在需要显示数据的时候调用,即在滑动ListView的时候调用,传进来几个参数需要说明一下,position指的数第几个条目,converView指的是缓存view对象(一般条目被划出屏幕都会被缓存),ViewGroup指,父节点,一般不用理会。

说完几个需要实现的方法了,那么我们应该怎么做呢,其实很简单,getView方法就是要我们返回每一个Item执行的方法,在listview 每在屏幕中出现一个新的Item都会调用一次该方法。而且每一次都会把Item是第几个通过position参数传进来。我们在里面就可以通过
View v = View.inflate(MainActivity.this, R.layout.item, null); 方法来加载布局文件,同时通过该View对象找到里面的子控件。最后我们把这个View对象返回就是需要显示的Item了。

说那么多没什么用,用一个实例说明吧。

加入我有布局文件item.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="horizontal" >    <TextView        android:id="@+id/name"        android:layout_width="wrap_content"        android:layout_height="wrap_content" />    <TextView        android:id="@+id/salary"        android:layout_width="wrap_content"        android:layout_height="wrap_content" />    <TextView        android:id="@+id/phone"        android:layout_width="wrap_content"        android:layout_height="wrap_content" /></LinearLayout>

我需要以该布局作为一个item的布局,然后把数据显示出去。

 class MyAdapter extends BaseAdapter{        private List<Person> list = new ArrayList<Persom>();        public void MyAdapter(){        for(int i =0 ;i< 10;i++){//初始化数据,姓名,薪水,电话号码            list.add(new Person("哈哈"+110000+i,"1387894"+i))                }        }        @Override        public int getCount() {            return list.size();        }        @Override        public Object getItem(int position) {            return position;        }        @Override        public long getItemId(int position) {            return position;        }        @Override        public View getView(int position, View convertView, ViewGroup parent) {View v = View.inflate(MainActivity.this, R.layout.item, null);            TextView name = (TextView) v.findViewById(R.id.name);        TextView salary = (TextView) v.findViewById(R.id.salary);          TextView phone = (TextView) v.findViewById(R.id.phone);            Person p = list.get(position);            name.setText(p.getName());            salary.setText(p.getSalary());            phone.setText(p.getPhone());            return v;        }    }}

这样简单的代码就能把数据绑定到ListView了。

其实这样的代码有2点不好的地方:

  • gerView 方法存进来的是一个convertView对象,该对象是缓存视图,在listview第一次加载的时候,该对象为空,但是一旦listview滑动,就会有对象保存到convertView中去了,所以我们不必要每次调用getView都需要创建加载一个布局文件,我们可以先判断convertView是否为空,不为空的话,可以直接使用。
  • 每次调用都会执行几次findViewById方法,这样也会耗费不必要的资源,我们可以定义一个ViewHolder,每次找到了子空间就存放在ViewHolder中,然后通过setTag 方法把ViewHolder绑定到view对象中,当缓存中获取该view对象中,里面就包含了对应的ViewHolder对象,节省了不必要的操作。

最终代码如下:

    class MyAdapter extends BaseAdapter{        private List<Person> list = new ArrayList<Persom>();        public void MyAdapter(){        for(int i =0 ;i< 10;i++){//初始化数据,姓名,薪水,电话号码            list.add(new Person("哈哈"+110000+i,"1387894"+i))                }        }        @Override        public int getCount() {            return list.size();        }        @Override        public Object getItem(int position) {            return position;        }        @Override        public long getItemId(int position) {            return position;        }        @Override        public View getView(int position, View convertView, ViewGroup parent) {            //从布局文件填充称为view对象            /**             * 第二个参数convertView 是缓存视图             * 优化过程是,getView会传进来一个convertView对象,该对象是缓存的视图,             * 为了使程序优化,避免出现OOM,所以我们需要判断converView是否为空,             * 不为空就返回convertView  ,问题来了:当listview滑动几次之后,convertView             * 就不一定是我们所需要的那个View对象,所以最后要把view对象的数据重新绑定,这样就             * 不会出问题了。             */            View v = null;            //当缓存不为空的时候,就填充视图,该代码优化了内存的使用            ViewHolder mHolder = null;            if(convertView == null){                v = View.inflate(MainActivity.this, R.layout.item, null);                mHolder = new ViewHolder();                mHolder.name = (TextView) v.findViewById(R.id.name);                mHolder.salary = (TextView) v.findViewById(R.id.salary);                mHolder.phone = (TextView) v.findViewById(R.id.phone);                v.setTag(mHolder); //将mholder绑定到view对象中,通过getTag方法就可以回去对应的view 避免每次重复查找            }else{                //当缓存不为空的时候,就不必要执行findViewById操作了                v = convertView;                mHolder = (ViewHolder) v.getTag();            }            //因为convertView对象是指缓存中的内容,不一定是我们需要的那个view对象,所以要重新设值            System.out.println("getView调用:"+position);            Person p = list.get(position);            mHolder.name.setText(p.getName());            mHolder.salary.setText(p.getSalary());            mHolder.phone.setText(p.getPhone());            return v;        }    }    /**     * ViewHolder 的作用是为了避免每次调用getView的时候都要再执行findviewById()这样会耗费资源     * @author Jam     *     */    class ViewHolder{        TextView name;        TextView salary;        TextView phone;     }}

以上就是我对ListView的一些总结了。

0 0
原创粉丝点击