•前行必备——ListView的显示与缓存机制

  我们知道 ListView、GridView 等控件可以展示大量的数据信息。

  假如下图中的 ListView 可以展示 100 条信息,但是屏幕的尺寸是有限的,只能显示下图中的 7 条。

  当向上滑动 ListView 的时候,item1 被滑出了屏幕区域,那么系统就会将item1回收到Recycler中,即View缓冲池中;

  而将要显示的 item8 则会从缓存池中取出布局文件,并重新设置好 item8 需要显示的数据,并放入需要显示的位置。

  这就是ListView的缓冲机制,总结起来就是一句话:需要时才显示,显示完就被会收到缓存。

  ListView,GridView 等数据显示控件通过这种缓存机制可以极大的节省系统资源。

  示意图如下:

    

•步入主提——BaseAdapter

  使用 BaseAdapter 比较简单,主要是通过继承此类来实现 BaseAdapter 的四个方法:

  • public int getCount() : 适配器中数据集的数据个数;
  • public Object getItem(int position) : 获取数据集中与索引对应的数据项;
  • public long getItemId(int position) : 获取指定行对应的ID;
  • public View getView(int position,View convertView,ViewGroup parent) : 获取每一行 Item 的显示内容。

  下面通过一个简单示例演示如何使用BaseAdapter。

准备工作

  新建一个项目,选择 Empty Activity 选项;

  Android Studio 会自动为我们生成两个文件 MainActivity.java 和 activity_main.xml;

activity_main.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent">
  5.  
  6. <ListView
  7. android:id="@+id/lv_base_adapter"
  8. android:layout_width="match_parent"
  9. android:layout_height="match_parent"
  10. />
  11.  
  12. </RelativeLayout>

  在 res/layout 新建一个 base_adapter_item.xml 文件;

base_adapter_item.xml

  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:padding="10dp"
  6. android:orientation="horizontal">
  7.  
  8. <ImageView
  9. android:id="@+id/header"
  10. android:layout_width="wrap_content"
  11. android:layout_height="wrap_content"
  12. android:scaleType="centerCrop"
  13. />
  14. <LinearLayout
  15. android:layout_width="match_parent"
  16. android:layout_height="160dp"
  17. android:orientation="vertical"
  18. android:layout_marginLeft="10dp">
  19.  
  20. <TextView
  21. android:id="@+id/name"
  22. android:layout_width="match_parent"
  23. android:layout_height="wrap_content"
  24. android:textSize="20sp"
  25. android:gravity="left"/>
  26. <TextView
  27. android:id="@+id/desc"
  28. android:layout_width="match_parent"
  29. android:layout_height="wrap_content"
  30. android:textSize="13sp"
  31. android:gravity="left"/>
  32. </LinearLayout>
  33. </LinearLayout>

页面布局说明

  1. 整体采用线性布局,并以水平排列。
  2. 左边第一项定义一个ImageView组件,用来显示图片。
  3. 右边嵌套一个线性布局,并以垂直排列。
  4. 嵌套的线性布局里面定义了两个TextView,一个显示名字,一个显示介绍。

  base_adapter_item布局示意图如下:

    

  新建 Fruit 类;

Fruit.java

  1. public class Fruit {
  2. private String name;//名称
  3. private String desc;//描述
  4. private int imgId;//对应图片id
  5.  
  6. public Fruit(String name,String desc,int imgId){
  7. this.name = name;
  8. this.desc = desc;
  9. this.imgId = imgId;
  10. }
  11.  
  12. public String getDesc() {
  13. return desc;
  14. }
  15.  
  16. public String getName() {
  17. return name;
  18. }
  19.  
  20. public int getImgId() {
  21. return imgId;
  22. }
  23. }

  通过此 Fruit类,我们就将要显示的数据与 ListView 的布局内容(base_adapter_item)一一对应了;

  每个 Fruit 对象对应 ListView 的一条数据,这种方法在 ListView 中使用的非常广泛。

  接下来需要创建一个自定义的适配器,这个适配器继承自 BaseAdapter,并将 List 的泛型指定为 Fruit 类。

  新建 MyBaseAdapter 类;

MyBaseAdapter.java

  1. public class MyBaseAdapter extends BaseAdapter {
  2.  
  3. private List<Fruit> list;//数据源
  4. private Context context;//调用 MyBaseAdapter 的上下文对象
  5.  
  6. //通过构造方法将数据源与数据适配器关联起来
  7. public MyBaseAdapter(Context context,List<Fruit>list){
  8. this.context = context;
  9. this.list = list;
  10. }
  11. @Override
  12. //ListView需要显示的数据数量
  13. public int getCount() {
  14. return list.size();
  15. }
  16.  
  17. @Override
  18. //指定的索引对应的数据项
  19. public Object getItem(int position) {
  20. return list.get(position);
  21. }
  22.  
  23. @Override
  24. public long getItemId(int position) {
  25. return position;
  26. }
  27.  
  28. static class ViewHolder{
  29. private ImageView imgView;
  30. private TextView name;
  31. private TextView desc;
  32. }
  33. @Override
  34. //返回每一项的显示内容
  35. public View getView(int position, View convertView, ViewGroup parent) {
  36.  
  37. View view;
  38. ViewHolder holder;
  39.  
  40. if(convertView == null){
  41. //由于我们只需要将 fruit.XML 转化为 View,并不涉及到具体的布局
  42. // 所以第二个参数通常设置为null
  43. view = LayoutInflater.from(context).inflate(R.layout.base_adapter_item, null);
  44. holder = new ViewHolder();
  45. holder.imgView = view.findViewById(R.id.header);
  46. holder.name = view.findViewById(R.id.name);
  47. holder.desc = view.findViewById(R.id.desc);
  48.  
  49. view.setTag(holder);
  50. }else{
  51. view = convertView;
  52. holder = (ViewHolder) view.getTag();
  53. }
  54.  
  55. //获取第 position 项的数据
  56. Fruit fruit = list.get(position);
  57. holder.imgView.setImageResource(fruit.getImgId());
  58. holder.name.setText(fruit.getName());
  59. holder.desc.setText(fruit.getDesc());
  60.  
  61. return view;
  62. }
  63. }

MyBaseAdapter代码分析

  listView在开始绘制的时候,系统首先调用  getCount() 函数,根据他的返回值得到 ListView 的长度。

  然后根据这个长度,调用  getView()  逐一绘制每一行,如果你的  getCount() 返回值是 0 的话,列表将不显示,同样 return 1,就只显示一行。

  系统显示列表时,首先实例化一个适配器(这里将实例化自定义的适配器),当手动完成适配时,必须手动映射数据,这需要重写  getView()  方法。

  系统在绘制列表的每一行的时候将调用此方法。

   getView() 有三个参数:

  • position表示将显示的是第几行
  • covertView是从布局文件中 inflate 来的布局

  我们用LayoutInflater的方法将定义好的  base_adapter_item 文件提取成 View 实例用来显示。

  通过 view.findViewById()  找到布局文件中的控件;

  实例化 Fruit 类,通过 set 方法将数据对应到各个组件上;

  至此一个自定义的 listView 就完成了,现在让我们回过头从新审视这个过程。

  系统要绘制 ListView,他首先获得要绘制的这个列表的长度,然后开始绘制第一行,怎么绘制呢?

  调用 getView() 函数,在这个函数里面首先获得一个View(实际上是一个ViewGroup),然后再实例并设置各个组件,显示之。

  好了,绘制完这一行了,那再绘制下一行,直到绘完为止。

   PS : 有关 ViewHolder 的使用,参考我的这篇博客——提升ListView的运行效率。

  接下来,也是最后一步,修改 MainActivity.java 中的代码;

MainActivity.java

  1. public class TestBaseAdapterActivity extends AppCompatActivity {
  2.  
  3. private ListView mLv;
  4. private MyBaseAdapter adapter;
  5. @Override
  6. protected void onCreate(Bundle savedInstanceState) {
  7. super.onCreate(savedInstanceState);
  8. setContentView(R.layout.activity_test_base_adapter);
  9.  
  10. mLv = findViewById(R.id.lv_base_adapter);
  11. adapter = new MyBaseAdapter(TestBaseAdapterActivity.this,getData());
  12. mLv.setAdapter(adapter);
  13. }
  14.  
  15. private List<Fruit> getData(){
  16. List<Fruit> list = new ArrayList<>();
  17.  
  18. //String name,String desc,int imgId
  19. list.add(new Fruit("apple","苹果",R.drawable.apple));
  20. list.add(new Fruit("banana","香蕉", R.drawable.banana));
  21. list.add(new Fruit("oranges","橘子",R.drawable.oranges));
  22.  
  23. return list;
  24. }
  25. }

  apple,banana,oranges 是我从网上下载的图片,放置在了 drawable 文件夹下:

        

•运行结果

  

Android Studio 之 BaseAdapter 学习笔记的更多相关文章

  1. Android Studio调试方法学习笔记

    (注:本人所用Android Studio的Keymap已设为Eclipse copy) 1.设置断点 只有设置断点,才好定位要调试什么地方,否则找不到要调试的地方,无法调试.(调试过程中也可以增加断 ...

  2. Android Studio 之 ImageView 学习笔记

    •参考资料 [1]:菜鸟教程 [2]:bilibili视频教程 •src和blackground的区别 background通常指的都是背景,而src指的是内容 当使用 src 填入图片时,是按照图片 ...

  3. Android(java)学习笔记206:利用开源SmartImageView优化网易新闻RSS客户端

    1.我们自己编写的SmartImageView会有很多漏洞,但是我们幸运的可以在网上利用开源项目的,开源项目中有很多成熟的代码,比如SmartImageView都编写的很成熟的 国内我们经常用到htt ...

  4. Android(java)学习笔记205:网易新闻RSS客户端应用编写逻辑过程

    1.我们的项目需求是编写一个新闻RSS浏览器,RSS(Really Simple Syndication)是一种描述和同步网站内容的格式,是使用最广泛的XML应用.RSS目前广泛用于网上新闻频道,bl ...

  5. Android(java)学习笔记149:利用开源SmartImageView优化网易新闻RSS客户端

    1.我们自己编写的SmartImageView会有很多漏洞,但是我们幸运的可以在网上利用开源项目的,开源项目中有很多成熟的代码,比如SmartImageView都编写的很成熟的 国内我们经常用到htt ...

  6. Android(java)学习笔记148:网易新闻RSS客户端应用编写逻辑过程

    1.我们的项目需求是编写一个新闻RSS浏览器,RSS(Really Simple Syndication)是一种描述和同步网站内容的格式,是使用最广泛的XML应用.RSS目前广泛用于网上新闻频道,bl ...

  7. Android自动化测试之Monkeyrunner学习笔记(一)

    Android自动化测试之Monkeyrunner学习笔记(一) 因项目需要,开始研究Android自动化测试方法,对其中的一些工具.方法和框架做了一些简单的整理,其中包括Monkey.Monkeyr ...

  8. Android(java)学习笔记267:Android线程池形态

    1. 线程池简介  多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力.     假设一个服务器完成一项任务所需时间为:T1 创建线程时间, ...

  9. Android(java)学习笔记207:开源项目使用之gif view

    1. 由于android没有自带的gif动画,我在Android(java)学习笔记198:Android下的帧动画(Drawable Animation) 播客中提到可以使用AnimationVie ...

随机推荐

  1. React & Special Props Warning

    React & Special Props Warning key & ref demo index.js:1 Warning: Comment: key is not a prop. ...

  2. Xcode 切换 iOS 模拟器的 Dark 模式

    Xcode 切换 iOS 模拟器的 Dark 模式 SwiftUI // // ContentView.swift // MemorizeGame // // Created by 夏凌晨 on 20 ...

  3. free online linux terminal & github cli online

    free online linux terminal & github cli online gitpod https://www.gitpod.io/features/ https://bc ...

  4. 抓手 & 技术管理

    抓手 & 技术管理 https://zhuanlan.zhihu.com/p/28891618 技术管理的目的 管理就是通过别人拿到结果.而管理的两个着眼点就是:成事.育人. 把事情搞定,把人 ...

  5. website 性能检测 & 前端性能优化

    website 性能检测 & 前端性能优化 https://cdn.xgqfrms.xyz/ https://mobile.xgqfrms.xyz/ PageSpeed Insights ht ...

  6. 口罩 & 防毒面具 N95 & P100

    口罩 & 防毒面具 N95 & P100 N95 口罩 < 防毒面具 P100 https://www.techritual.com/2020/01/30/210599/

  7. Google can't be accessed again, today is shit day

    Google can't be accessed again, today is shit day 2019.11.28 12:00~20:56 holy shit (pile of poop) Go ...

  8. 牛市下SPC新空投糖果来了

    2021年元旦刚过没几天,比特币就开启了牛市的旅程,比特币涨至三万四千美元,率领众多币种暴涨,一股浓浓的牛市味道来了. 虽然从昨天开始,比特币带领着主流币进行了一波调整,但是只涨不跌的市场是 大家说比 ...

  9. NGK以强大的创新能力赋予NGK公链超级实用的特性

    公链从大趋势看是一个不断迭代的过程,不管是共识算法.网络架构.开发者协议都在一代一代不断完善跟创新. NGK公链作为公链赛道上的后起之秀,对于主流公链技术的局限性以及下一代公链技术的发展方向都有非常清 ...

  10. CloudQuery v1.2.1 版本发布

    欢迎来到 CloudQuery v1.2.1 版本发布会. 上次 v1.2.0 版本发布收到广大朋友们的热烈反响,大家提出了很多宝贵建议,揪出了不少 Bug.在此,我们表示由衷感谢.问题和建议我们都会 ...