Android学习(十一)—— Android适配器
Android适配器
安卓的适配器在我看来是一个非常重要的知识点,面对形式相同但数据源较多的情况时,适配器是一个比较好的解决方法。
数据适配器是建立了数据源与控件之间的适配关系,将数据源转换为控件能够显示的数据格式,从而将数据的来源与数据的显示进行解耦,降低程序的耦合性。
这篇文章就说一下如何实现适配器。
首先说一下ListView的显示和缓存机制
我们知道,ListView、GridView等控件可以展示大量的数据信息。假如下图中的ListView可以展示100条信息,但是屏幕的尺寸是有限的,一屏幕只能显示下图中的4条。当向上滑动ListView的时候,T1被滑出了屏幕区域,那么系统就会将T1回收到Recycler中,即View缓冲池中,而将要显示的T5则会从缓存池中取出布局文件,并重新设置好T5需要显示的数据,并放入需要显示的位置。这就是ListView的缓冲机制,总结起来就是一句话:需要时才显示,显示完就被会收到缓存。ListView,GridView等数据显示控件通过这种缓存机制可以极大的节省系统资源。
然后来看一下实现方法
效果图
activity_main.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:id="@+id/container" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 android:orientation="vertical"> 7 8 <ListView 9 android:id="@+id/lv_main" 10 android:layout_width="match_parent" 11 android:layout_height="match_parent" 12 /> 13 14 </LinearLayout>
item_lv.xml (ListView中每条信息的显示布局)
1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout 3 xmlns:android="http://schemas.android.com/apk/res/android" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent"> 6 7 <ImageView 8 android:id="@+id/iv_image" 9 android:src="@mipmap/ic_launcher" 10 android:layout_width="60dp" 11 android:layout_height="60dp"/> 12 <TextView 13 android:id="@+id/tv_title" 14 android:layout_width="match_parent" 15 android:layout_height="30dp" 16 android:layout_toEndOf="@id/iv_image" 17 android:text="Title" 18 android:gravity="center" 19 android:textSize="25sp"/> 20 21 <TextView 22 android:id="@+id/tv_content" 23 android:layout_width="match_parent" 24 android:layout_height="wrap_content" 25 android:layout_toEndOf="@id/iv_image" 26 android:layout_below="@id/tv_title" 27 android:text="Content" 28 android:gravity="center" 29 android:textSize="20sp"/> 30 31 </RelativeLayout>
ItemBean.java(数据源)
1 public class ItemBean { 2 3 public int itemImageResId; //图像资源ID 4 public String itemTitle; //标题 5 public String itemContent; //内容 6 7 public ItemBean(int itemImageResId, String itemTitle, String itemContent) { 8 this.itemImageResId = itemImageResId; 9 this.itemTitle = itemTitle; 10 this.itemContent = itemContent; 11 } 12 13 }
MainActivity.java
1 public class MainActivity extends Activity { 2 3 ListView mListView ; 4 @Override 5 protected void onCreate(Bundle savedInstanceState) { 6 super.onCreate(savedInstanceState); 7 setContentView(R.layout.activity_main); 8 9 List<ItemBean> itemBeanList = new ArrayList<>(); 10 for (int i = 0;i < 20; i ++){ 11 itemBeanList.add(new ItemBean(R.mipmap.ic_launcher, "标题" + i, "内容" + i)); 12 } 13 mListView = (ListView) findViewById(R.id.lv_main); 14 //设置ListView的数据适配器 15 mListView.setAdapter(new MyAdapter(this,itemBeanList)); 16 } 17 18 }
MyAdapter.java
此方式不仅利用了ListView的缓存机制,而且使用ViewHolder类来实现显示数据视图的缓存,避免多次调用findViewById来寻找控件,以达到优化程序的目的。
所以,大家在平时的开发中应当尽量使用这种方式进行getView的实现。
1 public class MyAdapter extends BaseAdapter { 2 3 private List<ItemBean> mList;//数据源 4 private LayoutInflater mInflater;//布局装载器对象 5 6 // 通过构造方法将数据源与数据适配器关联起来 7 // context:要使用当前的Adapter的界面对象 8 public MyAdapter(Context context, List<ItemBean> list) { 9 mList = list; 10 mInflater = LayoutInflater.from(context); 11 } 12 13 @Override 14 //ListView需要显示的数据数量 15 public int getCount() { 16 return mList.size(); 17 } 18 19 @Override 20 //指定的索引对应的数据项 21 public Object getItem(int position) { 22 return mList.get(position); 23 } 24 25 @Override 26 //指定的索引对应的数据项ID 27 public long getItemId(int position) { 28 return position; 29 } 30 31 @Override 32 //返回每一项的显示内容 33 public View getView(int position, View convertView, ViewGroup parent) { 34 ViewHolder viewHolder; 35 //如果view未被实例化过,缓存池中没有对应的缓存 36 if (convertView == null) { 37 viewHolder = new ViewHolder(); 38 // 由于我们只需要将XML转化为View,并不涉及到具体的布局,所以第二个参数通常设置为null 39 convertView = mInflater.inflate(R.layout.item_lv, null); 40 41 //对viewHolder的属性进行赋值 42 viewHolder.imageView = (ImageView) convertView.findViewById(R.id.iv_image); 43 viewHolder.title = (TextView) convertView.findViewById(R.id.tv_title); 44 viewHolder.content = (TextView) convertView.findViewById(R.id.tv_content); 45 46 //通过setTag将convertView与viewHolder关联 47 convertView.setTag(viewHolder); 48 }else{//如果缓存池中有对应的view缓存,则直接通过getTag取出viewHolder 49 viewHolder = (ViewHolder) convertView.getTag(); 50 } 51 // 取出bean对象 52 ItemBean bean = mList.get(position); 53 54 // 设置控件的数据 55 viewHolder.imageView.setImageResource(bean.itemImageResId); 56 viewHolder.title.setText(bean.itemTitle); 57 viewHolder.content.setText(bean.itemContent); 58 59 return convertView; 60 } 61 // ViewHolder用于缓存控件,三个属性分别对应item布局文件的三个控件 62 class ViewHolder{ 63 public ImageView imageView; 64 public TextView title; 65 public TextView content; 66 } 67 68 }
ViewHolder优化BaseAdapter的整体步骤:
- 创建bean对象,用于封装数据。
- 在构造方法中初始化的数据List。
- 创建ViewHolder类,创建布局映射关系。
- 判断convertView,为空则创建,并设置tag,不为空则通过tag取出ViewHolder。
- 给ViewHolder的控件设置数据。