Android 工人、手机、手机包装盒——解析适配器 BaseAdapter
这一篇博文是建立在慕课网大牛Eclipse xu的基础上的,笔者听了他的课,在此表示感谢。
【如何描述BaseAdapter?】
软件世界中其实我们关注的其实是某个类的作用,而不是它是一个什么。
所谓BaseAdapter,按照笔者目前的理解,其实就是数据源和控件之间的桥梁。
我们首先考虑一个问题。
一个手机包装盒,一个手机,是否可以完成包装的任务呢。
答案是不可以,因为完成包装的既不是手机,也不是手机包装盒自身。而是人。包装工人要有一套包装的规则,手机怎么放,充电线放哪里,这都是规则指定的。
如果一个View是手机包装盒,那么你所想要展示的数据源就是手机,而BaseAdapter所扮演的就是人的角色。
那么ListView呢?ListView可以看作装有很多个手机包装盒的包装箱。
【BaseAdapter使用】
我们用一个小Demo来解析一下。
首先我们来定制一下手机包装盒。
<!--item.xml 手机包装盒的样式-->
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context=".MainActivity"
android:id="@+id/rl_item">
<ImageView
android:id="@+id/iv_image"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@mipmap/ic_launcher"
/>
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_toEndOf="@+id/iv_image"
android:text="Title"
android:gravity="center"
android:textSize="20sp"
/>
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_toEndOf="@+id/iv_image"
android:layout_below="@+id/tv_title"
android:text="Content"
android:gravity="center_vertical"
android:textSize="15sp"
/>
</RelativeLayout>
接下来是activity_main.xml
<!--在这里我们可以清楚地看到一个手机包装盒系列ListView-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"
android:id="@+id/mainLayout">
<ListView
android:id="@+id/lv_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
/>
</RelativeLayout>
下面是手机的代码。
package com.practice.fridge.fridgetest;
import android.widget.ImageView;
/**
* ItemBean就是我们所要的手机
* Created by Fridge on 2015/5/7.
*/
public class ItemBean {
public int ItemImageResId;
public String ItemTitle;
public String ItemContent;
public ItemBean(int itemImageResId, String itemTitle, String itemContent) {
ItemImageResId = itemImageResId;
ItemTitle = itemTitle;
ItemContent = itemContent;
}
}
现在,这个世界看起来并不圆满。
手机ItemBean还没有一个实例。
在手机包装盒item中空有手机的模子,但是并没有实物。
而包装箱ListView中什么都没有。
我们需要一个工人!他可以精准地将100个1000个手机精准地放入到手机包装盒之中。
//MyBaseAdapter.java
package com.practice.fridge.fridgetest;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
import java.util.zip.Inflater;
/**
* Created by Fridge on 2015/5/7.
*/
//我们的工人,底下的四个函数是必须的
public class MyBaseAdapter extends BaseAdapter {
//等待着工人去处理的一系列手机
private List<ItemBean> mItemBeanList;
//通过Inflater,工人可以将一个手机包装盒拿到手
private LayoutInflater mInflater;
public MyBaseAdapter(Context context,List<ItemBean> itemBeans) {
mItemBeanList=itemBeans;
mInflater=LayoutInflater.from(context);
}
@Override
public int getCount() {
return mItemBeanList.size();
}
@Override
public Object getItem(int i) {
return mItemBeanList.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
//最重要的组装过程
@Override
public View getView(int i, View convertView, ViewGroup viewGroup) {
//根据包装盒的id找到手机包装盒
View view=mInflater.inflate(R.layout.item,null);
//看准了包装盒中手机、手机充电器的槽
ImageView imageView = (ImageView) view.findViewById(R.id.iv_image);
TextView title=(TextView) view.findViewById(R.id.tv_title);
TextView content=(TextView) view.findViewById(R.id.tv_content);
//将一个手机、手机充电器拿在手中,一一套进去
ItemBean itemBean=mItemBeanList.get(i);
imageView.setImageResource(itemBean.ItemImageResId);
title.setText(itemBean.ItemTitle);
content.setText(itemBean.ItemContent);
//将手机返回给手机包装箱
return view;
}
}
大功告成!
这时候不要忘记了,我们只是定义了这几个类的指责罢了。
还需要在MainActivity中实例化他们,并且将关系联结好。
package com.practice.fridge.fridgetest;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends Activity {
private List<ItemBean> mItemBeanList;
private MyBaseAdapter mMyBaseAdapter;
protected ListView mListView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mItemBeanList=new ArrayList<>();
for(int i=0;i<20;i++){
ItemBean itemBean=new ItemBean(R.mipmap.ic_launcher,"标题"+i,"内容");
mItemBeanList.add(itemBean);
}
mMyBaseAdapter=new MyBaseAdapter(this,mItemBeanList);
//这个包装箱的负责人就交给这一名工人了
mListView=(ListView) findViewById(R.id.lv_main);
mListView.setAdapter(mMyBaseAdapter);
}
}
【更好的工人】
没有错,我们现在已经拥有了一名可以稳定工作的工人BaseAdapter,但是!不想做程序员的厨师不是好工人。所以我们也许需要对他进行一下调教。
且看这一句:
//根据包装盒的id找到手机包装盒
View view=mInflater.inflate(R.layout.item,null);
这里就好像工人分明一直包装的iPhone手机,但是他每一次得根据包装盒的规格去找这个包装盒。其实这个包装盒对他来说只有一种嘛~干嘛这么费劲!
我们也看到getView的三个参数int position ,view convertView 和viewGroup我们一个也没有用到,这让我们从直觉上觉得不太对。
其实Android中拥有缓存机制,之前的View会缓存。之后会通过convertView这个参数传递进来。
所以,我们应该把上面这行代码这样写。
View view;
if(convertView==null){
view=mInflater.inflate(R.layout.item,null);
}
else{
view=convertView;
}
这样,就可以不用每一次调用getView()这个函数时都去inflate了。
那么,是不是还可以做得更好?
还可以。你也许已经注意到了既然View的Inflate可以只做一次就足够了,那么是不是findViewById也可以只做一次呢?
//新的代码
//新建一个内部类
class ViewHolder{
public ImageView imageView;
public TextView title;
public TextView content;
}
//
public View getView(int i, View convertView, ViewGroup viewGroup) {
View view;
ViewHolder viewHolder;
if(convertView==null){
view=mInflater.inflate(R.layout.item,null);
viewHolder=new ViewHolder();
viewHolder.imageView=(ImageView) view.findViewById(R.id.iv_image);
viewHolder.title=(TextView)view.findViewById(R.id.tv_title);
viewHolder.content=(TextView) view.findViewById(R.id.tv_content);
convertView.setTag(viewHolder);
}
else{
view=convertView;
viewHolder=(ViewHolder) convertView.getTag();
ItemBean itemBean=mItemBeanList.get(i);
viewHolder.imageView.setImageResource(itemBean.ItemImageResId);
viewHolder.title.setText(itemBean.ItemTitle);
viewHolder.content.setText(itemBean.ItemContent);
}
return view;
}
通过convertView.setTag()和getTag()这两个方法,我们可以方便地在第一次inflate这个View的时候将这个View中的子View传递进去。在需要的时候取出。这样的效率要比findViewById()有效得多。尤其是在View很大的时候。
版权声明:本文为博主原创文章,转载请标明出处。