GridView、ListView、Adapter、Map、HashMap

来源:互联网 发布:java中重载的作用 编辑:程序博客网 时间:2024/06/05 16:43

1.ListView自定义适配器adapter
注:Android适配器是数据和视图之间的桥梁,以便于数据在View上显示。适配器就像显示器,把复杂的东西按人可以接受的方式来展现。
(1)首先将适配器的View视图表现出来,使用ListView为例:

<?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="vertical">    <ListView        android:id="@+id/listview"        android:layout_width="match_parent"        android:layout_height="match_parent">    </ListView></LinearLayout>

(2)把调用适配器的代码写好,之后再自定义适配器。

public class MainActivity extends AppCompatActivity {    private ListView listView;    private MyAdapter adapter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.adapter);        listView = (ListView) findViewById(R.id.listview);        adapter = new MyAdapter(getData());        listView.setAdapter(adapter);    }}

(3)现在开始自定义适配器,名字命名为MyAdapter,继承BaseAdapter,并重载这个抽象类的方法,实现其功能:

public class MyAdapter extends BaseAdapter{        private List<String> list;        //构造函数使其属性本地化,方便加载数据        public MyAdapter(List<String> list){            this.list = list;        }        //获取数据的长度        @Override        public int getCount() {            return list.size();        }        //获取某一位置的数据        @Override        public Object getItem(int position) {            return list.get(position);        }        //用户获取数据的位置        @Override        public long getItemId(int position) {            return position;        }        @Override        public View getView(int position, View convertView, ViewGroup parent) {            TextView textView = new TextView(MainActivity.this);            textView.setText(list.get(position));            return textView;        }    }

(4)因为自定义适配器中用到了List集合,所以新建立一个getData方法,用于获取和存储数据。然后就可以通过适配器按照我们自定义的形式展示出来。

public List<String> getData(){        List<String> list = new ArrayList<String>();        for (int i = 0; i<10;i++){            list.add("xyy"+i);        }        return list;    }

2.使用BaseAdapter优化ListView
注:(1)其中BaseAdapter需要重写的方法:getCount(),getItem(int position),getItemId(int position),getView(int position, View convertView, ViewGroup parent)listView在开始绘制的时候,系统首先调用getCount()函数,根据他的返回值得到 listView的长度,然后根据这个长度,调用getView()逐一绘制每一行。

当手动完成适配时,必须手动映射数据,这需要重写getView()方 法。系统在绘制列表的每一行的时候将调用此方法。getView()有三个参数,position表示将显示的是第几行,covertView是从布局文 件中inflate来的布局。我们用LayoutInflater的方法将定义好的item.xml文件提取成View实例用来显示。然后将xml文件中 的各个组件实例化(简单的findViewById()方法)。这样便可以将数据对应到各个组件上了。

现在让我们回过头从新审视这个过程。系统要绘制ListView了,他首先获得要 绘制的这个列表的长度,然后开始绘制第一行,怎么绘制呢?调用getView()函数。在这个函数里面首先获得一个View(实际上是一个 ViewGroup),然后再实例并设置各个组件,显示之。好了,绘制完这一行了。那再绘制下一行,直到绘完为止。
(2)在实际开发中LayoutInflater这个类的作用类似findViewById()。不同点是LayoutInflater是用来找res/layout/下的xml布局文件,并且实例化;而findViewById()是找xml布局文件下的具体widget控件(如Button、TextView等)。对于一个没有被载入或者想要动态载入的界面,都需要使用LayoutInflater.inflate()来载入。

代码实例:

publicclass MyListViewBase extends Activity {    private ListView lv;    //定义一个动态数组        ArrayList<HashMap<String, Object>>listItem;/** Called when the activity is first created. */    @Override    publicvoid onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        lv = (ListView) findViewById(R.id.lv);        MyAdapter mAdapter = new MyAdapter(this);//得到一个MyAdapter对象        lv.setAdapter(mAdapter);//为ListView绑定Adapter        /**为ListView添加点击事件*/        lv.setOnItemClickListener(new OnItemClickListener() {            @Override            publicvoid onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) {                Log.v("MyListViewBase", "你点击了ListView条目" + arg2);//在LogCat中输出信息                            }        });    }    /**添加一个得到数据的方法,方便使用*/    private ArrayList<HashMap<String, Object>> getDate(){        ArrayList<HashMap<String, Object>> listItem = new ArrayList<HashMap<String,Object>>();        /**为动态数组添加数据*/            for(int i=0;i<30;i++)          {              HashMap<String, Object> map = new HashMap<String, Object>();              map.put("ItemTitle", "第"+i+"行");              map.put("ItemText", "这是第"+i+"行");              listItem.add(map);          }        return listItem;    }    /** 新建一个类继承BaseAdapter,实现视图与数据的绑定     */    privateclass MyAdapter extends BaseAdapter {        private LayoutInflater mInflater;//得到一个LayoutInfalter对象用来导入布局         /**构造函数*/        public MyAdapter(Context context) {            this.mInflater = LayoutInflater.from(context);        }        @Override        publicint getCount() {            return getDate().size();//返回数组的长度                }        @Override        public Object getItem(int position) {            return null;        }        @Override        publiclong getItemId(int position) {            return 0;        }        /**书中详细解释该方法*/                @Override        public View getView(finalint position, View convertView, ViewGroup parent) {             ViewHolder holder;            //观察convertView随ListView滚动情况                         Log.v("MyListViewBase", "getView " + position + " " + convertView);            if (convertView == null) {                     convertView = mInflater.inflate(R.layout.item,null);                     holder = new ViewHolder();                    /**得到各个控件的对象*/                                        holder.title = (TextView) convertView.findViewById(R.id.ItemTitle);                    holder.text = (TextView) convertView.findViewById(R.id.ItemText);                    holder.bt = (Button) convertView.findViewById(R.id.ItemButton);                    convertView.setTag(holder);//绑定ViewHolder对象                               }            else{                    holder = (ViewHolder)convertView.getTag();//取出ViewHolder对象                              }            /**设置TextView显示的内容,即我们存放在动态数组中的数据*/                        holder.title.setText(getDate().get(position).get("ItemTitle").toString());            holder.text.setText(getDate().get(position).get("ItemText").toString());            /**为Button添加点击事件*/                         holder.bt.setOnClickListener(new OnClickListener() {                @Override                publicvoid onClick(View v) {                    Log.v("MyListViewBase", "你点击了按钮" + position);//打印Button的点击信息                                    }            });            return convertView;        }    }    /**存放控件*/    publicfinal class ViewHolder{        public TextView title;        public TextView text;        public Button   bt;    }}

3.ArrayList和ListView:
列表的显示需要三个元素:
1.ListVeiw 用来展示列表的View。
2.适配器 用来把数据映射到ListView上的中介。
3.数据 具体的将被映射的字符串,图片,或者基本组件。
其中以ArrayAdapter最为简单,只能展示一行字。SimpleAdapter有最好的扩充性,可以自定义出各种效果。SimpleCursorAdapter可以认为是SimpleAdapter对数据库的简单结合,可以方便的把数据库的内容以列表的形式展示出来。

public class MyListView extends Activity {    private ListView listView;    //private List<String> data = new ArrayList<String>();    @Override    public void onCreate(Bundle savedInstanceState){        super.onCreate(savedInstanceState);        listView = new ListView(this);        listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1,getData()));        setContentView(listView);    }    private List<String> getData(){        List<String> data = new ArrayList<String>();        data.add("测试数据1");        data.add("测试数据2");        data.add("测试数据3");        data.add("测试数据4");        return data;    }}

注:上面代码使用了ArrayAdapter(Context context, int textViewResourceId, List objects)来装配数据,要装配这些数据就需要一个连接ListView视图对象和数组数据的适配器来两者的适配工作,ArrayAdapter的构造需要三个参数,依次为this,布局文件(注意这里的布局文件描述的是列表的每一行的布局android.R.layout.simple_list_item_1是系统定义好的布局文件只显示一行文字,数据源(一个List集合)。同时用setAdapter()完成适配的最后工作。
运行后的现实结构如下图:
这里写图片描述

4.ListView之BaseAdapter的基本使用及两种优化模式:
BaseAdapter与其他Adapter有些不一样,其他的Adapter可以直接在其构造方法中进行数据的设置,比如:

SimpleAdapter adapter = new SimpleAdapter(this, getData(), R.layout.list_item, new String[]{"img","title","info"},new int[]{R.id.img, R.id.title, R.id.info});

但是在BaseAdapter中需要实现一个继承自BaseAdapter的类,并且重写里面的很多方法,例如:

class MyAdapter extends BaseAdapter    {        private Context context;        public MyAdapter(Context context)        {            this.context = context;        }        @Override        public int getCount() {            // (在此适配器中所代表的数据集中的条目数)            return length;        }        @Override        public Object getItem(int position) {            // (获取数据集中与指定索引对应的数据项)            return list[position];        }        @Override        public long getItemId(int position) {            // (取在列表中与指定索引对应的行id)            return position;        }        @Override        public View getView(int position, View convertView, ViewGroup parent) {            // Get a View that displays the data at the specified position in the data set.            return null;        }    }

getView处理方式:
第一种方法:没有任何处理,不建议这样写。如果数据量少看将就,但是如果列表项数据量很大的时候,会每次都重新创建View,设置资源,严重影响性能,所以从一开始就不要用这种方式。

public View getView(int position, View convertView, ViewGroup parent) {            View item = mInflater.inflate(R.layout.list_item, null);            ImageView img = (ImageView)item.findViewById(R.id.img)            TextView title = (TextView)item.findViewById(R.id.title);            TextView info = (TextView)item.findViewById(R.id.info);            img.setImageResource(R.drawable.ic_launcher);            title.setText("Hello");            info.setText("world");            return item;        }

第二种方法:通过缓存convertView,这种利用缓存contentView的方式可以判断如果缓存中不存在View才创建View,如果已经存在可以利用缓存中的View,提升了性能。

public View getView(int position, View convertView, ViewGroup parent) {            if(convertView == null)            {                convertView = mInflater.inflate(R.layout.list_item, null);            }            ImageView img = (ImageView)convertView.findViewById(R.id.img)            TextView title = (TextView)convertView.findViewById(R.id.title);            TextView info = (TextView)ConvertView.findViewById(R.id.info);            img.setImageResource(R.drawable.ic_launcher);            title.setText("Hello");            info.setText("world");            return convertView;        }

第三种方法:通过convertView+ViewHolder来实现,ViewHolder就是一个静态类,使用 ViewHolder 的关键好处是缓存了显示数据的视图(View),加快了 UI 的响应速度。
注:当我们判断 convertView == null 的时候,如果为空,就会根据设计好的List的Item布局(XML),来为convertView赋值,并生成一个viewHolder来绑定converView里面的各个View控件(XML布局里面的那些控件)。再用convertView的setTag将viewHolder设置到Tag中,以便系统第二次绘制ListView时从Tag中取出。(看下面代码中)
如果convertView不为空的时候,就会直接用convertView的getTag(),来获得一个ViewHolder。

//在外面先定义,ViewHolder静态类static class ViewHolder{    public ImageView img;    public TextView title;    public TextView info;}//然后重写getView@Overridepublic View getView(int position, View convertView, ViewGroup parent) {    ViewHolder holder;    if(convertView == null)    {        holder = new ViewHolder();        convertView = mInflater.inflate(R.layout.list_item, null);        holder.img = (ImageView)item.findViewById(R.id.img)        holder.title = (TextView)item.findViewById(R.id.title);        holder.info = (TextView)item.findViewById(R.id.info);        convertView.setTag(holder);    }else    {        holder = (ViewHolder)convertView.getTag();    }        holder.img.setImageResource(R.drawable.ic_launcher);        holder.title.setText("Hello");        holder.info.setText("World");    }    return convertView;}

ViewHolder类的作用:
ViewHolder模式通过getView()方法返回的视图的标签(Tag)中存储一个数据结构,这个数据结构包含了指向我们要绑定数据的视图的引用,从而避免每次调用getView()的时候调用findViewById()。
实例:用BaseAdapter来自定义ListView布局:
main.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical" >    <ListView        android:id="@+id/lv"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:fastScrollEnabled="true"        /></LinearLayout>

list_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" >    <ImageView        android:id="@+id/img"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        />    <LinearLayout        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:orientation="vertical"        >        <TextView            android:id="@+id/tv"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:textSize="20sp"        />        <TextView            android:id="@+id/info"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:textSize="14sp"            />    </LinearLayout></LinearLayout>

Activity

package com.loulijun.demo17;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import android.app.Activity;import android.content.Context;import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.ListView;import android.widget.TextView;public class Demo17Activity extends Activity {    private ListView lv;    private List<Map<String, Object>> data;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        lv = (ListView)findViewById(R.id.lv);        //获取将要绑定的数据设置到data中        data = getData();        MyAdapter adapter = new MyAdapter(this);        lv.setAdapter(adapter);    }    private List<Map<String, Object>> getData()    {        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();        Map<String, Object> map;        for(int i=0;i<10;i++)        {            map = new HashMap<String, Object>();            map.put("img", R.drawable.ic_launcher);            map.put("title", "跆拳道");            map.put("info", "快乐源于生活...");            list.add(map);        }        return list;    }    //ViewHolder静态类    static class ViewHolder    {        public ImageView img;        public TextView title;        public TextView info;    }    public class MyAdapter extends BaseAdapter    {           private LayoutInflater mInflater = null;        private MyAdapter(Context context)        {            //根据context上下文加载布局,这里的是Demo17Activity本身,即this            this.mInflater = LayoutInflater.from(context);        }        @Override        public int getCount() {            //How many items are in the data set represented by this Adapter.            //在此适配器中所代表的数据集中的条目数            return data.size();        }        @Override        public Object getItem(int position) {            // Get the data item associated with the specified position in the data set.            //获取数据集中与指定索引对应的数据项            return position;        }        @Override        public long getItemId(int position) {            //Get the row id associated with the specified position in the list.            //获取在列表中与指定索引对应的行id            return position;        }        //Get a View that displays the data at the specified position in the data set.        //获取一个在数据集中指定索引的视图来显示数据        @Override        public View getView(int position, View convertView, ViewGroup parent) {            ViewHolder holder = null;            //如果缓存convertView为空,则需要创建View            if(convertView == null)            {                holder = new ViewHolder();                //根据自定义的Item布局加载布局                convertView = mInflater.inflate(R.layout.list_item, null);                holder.img = (ImageView)convertView.findViewById(R.id.img);                holder.title = (TextView)convertView.findViewById(R.id.tv);                holder.info = (TextView)convertView.findViewById(R.id.info);                //将设置好的布局保存到缓存中,并将其设置在Tag里,以便后面方便取出Tag                convertView.setTag(holder);            }else            {                holder = (ViewHolder)convertView.getTag();            }            holder.img.setBackgroundResource((Integer)data.get(position).get("img"));            holder.title.setText((String)data.get(position).get("title"));            holder.info.setText((String)data.get(position).get("info"));            return convertView;        }    }}

最后的运行图:
这里写图片描述

0 0