连接AdapterView视图和数据源的桥梁:Adapter适配器(2)

  BaseAdapter是一种原生态的适配器,它是一个抽象类,一般使用它来实现自定义的适配器,当需要适配大量的数据时,为了节省手机的内存,往往会定义一个类继承它,从而优化内存的使用,使用在ListView、Spinner的内存效率优化。

  查询Android官方文档可知BaseAdapter的类定义

BaseAdapter是直接继承Java中顶级类Object类,同时它实现了ListAdapter和SpinnerAdapter接口。BaseAdapter的常用直接子类有ArrayAdapter<T>、CursorAdapter(抽象类)和SimpleAdapter,常用间接子类有ResourceCursorAdapter(抽象类)和SimpleCursorAdapter。

  一般定义一个类,它继承了BaseAdapter,同时会重写BaseAdapter的四个重要方法:

  1.public int getCount()  返回BaseAdapter适配的数据项个数

  2.public Object getItem(int position)  返回BaseAdapter适配的第postion个数据项的数据

  3.public long getItemId(int position)  返回BaseAdapter开始适配数据项的序号

  4.public View getView(int position, View convertView, ViewGroup parent)  返回BaseAdapter创建的某一个数据项

    

  BaseAdapter的使用一般在于它的优化,即重写getView()方法采用的不用方式,一般有三种写法:

  1.逗比式:未进行任何的优化,按一般思路来重写,当数据量不大,没有什么大问题,一旦数据量比较大时,严重浪费内存同时效率特别低。

  源码:

 1 @Override
 2     public View getView(int position, View convertView, ViewGroup parent) {
 3         View view = null;
 4 
 5         // 将布局文件转化为View对象,通过View对象获取需要设置数据的UI组件对象(两种方法)
 6         // view =LayoutInflater.from(context).inflate(R.layout.item_layout,null);
 7         view = LayoutInflater.from(context).inflate(R.layout.item_layout,
 8                 parent, false);
 9         ImageView image = (ImageView) view.findViewById(R.id.image);
10         TextView title = (TextView) view.findViewById(R.id.title);
11         TextView content = (TextView) view.findViewById(R.id.content);
12 
13         // 获取该position数据项要显示的数据
14         Map<String, Object> map = (Map<String, Object>) getItem(position);
15 
16         // 设置数据
17         image.setImageResource((Integer) map.get("image"));
18         title.setText(map.get("title").toString());
19         content.setText(map.get("content").toString());
20 
21         // 返回第position项的数据项视图
22         return view;
23     }

  2.一般式:在1的基础上进行优化,主要优化点在于,利用了方法中的convertView参数,这个参数是系统缓存的View视图,每次调用getView()方法创建View对象时,先判断是否convertView对象是否为空,当不为空时,不在创建View对象,之间将View指向convertView对象的地址,当为空时,采取和1一样的操作,即将布局文件转化为View对象。

 1 //方式2:利用缓存的convertView对象,不用每次都重新创建View对象,减少了内存空间的分配
 2     @Override
 3     public View getView(int position, View convertView, ViewGroup parent) {
 4         View view = null;
 5 
 6         if(convertView!=null)
 7             view = convertView;
 8         else{
 9             // 将布局文件转化为View对象,通过View对象获取需要设置数据的UI组件对象(两种方法)
10             // view =LayoutInflater.from(context).inflate(R.layout.item_layout,null);
11             view = LayoutInflater.from(context).inflate(R.layout.item_layout,
12                     parent, false);
13         }
14         
15         ImageView image = (ImageView) view.findViewById(R.id.image);
16         TextView title = (TextView) view.findViewById(R.id.title);
17         TextView content = (TextView) view.findViewById(R.id.content);
18 
19         // 获取该position数据项要显示的数据
20         Map<String, Object> map = (Map<String, Object>) getItem(position);
21 
22         // 设置数据
23         image.setImageResource((Integer) map.get("image"));
24         title.setText(map.get("title").toString());
25         content.setText(map.get("content").toString());
26 
27         // 返回第position项的数据项视图
28         return view;
29     }

  3.文艺式:在2的基础上进行优化,首先创建一个内部类,然后利用new View.setTag(Object object)和new View.getTag()方法,减少findViewById(int)的次数,当数据巨大时,可以发挥显著的效果。

 1 //方式三:在方式2的基础上,利用一个内部类,同时调用view.setTag(Object object)和view.getTag()方法
 2     //减少了findViewById(int)的次数
 3     @Override
 4     public View getView(int position, View convertView, ViewGroup parent) {
 5         View view = null;
 6 
 7         if(convertView!=null)
 8             view = convertView;
 9         else{
10             // 将布局文件转化为View对象,通过View对象获取需要设置数据的UI组件对象(两种方法)
11             // view =LayoutInflater.from(context).inflate(R.layout.item_layout,null);
12             view = LayoutInflater.from(context).inflate(R.layout.item_layout,
13                     parent, false);
14             ViewHolder holder = new ViewHolder();
15             holder.image = (ImageView) view.findViewById(R.id.image);
16             holder.title = (TextView) view.findViewById(R.id.title);
17             holder.content = (TextView) view.findViewById(R.id.content);
18             view.setTag(holder);
19         }
20         
21         ViewHolder viewHolder = (ViewHolder) view.getTag();
22 
23         // 获取该position数据项要显示的数据
24         Map<String, Object> map = (Map<String, Object>) getItem(position);
25 
26         // 设置数据
27         viewHolder.image.setImageResource((Integer) map.get("image"));
28         viewHolder.title.setText(map.get("title").toString());
29         viewHolder.content.setText(map.get("content").toString());
30 
31         // 返回第position项的数据项视图
32         return view;
33     }
34     class ViewHolder{
35         ImageView image;
36         TextView title;
37         TextView content;
38     }

注意:

  1.内部类ViewHolder是一个自定义类,它的类名是自定义的,我们可以取不同的名字,而不一定非要为ViewHolder。

  2.参数列表中的参数View convertView,它缓存了使用过的视图,例如当AdapterView是ListView时,上滑动ListView,顶部的数据项View视图会不见,这时就缓存为convertView,

上滑动多次,这时可能有多个convertView对象

  3.new View().setTag(Object object)和new View.getTag()方法,可以看作是当封装实体类时的setXXX()和getXXX()方法类似,便于理解和记忆。

扩展:

  可以在一个方法中创建BaseAdapter的匿名内部类,也可以将自定义继承了BaseAdapter的类作为某个类的内部类,也可以如上单独定义一个外部类继承BaseAdapter,它们根据情景的不同可以灵活的使用。例如将自定义继承了BaseAdapter的类作为某个类的内部类,如果这个外部类中存在数据源,那么就可以直接访问外部类的数据源,就不需要像上面的例子样传递上下文对象和数据源了,有时候方便多了。

  示例:

  需求:MainActivity界面利用ListView显示10条数据,自定义适配器BaseAdapter,采用上述三种重写getView方法。

  MainActivity源码:

 1 package com.my.day21_my_listview3;
 2 
 3 import java.util.ArrayList;
 4 import java.util.HashMap;
 5 import java.util.List;
 6 import java.util.Map;
 7 
 8 import com.my.day21_my_listview3.adapter.MyAdapter;
 9 
10 import android.os.Bundle;
11 import android.widget.ListView;
12 import android.app.Activity;
13 
14 public class MainActivity extends Activity {
15     private ListView listView;
16     private MyAdapter adapter;
17     private List<Map<String, Object>> data;
18     
19     @Override
20     protected void onCreate(Bundle savedInstanceState) {
21         super.onCreate(savedInstanceState);
22         setContentView(R.layout.activity_main);
23         
24         //获取ListView组件对象
25         listView = (ListView) findViewById(R.id.listView);
26         
27         //初始化数据源
28         data = new ArrayList<Map<String,Object>>();
29         for(int i=1;i<=10;i++){
30             Map<String, Object> map = new HashMap<String, Object>();
31             map.put("image", R.drawable.ic_launcher);
32             map.put("title", "这是第"+i+"个数据项的标题");
33             map.put("content", "这是第"+i+"个数据项的内容");
34             data.add(map);
35         }
36         
37         //创建适配器对象
38         adapter = new MyAdapter(this,data);
39         
40         //绑定适配器
41         listView.setAdapter(adapter);
42     }
43 }
View Code

  MyAdapter源码:

  1 package com.my.day21_my_listview3.adapter;
  2 
  3 import java.util.List;
  4 import java.util.Map;
  5 
  6 import com.my.day21_my_listview3.R;
  7 
  8 import android.content.Context;
  9 import android.view.LayoutInflater;
 10 import android.view.View;
 11 import android.view.ViewGroup;
 12 import android.widget.BaseAdapter;
 13 import android.widget.ImageView;
 14 import android.widget.TextView;
 15 
 16 public class MyAdapter extends BaseAdapter {
 17     private Context context;
 18     private List<Map<String, Object>> data;
 19 
 20     public MyAdapter(Context context,List<Map<String, Object>> data){
 21         this.context = context;
 22         this.data = data;
 23     }
 24     
 25     @Override
 26     public int getCount() {
 27         int count = 0;
 28         if (data != null)
 29             count = data.size();
 30         return count;
 31     }
 32 
 33     @Override
 34     public Map<String, Object> getItem(int position) {
 35         return data.get(position);
 36     }
 37 
 38     @Override
 39     public long getItemId(int position) {
 40         return position;
 41     }
 42 
 43     /*@Override
 44     public View getView(int position, View convertView, ViewGroup parent) {
 45         View view = null;
 46 
 47         // 将布局文件转化为View对象,通过View对象获取需要设置数据的UI组件对象(两种方法)
 48         // view =LayoutInflater.from(context).inflate(R.layout.item_layout,null);
 49         view = LayoutInflater.from(context).inflate(R.layout.item_layout,
 50                 parent, false);
 51         ImageView image = (ImageView) view.findViewById(R.id.image);
 52         TextView title = (TextView) view.findViewById(R.id.title);
 53         TextView content = (TextView) view.findViewById(R.id.content);
 54 
 55         // 获取该position数据项要显示的数据
 56         Map<String, Object> map = (Map<String, Object>) getItem(position);
 57 
 58         // 设置数据
 59         image.setImageResource((Integer) map.get("image"));
 60         title.setText(map.get("title").toString());
 61         content.setText(map.get("content").toString());
 62 
 63         // 返回第position项的数据项视图
 64         return view;
 65     }*/
 66     
 67     /*//方式2:利用缓存的convertView对象,不用每次都重新创建View对象,减少了内存空间的分配
 68     @Override
 69     public View getView(int position, View convertView, ViewGroup parent) {
 70         View view = null;
 71 
 72         if(convertView!=null)
 73             view = convertView;
 74         else{
 75             // 将布局文件转化为View对象,通过View对象获取需要设置数据的UI组件对象(两种方法)
 76             // view =LayoutInflater.from(context).inflate(R.layout.item_layout,null);
 77             view = LayoutInflater.from(context).inflate(R.layout.item_layout,
 78                     parent, false);
 79         }
 80         
 81         ImageView image = (ImageView) view.findViewById(R.id.image);
 82         TextView title = (TextView) view.findViewById(R.id.title);
 83         TextView content = (TextView) view.findViewById(R.id.content);
 84 
 85         // 获取该position数据项要显示的数据
 86         Map<String, Object> map = (Map<String, Object>) getItem(position);
 87 
 88         // 设置数据
 89         image.setImageResource((Integer) map.get("image"));
 90         title.setText(map.get("title").toString());
 91         content.setText(map.get("content").toString());
 92 
 93         // 返回第position项的数据项视图
 94         return view;
 95     }*/
 96     
 97     //方式三:在方式2的基础上,利用一个内部类,同时调用view.setTag(Object object)和view.getTag()方法
 98     //减少了findViewById(int)的次数
 99     @Override
100     public View getView(int position, View convertView, ViewGroup parent) {
101         View view = null;
102 
103         if(convertView!=null)
104             view = convertView;
105         else{
106             // 将布局文件转化为View对象,通过View对象获取需要设置数据的UI组件对象(两种方法)
107             // view =LayoutInflater.from(context).inflate(R.layout.item_layout,null);
108             view = LayoutInflater.from(context).inflate(R.layout.item_layout,
109                     parent, false);
110             ViewHolder holder = new ViewHolder();
111             holder.image = (ImageView) view.findViewById(R.id.image);
112             holder.title = (TextView) view.findViewById(R.id.title);
113             holder.content = (TextView) view.findViewById(R.id.content);
114             view.setTag(holder);
115         }
116         
117         ViewHolder viewHolder = (ViewHolder) view.getTag();
118 
119         // 获取该position数据项要显示的数据
120         Map<String, Object> map = (Map<String, Object>) getItem(position);
121 
122         // 设置数据
123         viewHolder.image.setImageResource((Integer) map.get("image"));
124         viewHolder.title.setText(map.get("title").toString());
125         viewHolder.content.setText(map.get("content").toString());
126 
127         // 返回第position项的数据项视图
128         return view;
129     }
130     class ViewHolder{
131         ImageView image;
132         TextView title;
133         TextView content;
134     }
135 }
View Code

  activity_main文件:

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:paddingBottom="@dimen/activity_vertical_margin"
 6     android:paddingLeft="@dimen/activity_horizontal_margin"
 7     android:paddingRight="@dimen/activity_horizontal_margin"
 8     android:paddingTop="@dimen/activity_vertical_margin"
 9     tools:context=".MainActivity" >
10 
11     <ListView
12         android:id="@+id/listView"
13         android:layout_width="match_parent"
14         android:layout_height="match_parent" >
15     </ListView>
16 
17 </RelativeLayout>
View Code

  列表项布局item_layout文件:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:orientation="horizontal"
 6     android:padding="10dp" >
 7 
 8     <ImageView
 9         android:id="@+id/image"
10         android:layout_width="80dp"
11         android:layout_height="80dp"
12         android:scaleType="fitXY" />
13 
14     <LinearLayout
15         android:layout_width="match_parent"
16         android:layout_height="80dp"
17         android:orientation="vertical" >
18 
19         <TextView
20             android:id="@+id/title"
21             android:layout_width="match_parent"
22             android:layout_height="wrap_content"
23             android:gravity="center"
24             android:textSize="20sp"
25             android:textStyle="bold" />
26 
27         <TextView
28             android:id="@+id/content"
29             android:layout_width="match_parent"
30             android:layout_height="0dp"
31             android:layout_marginLeft="20dp"
32             android:layout_weight="1"
33             android:gravity="center_horizontal" >
34         </TextView>
35     </LinearLayout>
36 
37 </LinearLayout>
View Code

  效果图:

  未完,待续。

原文地址:https://www.cnblogs.com/enjoy-coding/p/4798915.html