声明:刚开始学习Android技术,笔记中可能会有一些错误,如有发现请下方评论指出
Adapter应该是安卓中比较重要的一个知识点,官方文档说Adapter扮演一个在AdapterView即视图和底层数据之间桥梁,Adapter提供对每个数据项的访问,并且为数据集建立视图访问。简单来说就是适配器Adapter给我们的界面提供数据,给用户看。主要有三种Adapter:(可以把Adapter翻译为适配器)
- BaseAdapter
- ArrayAdapter
- CurosrAdapter
- SimpleCursorAdapter
一. ArrayAdapter的使用
ArrayAdapter使用相对简单,但是功能也很局限,基本上只能显示一行的文本,基本使用如下:
- 布局文件:activity_main.xml
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
- Java文件:MainActivity.java
public class MainActivity extends AppCompatActivity {
private ListView mListView;
private String[] dateTest={"vivo","xiaomi","oppo","huawei","vivo","xiaomi","oppo","huawei"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) findViewById(R.id.list_view);
ArrayAdapter<String> myAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,dateTest);
mListView.setAdapter(myAdapter);
mListView.setOnItemClickListener(mMessageOnclick);
}
private AdapterView.OnItemClickListener mMessageOnclick = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
Toast.makeText(MainActivity.this,"click"+position,Toast.LENGTH_SHORT).show();
}
};
}
-
ArrayAdapter myAdapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,dateTest);参数说明
- 第一个参数:Context上下文
- 第二个参数:每一个Item的样式,Android Studio会提示使用,有很多种;也可以直接使用R.layout.diy_item.xml自定义item布局
- 第三个参数:数据源,是一个数组或者集合数组
-
最终结果如下:
二. SimpleAdapter
这个适配器使用起来还是比较方便的,使用方法没有BaseAdapter那么复杂,但是却可以很方便地实现一些复杂地Item,下面是一个使用方法:
-
activity_main.xml中添加ListView
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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:orientation="vertical" tools:context=".MainActivity"> <ListView android:id="@+id/list_view" android:layout_width="match_parent" android:layout_height="match_parent"> </ListView> </LinearLayout>
-
创建一个布局my_item_view,用来显示一个稍复杂的列表项;其实就是应用商店一个应用的下载列表布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="80dp">
<ImageView
android:id="@+id/app_img"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_gravity="center"
android:src="@drawable/wangzhe"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="0dp"
android:layout_weight="3"
android:layout_height="match_parent">
<TextView
android:id="@+id/app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/title_app_name"
android:layout_margin="5dp"
android:textSize="20sp"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/app_kind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="5dp"
android:text="Social"/>
<TextView
android:id="@+id/app_volume"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="5dp"
android:text="100MB"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/app_score"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="5dp"
android:text="4.6分"
android:textColor="@color/colorScore"
/>
<TextView
android:id="@+id/app_download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="5dp"
android:text="106Million"/>
</LinearLayout>
</LinearLayout>
<Button
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="40dp"
android:layout_gravity="center"
android:text="@string/title_button"
android:layout_marginHorizontal="10dp"/>
</LinearLayout>
-
在MainActivity.java中给列表添加适配器,装载数据;数据先使用的假数据
public class MainActivity extends AppCompatActivity { private List<Map<String,Object>> mDataTest; private ListView mListView; private SimpleAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mListView = (ListView) findViewById(R.id.list_view); initDate(); mAdapter = new SimpleAdapter(MainActivity.this,mDataTest,R.layout.item_list, new String[]{"gameName","gameVolume","gameImg"},new int[]{R.id.app_name,R.id.app_volume,R.id.app_img}); mListView.setAdapter(mAdapter); } private void initDate(){ //这里先只添加这三个值,实际中这些值都是要从服务器获取 String[] gameName = {"王者荣耀","绝地求生","穿越火线"}; String[] gameVolume = {"1432MB","1230MB","1110MB"}; int[] gameImg ={R.drawable.wangzhe,R.drawable.chiji,R.drawable.chuanyue}; mDataTest = new ArrayList<>(); for(int i = 0;i<gameName.length;i++){ Map<String,Object> map = new HashMap<>(); map.put("gameName",gameName[i]); map.put("gameVolume",gameVolume[i]); map.put("gameImg",gameImg[i]); mDataTest.add(map); } } }
-
这里的重点是SimpleAdapter的5个参数,比ArrayAdapter参数复杂,功能也更加强大
- 第一个参数:上下文Context
- 第二个参数:一个包含Map类型的List集合,就是我们需要显示出来的数据,以键值对的形式给出
- 第三个参数:列表项Item的布局
- 第四个参数:数据来源,String数组中的每一个元素与第二个参数中的Map类型的key相对应
- 第五个参数:数据去向,int数组中为item布局中每一个组件的id,就是第三个布局文件中的id。是将第四个参数中的数据填充到对应的显示组件中
第二个第四个第五个参数其实都是对应的。只要将数据处理成相应的格式,使用SimpleAdapter还是很方便的
-
最终结果如下:
三. BaseAdapter
BaseAdapter是适配器通用的基类,使用相对复杂,功能也更加强大;使用的思想其实是差不多的,但是可能面对大量数据性能会不同吧。
-
activity.xml和列表项item的布局与第二个SimpleAdapter相同
-
新建一个数据结构的类AppMessage用来存放我们的数据
public class AppMessage { private int imgId; private String appName; private String appVolume; private String appScore; private String appDownload; public AppMessage(int imgId, String appName, String appVolume, String appScore, String appDownload) { this.imgId = imgId; this.appName = appName; this.appVolume = appVolume; this.appScore = appScore; this.appDownload = appDownload; } public int getImgId() { return imgId; } public String getAppName() { return appName; } public String getAppVolume() { return appVolume; } public String getAppScore() { return appScore; } public String getAppDownload() { return appDownload; } }
-
新建一个MyAdapter类继承自BaseAdapter
public class MyAdapter extends BaseAdapter { private List<AppMessage> mData; private Context mContext; //构造函数初始化数据和上下文 public MyAdapter(List<AppMessage> data, Context context) { this.mData = data; this.mContext = context; } //列表项的数量 @Override public int getCount() { return mData.size(); } //获取某一个列表项 @Override public Object getItem(int i) { return mData.get(i); } //获取列表项位置 @Override public long getItemId(int i) { return i; } //设置列表项的的布局,并且插入相应数据 @Override public View getView(int i, View view, ViewGroup viewGroup) { view = LayoutInflater.from(mContext).inflate(R.layout.item_list, viewGroup, false); ImageView appImg = (ImageView) view.findViewById(R.id.app_img); TextView appVolume = (TextView) view.findViewById(R.id.app_volume); TextView appName = (TextView) view.findViewById(R.id.app_name); TextView appScore = (TextView) view.findViewById(R.id.app_score); TextView appDownload = (TextView) view.findViewById(R.id.app_download); appImg.setImageResource(mData.get(i).getImgId()); appDownload.setText(mData.get(i).getAppDownload()); appName.setText(mData.get(i).getAppName()); appScore.setText(mData.get(i).getAppScore()); appVolume.setText(mData.get(i).getAppVolume()); return view; } }
这个适配器需要重写4个函数,几个函数的作用显而易见,除此之外需要创建一个构造函数来初始化数据结构和上下文context,主要部分是getView()函数,获取到我们的列表项视图,然后将数据填充到其中,但是上面这种做法Google官方是不推荐的,会有如下提示:
官方推荐我们使用ViewHolder,应该是处于效率的考虑。可以看到上述代码中的getView()函数的执行次数应该是数据项的个数,那么当数据量大时每加载一个数据项就要创建一次view视图,就要执行多次findViewById,这样效率的相对较低的,所以可以使用另一种写法。实现出来的效果如下:
更优写法
public class MyAdapter extends BaseAdapter { private List<AppMessage> mData; private Context mContext; //构造函数初始化数据和上下文 MyAdapter(List<AppMessage> data, Context context) { this.mData = data; this.mContext = context; } //列表项的数量 @Override public int getCount() { return mData.size(); } //获取某一个列表项 @Override public Object getItem(int i) { return mData.get(i); } //获取列表项位置 @Override public long getItemId(int i) { return i; } //第二种相对高效的写法,不用每次都创建View对象和findViewById @Override public View getView(int i, View view, ViewGroup viewGroup) { ViewHolder viewHolder; if (view == null) { //如果没有view视图,则创建一个 viewHolder = new ViewHolder(); view = LayoutInflater.from(mContext).inflate(R.layout.item_list, viewGroup, false); viewHolder.appImg = (ImageView) view.findViewById(R.id.app_img); viewHolder.appVolume = (TextView) view.findViewById(R.id.app_volume); viewHolder.appName = (TextView) view.findViewById(R.id.app_name); viewHolder.appScore = (TextView) view.findViewById(R.id.app_score); viewHolder.appDownload = (TextView) view.findViewById(R.id.app_download); view.setTag(viewHolder); //设置与view视图关联的标记 } else { //除第一个item后其他的都是else,只需要获取之前标记的viewHolder就行 viewHolder = (ViewHolder) view.getTag(); } viewHolder.appImg.setImageResource(mData.get(i).getImgId()); viewHolder.appDownload.setText(mData.get(i).getAppDownload()); viewHolder.appName.setText(mData.get(i).getAppName()); viewHolder.appScore.setText(mData.get(i).getAppScore()); viewHolder.appVolume.setText(mData.get(i).getAppVolume()); return view; } private class ViewHolder { private ImageView appImg; private TextView appVolume; private TextView appName; private TextView appScore; private TextView appDownload; } }
这种写法if中的代码只需要执行一次,会提升一定的效率。
除以上之外还有recycleView实现滑动列表,它的适配器需要继承RecycleView.Adapter回头整理