2

Android入门第26天-在Android里自定义Adapter

 1 year ago
source link: https://blog.csdn.net/lifetragedy/article/details/127851339
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Android入门第26天-在Android里自定义Adapter

在上一篇“SimpleAdapter“章节中,我们看到了把:ListView和Listview内部详细页面进行分离的Adapter的设计手法。

可是,这个SimpleAdapter的构造函数不够录活、苦涩难懂。很难满足我们实际大多生产场景的开发。

因此,今天我们就要来看一个更人性化的“自定义BaseAdapter“。实际生产应用场景开发中充斥着自定义BaseAdapter,因此必须要提及它并且围绕着这个extends BaseAdapter我们要持续说不少高级特性。

先来看一下课程最终要实现的目标

6fa06cd59f284ee3b5540609cd0f0b95.png

有喵、有汪、有金钱。还多了表头和表尾。

我们这次就要使用真正的面向业务逻辑、面向对象的手法来实现这个界面。

上述界面其实和上一篇例子相仿,使用到了:1个ImageView、两个TextView。

只不过这次我们用的是标准MVC模式的自定义Adapter。

5694b52b5e824191bc36d9e26fff4f07.png

是不是很详尽?保姆式教程,不详尽不称为“保姆”。

先来看UI端代码

UI端代码

这一块和上一篇几乎相似,没有什么太多变化

activity_main.xml文件

很简单,没有任何神密可言,就一个“光杆”Listview的存在。

customized_layout.xml文件

内容也是very easy,属于“常规损人和”,和上一篇无异。

newCodeMoreWhite.png

PetBean.java

newCodeMoreWhite.png

这个Java Bean里分别就对应着一个ImageView,两个TextView。

始终记得,把Image传递给到Adapter用的是一个int值,它来源于:R.drawable.图片名称(不带.即postfix)。

PetAdapter.java

newCodeMoreWhite.png

代码导读

整个自定义的Adapter是extends自BaseAdapter,这个BaseAdapter在extends后有几个方法需要进行覆盖:

  • 构造函数,构造函数里需要两个参数:
    • 第一个参数,构造函数里把自定义的数据源在上一例里我们用的是List<Map<String,Object>>(不够面向对象),而这边就是List<我们的ViewBean>传进去;
    • Context,如果在MainActivity.java里,我们就可以用这样的形式来传这个参数:Context ctx = MainActivity.this;
  •  public int getCount() ,它返回的就是你的ListView里有多少行的这个size即我们在构造方法里传入的这个List<ViewBean>的size;
  • public Object getItem(int i),这个方法我们在后一步,高级定制化Adapter里会进一步用到,目前在此我们直接return null就完事了,不用作纠结;
  •  public long getItemId(int i),这边的int i其实是position,我们可以这么干:直接return i即可,它其实是一种“一行行从List<ViewBean>取出数据做渲染”用的;
  • public View getView(int i, View view, ViewGroup viewGroup) ,这个函数是核心,它的故事长了,来看一步步导读:
    • 这个方法的作用就是一条条把List<ViewBean>数据取出来作渲染用的,它依赖于这一句话:LayoutInflater.from(ctx).inflate(R.layout.customized_layout, viewGroup, false);这个语句被调用的次数=List.size(),每调用一次这条语句,Android界面会渲染一次(一次开销);
    • 每一个ListView内的行显示的内容根据List<ViewBean>里每一行不同的内容会有不同的显示,在这边的一行指的就是:一个ImageView+两个TextView的渲染。因此你要做的就是一个个“控制件名.set属性(List里取出相应的该行的这个数组的属性件)”,因此才有了如此的写法:name.setText(data.get(i).getName());如:description.setText(data.get(i).getDescription());如:touxiang.setBackgroundResource(data.get(i).getImgId());这样的东西。随便说一句:此处的i带的正是getView里的(int i...)里的这个i,这个i对应着你的List<ViewBean>里当前的“游标”;
    • 全部一个个set完了后,把这个view return出去;
    • 接着我们来说,这块代码看似没逻辑那为什么会有:View Holder这是一个什么鬼?前面我们提到了一句:LayoutInflater.from(ctx).inflate(R.layout.customized_layout, viewGroup, false);这个语句被调用的次数=List.size(),每调用一次这条语句,Android界面会渲染一次,这个动作其实是很开销资源的。比如说我的List<ViewBean>里有100条数据,Android会界面渲染100次。其实这个渲染只是一个“一次性”的事,在这边只要渲染一次就够了,其余99次是多余重复的。渲染太多会造成这个Android极其吃手机的“运存”。所以我们使用了一个小技巧:只在这个View为空时做一次渲染。渲染过后就不要再渲染了,直接填充界面控件内的属性值就行了。因此才有了第一个if (view == null) {的判断。
    • 那么ViewHolder呢?还是没有解释ViewHolder的作用。我们前面解决了这个LayoutInflater.from(ctx).inflate的重复调用问题,但是读者们知道吗?你在getView方法里的findViewById(R.id.description)这样的东西也是会每次被重复调用一次的,举例来说:你有3个控件,在List<ViewBean>里有3行数据,你以为你只调用了3次findViewById?其实是调用了总计3*3=9次,即调用第二个控件的findViewById时它依旧会重复调用第一个控件的findViewById。这个动作也是开销Android的运存和cpu的。那么我们同样为了减少findViewById的重复调用,因此我们使用一个MyViewHolder,让其和我们的ViewBean(此处就是PetBean)一样的结构,它专门是用于保存已经被调用过findViewById的状态(TAG)。然后使用view.setTag和view.getTag来做状态保留。如果这个Tag存在那么不用再findViewById一次了。如果不存在再findViewById一次

接着我们就来看交程序交互后端代码MainActivity.java

MainActivity.java

newCodeMoreWhite.png

我们这次为我们的ListView增加了一个表头,一个表尾。表头表尾分别对应着两个layout xml文件,它们位于我们项目的res\layout目录下。

注:

记得在调用addHeaderView和addFootView的动作必须位于setAdapter(adapter)语句前;

表头样式-view_header.xml

newCodeMoreWhite.png

表尾样式-view_footer.xml

newCodeMoreWhite.png
39c7d0c8e9814aa9b18adbaf94a01606.png

自己动一下手试试就能找到自定义Adapter的感觉。自定义Adapter的作用很大、使用场景也很多。我们后面会继续强化自定义Adapter的业务场景的使用。 


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK