Android ListView – Holder模式和getItemViewType

简介:

Mobile开发:Android-ListView中介绍了在Android中如何使用ListView,以及为数据模型自定义Item的UI. 这一篇要将两个方面的内容:Holder模式和getItemViewType的应用。

Holder模式

模式这个词语是通过GOF的《设计模式》这本书而引入软件设计领域的。在软件设计领域里面,模式是指为解决特定问题而存在的通用解决方案。这个特定的问题如果在软件设计领域广泛存在,那么该解决方案就有记录和传播的价值。

Holder模式要解决的是性能问题:

场景:在我们的Adapter中每次都要从row中通过findViewById来找到子控件,然后设置值。如果row的布局比较复杂,或者row的数目特别多。这个查找就要不断发生。从而导致性能问题。

方案:在row第一次被构建出来的时候,调用findViewById, 通过Holder对象存储起来,然后把Holder对象通过row.setTag方法,直接缓存在row上。这样下次就不用在查找了。

看看下面的代码:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    try {
        Restaurant item = this.getItem(position);
        View row = convertView;
        RestaurantListViewItemHolder holder=null;
        if (row == null) {
            LayoutInflater inflater = LayoutInflater
                    .from(this.getContext());
            if(!item.isGoldenBrand())
            row = inflater
                    .inflate(R.layout.restaurant_list_view_item, null);
            else row=inflater.inflate(R.layout.restaurant_list_view_item_golden, null);
 
            holder = createRestaurantListViewItemHolder(row,item.isGoldenBrand());
            row.setTag(holder);
        }else{
            holder=(RestaurantListViewItemHolder)row.getTag();
        }       
 
        holder.UpdateUI(item);
        return row;
    } catch (Exception e) {
        Log.e(LogTags.RestaurantListAdapter, e.getLocalizedMessage(), e);
    }
    return super.getView(position, convertView, parent);
}
 
/**
 * Create a holder for a row in list,when the row is first loaded.
 * @param row
 * @return
 */
private RestaurantListViewItemHolder createRestaurantListViewItemHolder(
        View row,boolean isGoldenBrand) {
    TextView txtName = (TextView) row
            .findViewById(R.id.restaurant_name);
    TextView txtPhoneNR = (TextView) row
            .findViewById(R.id.restaurant_phone_nr);
    TextView txtLocation = (TextView) row
            .findViewById(R.id.restaurant_address);
    ImageView imgIcon=(ImageView) row.findViewById(R.id.restaurent_icon);
    TextView txtDescription=null;
    if(isGoldenBrand)
        txtDescription=(TextView)row.findViewById(R.id.restaurant_description_direct);
    return new RestaurantListViewItemHolder(txtPhoneNR,txtName,txtLocation,
            imgIcon,txtDescription);
}

上面的代码由于混合了和getItemViewType有关的内容。所以看起来有点和上篇中不同。其主要代码在第15,16,18,21行。

  • 第15行:通过调用createRestaurantListViewItemHolder来构造一个Holder对象。
  • 第16行:调用row.setTag将Holder关联到row对象上。
  • 第18行:如果row对象不是新构建的,直接获取row上的Tag,这个Tag对象就是我们在第16行存储的RestaurantListViewItemHolder对象。
  • 第21行:调用holder.UpdateUI来更新UI。

上面的代码中已经用到了RestaurantListViewItemHolder,下面是代码文件。逻辑非常的简单。

package net.lxzhu.mobile;
 
import android.widget.ImageView;
import android.widget.TextView;
 
public class RestaurantListViewItemHolder {
    private TextView phoneNumberUI;
    private TextView nameUI;
    private TextView addressUI;
    private ImageView iconUI;
    private TextView descriptionUI;
 
    public RestaurantListViewItemHolder(TextView phoneNumberUI,
            TextView nameUI, TextView addressUI, ImageView iconUI,TextView descriptionUI) {
        this.phoneNumberUI=phoneNumberUI;
        this.nameUI=nameUI;
        this.addressUI=addressUI;
        this.iconUI=iconUI;
        this.descriptionUI=descriptionUI;
    }
 
    public void UpdateUI(Restaurant data){
        this.phoneNumberUI.setText(data.getPhoneNR());
        this.nameUI.setText(data.getName());
        this.addressUI.setText(data.getAddress());
        this.iconUI.setImageResource(R.drawable.ic_launcher);
        if(this.descriptionUI!=null)
            this.descriptionUI.setText(data.getDescription());
    }
}

getItemViewType

假设我们的UI设计有这样一个需求。如果一家餐馆被评为金牌场馆,那么它可以直接将最近的一条点评显示在列表中,这样用户不用选中或者点击就可以看到评价了。

这就是为什么我们上面的代码中出现了isGoldenBrand这样的代码。到目前为止,我们的ListView中的每个Item都是一样的。而这个需求却让我们根据数据的不同出现了不同的布局。AdapterView已经提供了支持,我们只需要:

  1. 重写getViewTypeCount方法,返回可能出现的布局的数目。
  2. 重写getItemViewType方法,这个方法返回0到getViewTypeCount()-1之间的数字或者IGNORE_ITEM_VIEW_TYPE. 这个方法返回的id必须要和getView方法中返回的View匹配:在getView中返回相同类型View的position, getItemViewType应该返回同一个id.
  3. 在getView中根据数据不同,返回不同的View。

下面是getViewTypeCount和getItemViewType的代码,getView的代码前面已经给出,这里就不在重复了。


@Override
public int getViewTypeCount() {
    return 2;
}
 
@Override
public int getItemViewType(int position) {
    Restaurant data=this.getItem(position);
    if(!data.isGoldenBrand())
        return 0;
    else return 1;
}

其实我们这里的需求不使用这种模式也可以开发出来。但是如果需求中对金牌餐馆的布局和普通餐馆布局有很大的不同的话。这个功能就非常实用了。下面是修改后的代码的执行结果。

image



相关文章
|
1天前
|
Android开发
Android Mediatek 增加Recovery模式下读cmdline的强制工厂重置选项
Android Mediatek 增加Recovery模式下读cmdline的强制工厂重置选项
21 0
|
1天前
|
API Android开发 开发者
Android UI设计: 什么是RecyclerView?为什么它比ListView更好?
Android UI设计: 什么是RecyclerView?为什么它比ListView更好?
33 2
|
1天前
|
XML 前端开发 测试技术
Android基础知识:解释Android的MVC和MVP模式。
Android基础知识:解释Android的MVC和MVP模式。
35 0
|
9月前
|
测试技术 Android开发 虚拟化
踩坑记录 | Android 逆向之如何处理 Kali Nat 模式无法上网?
踩坑记录 | Android 逆向之如何处理 Kali Nat 模式无法上网?
213 0
|
1天前
|
XML Java Android开发
如何美化android程序:自定义ListView背景
如何美化android程序:自定义ListView背景
|
1天前
|
设计模式 前端开发 数据库
构建高效Android应用:使用Jetpack架构组件实现MVVM模式
【4月更文挑战第21天】 在移动开发领域,构建一个既健壮又易于维护的Android应用是每个开发者的目标。随着项目复杂度的增加,传统的MVP或MVC架构往往难以应对快速变化的市场需求和复杂的业务逻辑。本文将探讨如何利用Android Jetpack中的架构组件来实施MVVM(Model-View-ViewModel)设计模式,旨在提供一个更加模块化、可测试且易于管理的代码结构。通过具体案例分析,我们将展示如何使用LiveData, ViewModel, 和Repository来实现界面与业务逻辑的分离,以及如何利用Room数据库进行持久化存储。最终,你将获得一个响应迅速、可扩展且符合现代软件工
26 0
|
1天前
|
XML Java Android开发
Android Studio App入门之列表视图ListView的讲解及实战(附源码 超详细必看)
Android Studio App入门之列表视图ListView的讲解及实战(附源码 超详细必看)
101 0
|
1天前
|
传感器 小程序 Java
Java+saas模式 智慧校园系统源码Java Android +MySQL+ IDEA 多校运营数字化校园云平台源码
Java+saas模式 智慧校园系统源码Java Android +MySQL+ IDEA 多校运营数字化校园云平台源码 智慧校园即智慧化的校园,也指按智慧化标准进行的校园建设,按标准《智慧校园总体框架》中对智慧校园的标准定义是:物理空间和信息空间的有机衔接,使任何人、任何时间、任何地点都能便捷的获取资源和服务。
21 1
|
1天前
|
XML 编解码 Java
Android控件之高级控件——ListView、cardView、屏幕适配
Android控件之高级控件——ListView、cardView、屏幕适配
|
1天前
|
XML 数据库 数据安全/隐私保护
Android App规范处理中版本设置、发布模式、给数据集SQLite加密的讲解及使用(附源码 超详细必看)
Android App规范处理中版本设置、发布模式、给数据集SQLite加密的讲解及使用(附源码 超详细必看)
45 0