一句话说透Android里面的适配器模式

276 阅读2分钟

一句话总结:
适配器模式就像「电源转接头」—— 把不匹配的数据接口转换成 View 能理解的格式,Android 里 RecyclerView、ListView 都靠它变身数据展示大师!


一、适配器模式在 Android 的日常

核心作用:把五花八门的数据(数组、数据库查询结果等)转换成列表项(View)
类比场景

  • 数据:不同国家的电源插头(Type-C、Lightning、MicroUSB)
  • 适配器:万能转接头
  • View:手机充电口

二、源码级原理分析(以 RecyclerView 为例)

1. 核心类关系图

数据源(List/Cursor) → Adapter → RecyclerView  
      ↑                       |  
      └───── ViewHolder ←─────┘  

2. 核心源码拆解

关键类RecyclerView.Adapter

// frameworks/base/core/java/androidx/recyclerview/widget/RecyclerView.java  
public abstract static class Adapter<VH extends ViewHolder> {  
    // 必须实现的三个方法  
    public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);  
    public abstract void onBindViewHolder(VH holder, int position);  
    public abstract int getItemCount();  

    // 数据变更通知机制(观察者模式)  
    private final AdapterDataObservable mObservable = new AdapterDataObservable();  

    public void registerAdapterDataObserver(AdapterDataObserver observer) {  
        mObservable.registerObserver(observer);  
    }  

    public void notifyDataSetChanged() {  
        mObservable.notifyChanged();  
    }  
}  

工作流程

  1. 创建 ViewHolder

    // 系统在需要新 View 时调用  
    ViewHolder vh = adapter.onCreateViewHolder(parent, viewType);  
    
    • 底层通过 LayoutInflater 解析 XML → View

    • 典型实现:

      public ViewHolder onCreateViewHolder(...) {  
          View view = LayoutInflater.from(parent.getContext())  
              .inflate(R.layout.item_list, parent, false);  
          return new MyViewHolder(view);  
      }  
      
  2. 绑定数据

    // 当列表项进入屏幕时触发  
    adapter.onBindViewHolder(holder, position);  
    
    • 典型实现:

      public void onBindViewHolder(MyViewHolder holder, int position) {  
          String data = mDataList.get(position);  
          holder.textView.setText(data);  
      }  
      
  3. 复用机制(性能关键):

    • RecyclerView 维护一个 回收池(Recycler)
    • 滑动时离屏的 ViewHolder 存入回收池
    • 新进入屏幕的项优先从回收池获取(避免频繁创建 View)

三、底层设计亮点

1. 观察者模式驱动数据更新

// 数据变化时通知 RecyclerView 刷新  
public class MyAdapter extends RecyclerView.Adapter<...> {  
    private List<String> mData;  

    public void updateData(List<String> newData) {  
        mData = newData;  
        notifyDataSetChanged(); // 触发重绘  
    }  
}  

// 源码中的观察者实现  
public static class AdapterDataObservable extends Observable<AdapterDataObserver> {  
    public void notifyChanged() {  
        for (int i = mObservers.size() - 1; i >= 0; i--) {  
            mObservers.get(i).onChanged();  
        }  
    }  
}  

2. ViewHolder 模式优化性能

  • 传统 ListView 的 getView() 每次都要 findViewById()

  • RecyclerView 的 ViewHolder 缓存 View 引用

    class MyViewHolder extends RecyclerView.ViewHolder {  
        TextView textView;  
    
        public MyViewHolder(View itemView) {  
            super(itemView);  
            textView = itemView.findViewById(R.id.text); // 只执行一次  
        }  
    }  
    

3. 差异化视图类型(ViewType)

// 根据数据返回不同布局类型  
public int getItemViewType(int position) {  
    return mData.get(position).isImportant() ? TYPE_HEADER : TYPE_NORMAL;  
}  

// onCreateViewHolder 根据类型创建不同 ViewHolder  
public ViewHolder onCreateViewHolder(...) {  
    if (viewType == TYPE_HEADER) {  
        return new HeaderViewHolder(...);  
    } else {  
        return new NormalViewHolder(...);  
    }  
}  

四、与其他模式的对比

模式核心区别Android 案例
适配器模式接口转换,数据→ViewRecyclerView.Adapter
装饰者模式动态增强功能,保持接口相同ContextWrapper → Context
代理模式控制访问,可能跨进程ActivityManagerProxy

五、最佳实践与坑点

该做的

  1. ViewHolder 用 static 内部类(防止内存泄漏)
  2. 分页加载大数据(避免一次性绑定所有数据)
  3. 使用 DiffUtil 智能刷新(减少不必要的重绘)

不该做的

  1. 在 onBindViewHolder 执行耗时操作(导致列表卡顿)
  2. 在 Adapter 中写业务逻辑(应该放在 ViewModel/Presenter)
  3. 忘记调用 notifyXXX 方法(数据更新但 UI 不变)

六、总结口诀

数据视图两茫茫,适配器来做红娘
ViewHolder 缓存在手,RecyclerView 性能无忧
观察通知变化有,DiffUtil 更智能