Android DataBinding与RecyclerView深度集成(9)

147 阅读44分钟

Android DataBinding与RecyclerView深度集成:列表数据绑定的源码级剖析

一、引言

在现代Android开发中,RecyclerView已成为展示列表数据的标准组件,而DataBinding则为视图与数据之间的绑定提供了高效的解决方案。当这两者结合使用时,可以极大地简化列表数据的展示和更新逻辑。本文将从源码级别深入分析Android DataBinding与RecyclerView结合使用的原理与实现细节,通过大量实例代码和详细注释,全面解析其实现机制。

二、RecyclerView与DataBinding基础

2.1 RecyclerView概述

RecyclerView是Android提供的一个强大的列表控件,用于高效展示大量数据。

// RecyclerView的基本使用
public class MainActivity extends AppCompatActivity {
    private RecyclerView recyclerView;
    private MyAdapter adapter;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // 初始化RecyclerView
        recyclerView = findViewById(R.id.recyclerView);
        
        // 设置布局管理器
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        
        // 设置适配器
        adapter = new MyAdapter();
        recyclerView.setAdapter(adapter);
        
        // 设置数据
        List<String> data = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            data.add("Item " + i);
        }
        adapter.setData(data);
    }
}

2.2 DataBinding概述

DataBinding是Android官方提供的一个支持库,允许开发者将布局文件中的视图与应用程序中的数据源绑定。

// 启用DataBinding的build.gradle配置
android {
    ...
    dataBinding {
        enabled = true
    }
}

2.3 简单的数据绑定示例

下面是一个简单的数据绑定示例,展示如何将数据绑定到TextView。

<!-- 布局文件 -->
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="user"
            type="com.example.User" />
    </data>
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.name}" /> <!-- 绑定到user对象的name属性 -->
    </LinearLayout>
</layout>
// User类
public class User extends BaseObservable {
    private String name;
    
    // 构造方法
    public User(String name) {
        this.name = name;
    }
    
    // 获取name属性,添加@Bindable注解以便DataBinding识别
    @Bindable
    public String getName() {
        return name;
    }
    
    // 设置name属性,并通知属性变化
    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(BR.name); // 通知name属性已变化
    }
}

三、RecyclerView与DataBinding的基本集成

3.1 传统方式集成RecyclerView与DataBinding

下面是一个传统方式集成RecyclerView与DataBinding的示例。

// 使用DataBinding的RecyclerView适配器
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
    private List<String> data = new ArrayList<>();
    
    // 设置数据
    public void setData(List<String> data) {
        this.data = data;
        notifyDataSetChanged(); // 通知适配器数据已变化
    }
    
    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // 使用DataBindingUtil.inflate方法创建Item布局的绑定类
        ItemLayoutBinding binding = ItemLayoutBinding.inflate(
                LayoutInflater.from(parent.getContext()), parent, false);
        return new MyViewHolder(binding);
    }
    
    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        // 获取当前位置的数据
        String item = data.get(position);
        
        // 设置数据到绑定类
        holder.binding.setItem(item);
        
        // 执行挂起的绑定,确保数据立即更新到视图
        holder.binding.executePendingBindings();
    }
    
    @Override
    public int getItemCount() {
        return data.size();
    }
    
    // ViewHolder类,持有绑定类的引用
    public static class MyViewHolder extends RecyclerView.ViewHolder {
        private ItemLayoutBinding binding;
        
        public MyViewHolder(@NonNull ItemLayoutBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }
    }
}
<!-- 列表项布局文件 -->
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="item"
            type="java.lang.String" />
    </data>
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="16dp">
        
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{item}" /> <!-- 绑定到item变量 -->
    </LinearLayout>
</layout>

3.2 使用DataBinding的RecyclerView适配器

下面是一个更通用的RecyclerView适配器,使用DataBinding处理不同类型的列表项。

// 通用的RecyclerView适配器,使用DataBinding
public class GenericAdapter<T> extends RecyclerView.Adapter<GenericAdapter.BindingViewHolder> {
    private List<T> items = new ArrayList<>();
    private int layoutId;
    private int variableId;
    
    // 构造方法,传入布局ID和变量ID
    public GenericAdapter(int layoutId, int variableId) {
        this.layoutId = layoutId;
        this.variableId = variableId;
    }
    
    // 设置数据
    public void setItems(List<T> items) {
        this.items = items;
        notifyDataSetChanged(); // 通知适配器数据已变化
    }
    
    @NonNull
    @Override
    public BindingViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // 使用DataBindingUtil.inflate方法创建布局的绑定类
        ViewDataBinding binding = DataBindingUtil.inflate(
                LayoutInflater.from(parent.getContext()), layoutId, parent, false);
        return new BindingViewHolder(binding);
    }
    
    @Override
    public void onBindViewHolder(@NonNull BindingViewHolder holder, int position) {
        // 获取当前位置的数据
        T item = items.get(position);
        
        // 设置变量到绑定类
        holder.binding.setVariable(variableId, item);
        
        // 执行挂起的绑定,确保数据立即更新到视图
        holder.binding.executePendingBindings();
    }
    
    @Override
    public int getItemCount() {
        return items.size();
    }
    
    // ViewHolder类,持有绑定类的引用
    public static class BindingViewHolder extends RecyclerView.ViewHolder {
        private ViewDataBinding binding;
        
        public BindingViewHolder(@NonNull ViewDataBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }
    }
}
// 在Activity中使用通用适配器
public class MainActivity extends AppCompatActivity {
    private RecyclerView recyclerView;
    private GenericAdapter<String> adapter;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // 初始化RecyclerView
        recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        
        // 创建适配器,传入布局ID和变量ID
        adapter = new GenericAdapter<>(R.layout.item_layout, BR.item);
        
        // 设置适配器
        recyclerView.setAdapter(adapter);
        
        // 设置数据
        List<String> data = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            data.add("Item " + i);
        }
        adapter.setItems(data);
    }
}

四、编译时处理

4.1 布局文件解析

在编译时,DataBinding框架会解析布局文件,提取数据绑定表达式。

// 布局文件解析器的简化实现
public class LayoutFileParser {
    // 解析布局文件,提取数据绑定信息
    public BindingInfo parseLayoutFile(File layoutFile) throws XmlPullParserException, IOException {
        BindingInfo bindingInfo = new BindingInfo();
        
        // 创建XML解析器
        XmlPullParser parser = Xml.newPullParser();
        parser.setInput(new FileInputStream(layoutFile), null);
        
        int eventType = parser.getEventType();
        while (eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.START_TAG) {
                // 处理标签
                if (parser.getName().equals("layout")) {
                    // 处理layout标签
                    parseLayoutTag(parser, bindingInfo);
                } else if (parser.getName().equals("data")) {
                    // 处理data标签
                    parseDataTag(parser, bindingInfo);
                } else {
                    // 处理普通视图标签
                    parseViewTag(parser, bindingInfo);
                }
            }
            eventType = parser.next();
        }
        
        return bindingInfo;
    }
    
    // 解析layout标签
    private void parseLayoutTag(XmlPullParser parser, BindingInfo bindingInfo) {
        // 处理layout标签的属性
        for (int i = 0; i < parser.getAttributeCount(); i++) {
            String attrName = parser.getAttributeName(i);
            String attrValue = parser.getAttributeValue(i);
            
            // 处理属性...
        }
    }
    
    // 解析data标签
    private void parseDataTag(XmlPullParser parser, BindingInfo bindingInfo) throws XmlPullParserException, IOException {
        int eventType = parser.getEventType();
        while (eventType != XmlPullParser.END_TAG || !parser.getName().equals("data")) {
            if (eventType == XmlPullParser.START_TAG) {
                if (parser.getName().equals("variable")) {
                    // 解析variable标签
                    parseVariableTag(parser, bindingInfo);
                } else if (parser.getName().equals("import")) {
                    // 解析import标签
                    parseImportTag(parser, bindingInfo);
                }
            }
            eventType = parser.next();
        }
    }
    
    // 解析variable标签
    private void parseVariableTag(XmlPullParser parser, BindingInfo bindingInfo) {
        String name = parser.getAttributeValue(null, "name");
        String type = parser.getAttributeValue(null, "type");
        
        // 创建变量信息对象
        VariableInfo variableInfo = new VariableInfo();
        variableInfo.setName(name);
        variableInfo.setType(type);
        
        // 添加到绑定信息中
        bindingInfo.addVariable(variableInfo);
    }
    
    // 解析import标签
    private void parseImportTag(XmlPullParser parser, BindingInfo bindingInfo) {
        String type = parser.getAttributeValue(null, "type");
        String alias = parser.getAttributeValue(null, "alias");
        
        // 创建导入信息对象
        ImportInfo importInfo = new ImportInfo();
        importInfo.setType(type);
        importInfo.setAlias(alias);
        
        // 添加到绑定信息中
        bindingInfo.addImport(importInfo);
    }
    
    // 解析普通视图标签
    private void parseViewTag(XmlPullParser parser, BindingInfo bindingInfo) {
        String tagName = parser.getName();
        int id = parser.getIdAttributeResourceValue(-1);
        
        // 创建视图信息对象
        ViewInfo viewInfo = new ViewInfo();
        viewInfo.setTagName(tagName);
        viewInfo.setId(id);
        
        // 处理视图的属性
        for (int i = 0; i < parser.getAttributeCount(); i++) {
            String attrNamespace = parser.getAttributeNamespace(i);
            String attrName = parser.getAttributeName(i);
            String attrValue = parser.getAttributeValue(i);
            
            // 检查是否是数据绑定表达式
            if (attrValue.startsWith("@{") && attrValue.endsWith("}")) {
                // 提取表达式内容
                String expression = attrValue.substring(2, attrValue.length() - 1);
                
                // 创建属性绑定信息
                AttributeBinding attributeBinding = new AttributeBinding();
                attributeBinding.setNamespace(attrNamespace);
                attributeBinding.setName(attrName);
                attributeBinding.setExpression(expression);
                
                // 添加到视图信息中
                viewInfo.addAttributeBinding(attributeBinding);
            }
        }
        
        // 添加到绑定信息中
        bindingInfo.addView(viewInfo);
    }
}

4.2 绑定类生成

DataBinding框架会为每个布局文件生成一个绑定类,负责处理数据与视图的绑定。

// 绑定类生成器的简化实现
public class BindingClassGenerator {
    // 生成绑定类
    public void generateBindingClass(BindingInfo bindingInfo, File outputDir) throws IOException {
        String packageName = bindingInfo.getPackageName();
        String className = bindingInfo.getClassName();
        
        // 创建Java文件
        File javaFile = new File(outputDir, className.replace('.', '/') + ".java");
        javaFile.getParentFile().mkdirs();
        javaFile.createNewFile();
        
        // 创建输出流
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(javaFile))) {
            // 写入包声明
            writer.write("package " + packageName + ";\n\n");
            
            // 写入导入语句
            writer.write("import android.view.View;\n");
            writer.write("import androidx.databinding.Bindable;\n");
            writer.write("import androidx.databinding.DataBindingUtil;\n");
            writer.write("import androidx.databinding.ViewDataBinding;\n");
            
            // 写入布局文件中声明的导入
            for (ImportInfo importInfo : bindingInfo.getImports()) {
                writer.write("import " + importInfo.getType() + ";\n");
            }
            
            writer.write("\n");
            
            // 写入类声明
            writer.write("public class " + className + " extends ViewDataBinding {\n\n");
            
            // 写入成员变量
            writer.write("    @NonNull\n");
            writer.write("    private final View rootView;\n\n");
            
            // 写入变量引用
            for (VariableInfo variableInfo : bindingInfo.getVariables()) {
                writer.write("    @Nullable\n");
                writer.write("    private " + variableInfo.getType() + " " + 
                        variableInfo.getName() + ";\n");
            }
            
            writer.write("\n");
            
            // 写入构造方法
            writer.write("    public " + className + "(@NonNull View root) {\n");
            writer.write("        super(root);\n");
            writer.write("        this.rootView = root;\n");
            
            // 初始化视图引用
            for (ViewInfo viewInfo : bindingInfo.getViews()) {
                writer.write("        this." + viewInfo.getIdName() + " = findViewById(root, " + 
                        viewInfo.getId() + ");\n");
            }
            
            writer.write("    }\n\n");
            
            // 写入设置变量的方法
            writer.write("    @Override\n");
            writer.write("    public boolean setVariable(int variableId, @Nullable Object variable) {\n");
            writer.write("        switch (variableId) {\n");
            
            for (VariableInfo variableInfo : bindingInfo.getVariables()) {
                writer.write("            case " + getVariableId(variableInfo) + ":\n");
                writer.write("                this." + variableInfo.getName() + " = (" + 
                        variableInfo.getType() + ") variable;\n");
                writer.write("                return true;\n");
            }
            
            writer.write("            default:\n");
            writer.write("                return false;\n");
            writer.write("        }\n");
            writer.write("    }\n\n");
            
            // 为每个变量写入单独的setter方法
            for (VariableInfo variableInfo : bindingInfo.getVariables()) {
                writer.write("    public void set" + capitalize(variableInfo.getName()) + 
                        "(@Nullable " + variableInfo.getType() + " " + variableInfo.getName() + ") {\n");
                writer.write("        this." + variableInfo.getName() + " = " + variableInfo.getName() + ";\n");
                writer.write("        invalidateAll();\n");
                writer.write("    }\n\n");
            }
            
            // 写入执行绑定的方法
            writer.write("    @Override\n");
            writer.write("    protected void executeBindings() {\n");
            
            // 获取所有变量
            for (VariableInfo variableInfo : bindingInfo.getVariables()) {
                writer.write("        " + variableInfo.getType() + " " + variableInfo.getName() + "Value = " + 
                        variableInfo.getName() + ";\n");
            }
            
            writer.write("\n");
            
            // 处理每个视图的绑定
            for (ViewInfo viewInfo : bindingInfo.getViews()) {
                for (AttributeBinding attributeBinding : viewInfo.getAttributeBindings()) {
                    // 生成绑定代码
                    writer.write("        // " + viewInfo.getIdName() + "." + attributeBinding.getName() + "\n");
                    writer.write("        " + generateBindingCode(viewInfo, attributeBinding) + "\n");
                }
            }
            
            writer.write("    }\n\n");
            
            // 写入结束括号
            writer.write("}\n");
        }
    }
    
    // 生成绑定代码
    private String generateBindingCode(ViewInfo viewInfo, AttributeBinding attributeBinding) {
        // 简化实现:在实际代码中,这里会生成更复杂的绑定代码
        return "// Binding code for " + viewInfo.getIdName() + "." + attributeBinding.getName();
    }
    
    // 获取变量ID
    private String getVariableId(VariableInfo variableInfo) {
        // 简化实现:在实际代码中,这里会使用BR类中的常量
        return "BR." + variableInfo.getName();
    }
    
    // 首字母大写
    private String capitalize(String s) {
        if (s == null || s.isEmpty()) {
            return s;
        }
        return Character.toUpperCase(s.charAt(0)) + s.substring(1);
    }
}

五、运行时处理

5.1 绑定类初始化

在运行时,绑定类会被实例化并与布局视图关联。

// 绑定类初始化过程
public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding binding;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 使用DataBindingUtil.inflate方法创建绑定类实例
        binding = DataBindingUtil.inflate(
                getLayoutInflater(),
                R.layout.activity_main,
                null,
                false);
        
        // 设置ContentView为绑定类的根视图
        setContentView(binding.getRoot());
        
        // 初始化RecyclerView
        RecyclerView recyclerView = binding.recyclerView;
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        
        // 创建适配器
        MyAdapter adapter = new MyAdapter();
        recyclerView.setAdapter(adapter);
        
        // 设置数据
        List<String> data = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            data.add("Item " + i);
        }
        adapter.setData(data);
    }
}

5.2 数据变化监听与通知

当数据发生变化时,会触发通知机制。

// 数据变化通知流程
public class User extends BaseObservable {
    private String name;
    private int age;
    
    // 构造方法
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // 获取name属性
    @Bindable
    public String getName() {
        return name;
    }
    
    // 设置name属性,并通知变化
    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(BR.name); // 通知name属性已变化
    }
    
    // 获取age属性
    @Bindable
    public int getAge() {
        return age;
    }
    
    // 设置age属性,并通知变化
    public void setAge(int age) {
        this.age = age;
        notifyPropertyChanged(BR.age); // 通知age属性已变化
    }
}

5.3 UI更新过程

当数据变化通知到达时,绑定类会更新对应的UI组件。

// UI更新过程
public class ItemLayoutBindingImpl extends ItemLayoutBinding {
    @NonNull
    private final LinearLayout rootView;
    
    @NonNull
    public final TextView textView;
    
    @Nullable
    private String mItem;  // 数据源对象
    
    // 构造方法
    public ItemLayoutBindingImpl(@NonNull View root) {
        super(root);
        this.rootView = (LinearLayout) root;
        this.textView = findViewById(root, R.id.textView);
    }
    
    // 设置Item对象
    public void setItem(@Nullable String item) {
        mItem = item;
        invalidateAll();  // 标记所有绑定需要重新计算
    }
    
    // 执行绑定操作
    @Override
    protected void executeBindings() {
        String itemValue = mItem;
        
        // 更新视图
        textView.setText(itemValue);
    }
}

六、与LiveData的集成

6.1 LiveData概述

LiveData是一种可观察的数据持有者类,它遵循应用程序组件的生命周期,确保仅在活动的生命周期状态下更新UI。

// LiveData类定义
public abstract class LiveData<T> {
    // 添加观察者
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        // 检查生命周期状态
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // 已经销毁,直接返回
            return;
        }
        
        // 创建包装后的观察者
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        
        // 存储观察者
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        
        // 处理已存在的观察者
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        
        if (existing != null) {
            return;
        }
        
        // 绑定到生命周期
        owner.getLifecycle().addObserver(wrapper);
    }
    
    // 设置值(主线程)
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }
    
    // 发布值(后台线程)
    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }
    
    // 分发值给观察者
    private void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }
    
    // 考虑通知观察者
    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        
        // 检查生命周期状态
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        
        // 检查版本
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        
        // 更新版本
        observer.mLastVersion = mVersion;
        
        // 调用观察者的onChanged方法
        observer.mObserver.onChanged((T) mData);
    }
    
    // 观察者包装类
    private abstract class ObserverWrapper {
        final Observer<? super T> mObserver;
        boolean mActive;
        int mLastVersion = START_VERSION;
        
        ObserverWrapper(Observer<? super T> observer) {
            mObserver = observer;
        }
        
        abstract boolean shouldBeActive();
        
        boolean isAttachedTo(LifecycleOwner owner) {
            return false;
        }
        
        void detachObserver() {
        }
        
        void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            
            // 更改活动状态
            mActive = newActive;
            
            // 计算活动观察者数量
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            LiveData.this.mActiveCount += mActive ? 1 : -1;
            
            // 处理首次活动和不再活动的情况
            if (wasInactive && mActive) {
                onActive();
            }
            
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                onInactive();
            }
            
            if (mActive) {
                dispatchingValue(this);
            }
        }
    }
    
    // 生命周期绑定的观察者
    class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;
        
        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
        }
        
        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }
        
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            activeStateChanged(shouldBeActive());
        }
        
        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }
        
        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }
}

6.2 DataBinding与LiveData的集成

DataBinding可以直接与LiveData集成,实现自动更新UI。

// ViewModel类
public class UserViewModel extends ViewModel {
    private MutableLiveData<List<User>> userListLiveData = new MutableLiveData<>();
    
    public UserViewModel() {
        // 初始化用户列表
        List<User> userList = new ArrayList<>();
        userList.add(new User("John Doe", 30));
        userList.add(new User("Jane Smith", 25));
        userList.add(new User("Bob Johnson", 35));
        
        userListLiveData.setValue(userList);
    }
    
    // 获取用户列表LiveData
    public LiveData<List<User>> getUserList() {
        return userListLiveData;
    }
    
    // 添加新用户
    public void addUser() {
        List<User> currentList = userListLiveData.getValue();
        List<User> newList = new ArrayList<>(currentList);
        newList.add(new User("New User", 20));
        userListLiveData.setValue(newList);
    }
}
<!-- 布局文件 -->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="viewModel"
            type="com.example.UserViewModel" />
    </data>
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        
        <androidx.recyclerview.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
            app:adapter="@{viewModel.userList}" /> <!-- 绑定到LiveData中的userList -->
            
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Add User"
            android:onClick="@{() -> viewModel.addUser()}" />
    </LinearLayout>
</layout>
// Activity类
public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding binding;
    private UserViewModel viewModel;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 创建ViewModel
        viewModel = new ViewModelProvider(this).get(UserViewModel.class);
        
        // 创建DataBinding
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        
        // 设置ViewModel到DataBinding
        binding.setViewModel(viewModel);
        
        // 设置生命周期所有者,使DataBinding能够观察LiveData
        binding.setLifecycleOwner(this);
        
        // 初始化RecyclerView
        RecyclerView recyclerView = binding.recyclerView;
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        
        // 创建适配器
        UserAdapter adapter = new UserAdapter();
        recyclerView.setAdapter(adapter);
        
        // 观察用户列表变化
        viewModel.getUserList().observe(this, new Observer<List<User>>() {
            @Override
            public void onChanged(List<User> users) {
                adapter.setUsers(users); // 更新适配器数据
            }
        });
    }
}

6.3 LiveData到RecyclerView的更新流程

当LiveData的值发生变化时,会触发RecyclerView的更新。

// LiveData到RecyclerView的更新流程
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserViewHolder> {
    private List<User> users = new ArrayList<>();
    
    // 设置用户列表
    public void setUsers(List<User> users) {
        this.users = users;
        notifyDataSetChanged(); // 通知适配器数据已变化
    }
    
    @NonNull
    @Override
    public UserViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // 使用DataBindingUtil.inflate方法创建Item布局的绑定类
        ItemUserBinding binding = ItemUserBinding.inflate(
                LayoutInflater.from(parent.getContext()), parent, false);
        return new UserViewHolder(binding);
    }
    
    @Override
    public void onBindViewHolder(@NonNull UserViewHolder holder, int position) {
        // 获取当前位置的用户
        User user = users.get(position);
        
        // 设置用户到绑定类
        holder.binding.setUser(user);
        
        // 执行挂起的绑定,确保数据立即更新到视图
        holder.binding.executePendingBindings();
    }
    
    @Override
    public int getItemCount() {
        return users.size();
    }
    
    // ViewHolder类
    public static class UserViewHolder extends RecyclerView.ViewHolder {
        private ItemUserBinding binding;
        
        public UserViewHolder(@NonNull ItemUserBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }
    }
}

七、使用DiffUtil优化RecyclerView更新

7.1 DiffUtil概述

DiffUtil是Android提供的一个工具类,用于计算两个数据集之间的差异。

// DiffUtil类定义
public class DiffUtil {
    // 计算两个数据集之间的差异
    public static DiffResult calculateDiff(Callback callback) {
        return calculateDiff(callback, false);
    }
    
    // 计算两个数据集之间的差异
    public static DiffResult calculateDiff(Callback callback, boolean detectMoves) {
        // 获取旧数据集的大小
        final int oldSize = callback.getOldListSize();
        // 获取新数据集的大小
        final int newSize = callback.getNewListSize();
        
        // 创建结果对象
        final DiffResult result = new DiffResult(callback, detectMoves);
        
        // 处理特殊情况
        if (oldSize == 0) {
            // 旧数据集为空,所有项都是新增的
            result.mNewItemCount = newSize;
            result.mOldItemCount = 0;
            for (int i = 0; i < newSize; i++) {
                result.mPostponedUpdates.add(new UpdateOp(UpdateOp.ADD, -1, i));
            }
            return result;
        }
        
        if (newSize == 0) {
            // 新数据集为空,所有项都是删除的
            result.mNewItemCount = 0;
            result.mOldItemCount = oldSize;
            for (int i = 0; i < oldSize; i++) {
                result.mPostponedUpdates.add(new UpdateOp(UpdateOp.REMOVE, i, -1));
            }
            return result;
        }
        
        // 使用 Myers 差异算法计算差异
        final List<Snake> snakes = new ArrayList<>();
        final SparseIntArray forward = new SparseIntArray();
        final SparseIntArray backward = new SparseIntArray();
        
        // 初始化
        int max = oldSize + newSize + 1;
        forward.put(1, 0);
        backward.put(1, oldSize);
        
        // 执行算法
        int d;
        for (d = 0; d <= (oldSize + newSize + 1) / 2; d++) {
            // 向前搜索
            for (int k = -d; k <= d; k += 2) {
                int x;
                if (k == -d || (k != d && forward.get(k - 1) < forward.get(k + 1))) {
                    x = forward.get(k + 1);
                } else {
                    x = forward.get(k - 1) + 1;
                }
                
                int y = x - k;
                
                while (x < oldSize && y < newSize && callback.areItemsTheSame(x, y)) {
                    x++;
                    y++;
                }
                
                forward.put(k, x);
                
                if (x >= oldSize && y >= newSize) {
                    // 找到解
                    result.mNewItemCount = newSize;
                    result.mOldItemCount = oldSize;
                    result.mSnakes = snakes;
                    result.mReverse = false;
                    return result;
                }
            }
            
            // 向后搜索
            for (int k = -d; k <= d; k += 2) {
                int x;
                if (k == -d || (k != d && backward.get(k - 1) < backward.get(k + 1))) {
                    x = backward.get(k + 1);
                } else {
                    x = backward.get(k - 1) + 1;
                }
                
                int y = x - k;
                
                while (x > 0 && y > 0 && callback.areItemsTheSame(x - 1, y - 1)) {
                    x--;
                    y--;
                }
                
                backward.put(k, x);
                
                if (x <= 0 && y <= 0) {
                    // 找到解
                    result.mNewItemCount = newSize;
                    result.mOldItemCount = oldSize;
                    result.mSnakes = snakes;
                    result.mReverse = true;
                    return result;
                }
            }
        }
        
        throw new IllegalStateException("DiffUtil hit an unexpected case while trying to calculate"
                + " the optimal path. Please make sure your data is not changing during the"
                + " diff calculation.");
    }
    
    // 回调接口,用于比较两个数据集
    public abstract static class Callback {
        // 获取旧数据集的大小
        public abstract int getOldListSize();
        
        // 获取新数据集的大小
        public abstract int getNewListSize();
        
        // 判断两个位置的项是否代表同一个对象
        public abstract boolean areItemsTheSame(int oldItemPosition, int newItemPosition);
        
        // 判断两个项的内容是否相同
        public abstract boolean areContentsTheSame(int oldItemPosition, int newItemPosition);
        
        // 获取变化的有效负载
        @Nullable
        public Object getChangePayload(int oldItemPosition, int newItemPosition) {
            return null;
        }
    }
    
    // 差异结果类
    public static class DiffResult {
        // 各种更新操作类型
        public static final int UPDATE = 0;
        public static final int INSERT = 1;
        public static final int REMOVE = 2;
        public static final int MOVE = 3;
        
        // 其他成员变量和方法...
    }
}

7.2 使用DiffUtil优化RecyclerView适配器

下面是一个使用DiffUtil优化的RecyclerView适配器。

// 使用DiffUtil优化的RecyclerView适配器
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserViewHolder> {
    private List<User> users = new ArrayList<>();
    
    // 设置用户列表
    public void setUsers(List<User> newUsers) {
        // 计算差异
        DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new UserDiffCallback(users, newUsers));
        
        // 更新数据
        users.clear();
        users.addAll(newUsers);
        
        // 应用差异
        diffResult.dispatchUpdatesTo(this);
    }
    
    @NonNull
    @Override
    public UserViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // 使用DataBindingUtil.inflate方法创建Item布局的绑定类
        ItemUserBinding binding = ItemUserBinding.inflate(
                LayoutInflater.from(parent.getContext()), parent, false);
        return new UserViewHolder(binding);
    }
    
    @Override
    public void onBindViewHolder(@NonNull UserViewHolder holder, int position) {
        // 获取当前位置的用户
        User user = users.get(position);
        
        // 设置用户到绑定类
        holder.binding.setUser(user);
        
        // 执行挂起的绑定,确保数据立即更新到视图
        holder.binding.executePendingBindings();
    }
    
    @Override
    public int getItemCount() {
        return users.size();
    }
    
    // DiffUtil回调类
    private static class UserDiffCallback extends DiffUtil.Callback {
        private List<User> oldUsers;
        private List<User> newUsers;
        
        public UserDiffCallback(List<User> oldUsers, List<User> newUsers) {
            this.oldUsers = oldUsers;
            this.newUsers = newUsers;
        }
        
        @Override
        public int getOldListSize() {
            return oldUsers.size();
        }
        
        @Override
        public int getNewListSize() {
            return newUsers.size();
        }
        
        @Override
        public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
            // 判断是否是同一个用户(通过ID比较)
            return oldUsers.get(oldItemPosition).getId() == newUsers.get(newItemPosition).getId();
        }
        
        @Override
        public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
            // 判断两个用户的内容是否相同
            User oldUser = oldUsers.get(oldItemPosition);
            User newUser = newUsers.get(newItemPosition);
            
            return oldUser.getName().equals(newUser.getName()) &&
                    oldUser.getAge() == newUser.getAge();
        }
        
        @Nullable
        @Override
        public Object getChangePayload(int oldItemPosition, int newItemPosition) {
            // 获取变化的有效负载
            User oldUser = oldUsers.get(oldItemPosition);
            User newUser = newUsers.get(newItemPosition);
            
            Bundle diffBundle = new Bundle();
            
            if (!oldUser.getName().equals(newUser.getName())) {
                diffBundle.putString("name", newUser.getName());
            }
            
            if (oldUser.getAge() != newUser.getAge()) {
                diffBundle.putInt("age", newUser.getAge());
            }
            
            if (diffBundle.size() == 0) {
                return null;
            }
            
            return diffBundle;
        }
    }
    
    // ViewHolder类
    public static class UserViewHolder extends RecyclerView.ViewHolder {
        private ItemUserBinding binding;
        
        public UserViewHolder(@NonNull ItemUserBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }
    }
}

7.3 使用Payloads优化部分更新

可以使用payloads来优化只更新发生变化的部分UI。

// 使用payloads优化部分更新
@Override
public void onBindViewHolder(@NonNull UserViewHolder holder, int position, @NonNull List<Object> payloads) {
    if (payloads.isEmpty()) {
        // 没有有效负载,进行完整绑定
        onBindViewHolder(holder, position);
    } else {
        // 有有效负载,只更新变化的部分
        Bundle payload = (Bundle) payloads.get(0);
        User user = users.get(position);
        
        if (payload.containsKey("name")) {
            holder.binding.textViewName.setText(payload.getString("name"));
        }
        
        if (payload.containsKey("age")) {
            holder.binding.textViewAge.setText(String.valueOf(payload.getInt("age")));
        }
    }
}

八、使用ListAdapter简化实现

8.1 ListAdapter概述

ListAdapter是RecyclerView.Adapter的抽象子类,内置了DiffUtil功能,可以简化RecyclerView适配器的实现。

// ListAdapter类定义
public abstract class ListAdapter<T, VH extends RecyclerView.ViewHolder>
        extends RecyclerView.Adapter<VH> {
    private final AsyncListDiffer<T> mDiffer;
    private final DiffUtil.ItemCallback<T> mDiffCallback;
    
    // 构造方法
    protected ListAdapter(@NonNull DiffUtil.ItemCallback<T> diffCallback) {
        mDiffCallback = diffCallback;
        mDiffer = new AsyncListDiffer<>(
                new AdapterListUpdateCallback(this),
                new AsyncDifferConfig.Builder<T>(diffCallback).build());
    }
    
    // 构造方法
    protected ListAdapter(@NonNull Executor mainThreadExecutor,
            @NonNull Executor backgroundExecutor,
            @NonNull DiffUtil.ItemCallback<T> diffCallback) {
        mDiffCallback = diffCallback;
        mDiffer = new AsyncListDiffer<>(
                new AdapterListUpdateCallback(this),
                new AsyncDifferConfig.Builder<T>(diffCallback)
                        .setMainThreadExecutor(mainThreadExecutor)
                        .setBackgroundExecutor(backgroundExecutor)
                        .build());
    }
    
    // 设置新的列表数据
    public void submitList(@Nullable List<T> list) {
        mDiffer.submitList(list);
    }
    
    // 设置新的列表数据,并提供一个回调,当

8.1 ListAdapter概述(续)

    // 设置新的列表数据,并提供一个回调,当差异计算完成且更新已发布时执行
    public void submitList(@Nullable List<T> list, @Nullable Runnable commitCallback) {
        mDiffer.submitList(list, commitCallback);
    }
    
    // 获取当前列表数据
    @Nullable
    public T getItem(int position) {
        return mDiffer.getCurrentList().get(position);
    }
    
    // 获取当前列表大小
    @Override
    public int getItemCount() {
        return mDiffer.getCurrentList().size();
    }
    
    // 获取差异回调
    @NonNull
    protected DiffUtil.ItemCallback<T> getDiffCallback() {
        return mDiffCallback;
    }
}

8.2 使用ListAdapter实现RecyclerView适配器

下面是一个使用ListAdapter实现的RecyclerView适配器示例。

// 使用ListAdapter的RecyclerView适配器
public class UserAdapter extends ListAdapter<User, UserAdapter.UserViewHolder> {
    // 创建DiffUtil.ItemCallback实例
    private static final DiffUtil.ItemCallback<User> DIFF_CALLBACK = new DiffUtil.ItemCallback<User>() {
        @Override
        public boolean areItemsTheSame(@NonNull User oldItem, @NonNull User newItem) {
            // 判断是否是同一个用户(通过ID比较)
            return oldItem.getId() == newItem.getId();
        }
        
        @Override
        public boolean areContentsTheSame(@NonNull User oldItem, @NonNull User newItem) {
            // 判断两个用户的内容是否相同
            return oldItem.getName().equals(newItem.getName()) &&
                    oldItem.getAge() == newItem.getAge();
        }
    };
    
    // 构造方法
    public UserAdapter() {
        super(DIFF_CALLBACK);
    }
    
    @NonNull
    @Override
    public UserViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // 使用DataBindingUtil.inflate方法创建Item布局的绑定类
        ItemUserBinding binding = ItemUserBinding.inflate(
                LayoutInflater.from(parent.getContext()), parent, false);
        return new UserViewHolder(binding);
    }
    
    @Override
    public void onBindViewHolder(@NonNull UserViewHolder holder, int position) {
        // 获取当前位置的用户
        User user = getItem(position);
        
        // 设置用户到绑定类
        holder.binding.setUser(user);
        
        // 执行挂起的绑定,确保数据立即更新到视图
        holder.binding.executePendingBindings();
    }
    
    // ViewHolder类
    public static class UserViewHolder extends RecyclerView.ViewHolder {
        private ItemUserBinding binding;
        
        public UserViewHolder(@NonNull ItemUserBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }
    }
}

8.3 在ViewModel中使用ListAdapter

下面是一个在ViewModel中使用ListAdapter的示例。

// 在ViewModel中使用ListAdapter
public class UserViewModel extends ViewModel {
    private MutableLiveData<PagedList<User>> userListLiveData;
    private UserAdapter adapter;
    private UserRepository repository;
    
    public UserViewModel() {
        repository = new UserRepository();
        adapter = new UserAdapter();
        
        // 配置Paging
        PagedList.Config config = new PagedList.Config.Builder()
                .setPageSize(20)  // 每页显示的数量
                .setEnablePlaceholders(false)  // 不启用占位符
                .build();
        
        // 创建PagedList
        userListLiveData = new MutableLiveData<>();
        LivePagedListBuilder<Integer, User>(repository.getUsers(), config)
                .build()
                .observeForever(new Observer<PagedList<User>>() {
                    @Override
                    public void onChanged(PagedList<User> users) {
                        adapter.submitList(users);  // 提交列表到适配器
                    }
                });
    }
    
    // 获取适配器
    public UserAdapter getAdapter() {
        return adapter;
    }
    
    // 添加新用户
    public void addUser() {
        repository.addUser(new User("New User", 20));
    }
}

8.4 ListAdapter与Paging库结合使用

ListAdapter可以与Paging库结合使用,高效处理大量数据。

// ListAdapter与Paging库结合使用
public class UserViewModel extends ViewModel {
    private LiveData<PagedList<User>> userListLiveData;
    private UserAdapter adapter;
    
    public UserViewModel() {
        adapter = new UserAdapter();
        
        // 配置Paging
        PagedList.Config config = new PagedList.Config.Builder()
                .setPageSize(20)  // 每页显示的数量
                .setPrefetchDistance(10)  // 预取距离
                .setEnablePlaceholders(true)  // 启用占位符
                .build();
        
        // 创建PagedList
        userListLiveData = new LivePagedListBuilder<>(
                new UserDataSourceFactory(),  // 数据源工厂
                config)
                .build();
        
        // 观察PagedList变化
        userListLiveData.observeForever(new Observer<PagedList<User>>() {
            @Override
            public void onChanged(PagedList<User> users) {
                adapter.submitList(users);  // 提交列表到适配器
            }
        });
    }
    
    // 获取用户列表LiveData
    public LiveData<PagedList<User>> getUserListLiveData() {
        return userListLiveData;
    }
    
    // 获取适配器
    public UserAdapter getAdapter() {
        return adapter;
    }
}

九、性能优化

9.1 减少不必要的更新

在数据模型中,应该只在数据真正发生变化时才通知UI更新。

// 优化数据模型,减少不必要的更新
public class User extends BaseObservable {
    private String name;
    private int age;
    
    // 获取name属性
    @Bindable
    public String getName() {
        return name;
    }
    
    // 设置name属性,仅在值不同时通知变化
    public void setName(String name) {
        if (!Objects.equals(this.name, name)) {
            this.name = name;
            notifyPropertyChanged(BR.name);  // 通知name属性已变化
        }
    }
    
    // 获取age属性
    @Bindable
    public int getAge() {
        return age;
    }
    
    // 设置age属性,仅在值不同时通知变化
    public void setAge(int age) {
        if (this.age != age) {
            this.age = age;
            notifyPropertyChanged(BR.age);  // 通知age属性已变化
        }
    }
}

9.2 使用合并更新

对于频繁变化的数据,可以合并更新以减少UI刷新次数。

// 使用合并更新的ViewModel
public class UserViewModel extends ViewModel {
    private MutableLiveData<User> userLiveData = new MutableLiveData<>();
    private Handler handler = new Handler(Looper.getMainLooper());
    private Runnable updateRunnable;
    private User pendingUser;
    
    public UserViewModel() {
        // 初始化用户数据
        User user = new User("John Doe", 30);
        userLiveData.setValue(user);
    }
    
    // 获取用户LiveData
    public LiveData<User> getUser() {
        return userLiveData;
    }
    
    // 批量更新用户信息
    public void updateUserInfo(String name, int age, boolean isPremium) {
        // 获取当前用户
        User currentUser = userLiveData.getValue();
        
        // 创建新用户对象
        User newUser = new User(name, age);
        newUser.setPremium(isPremium);
        
        // 设置待更新的用户
        pendingUser = newUser;
        
        // 如果已经有一个更新任务在排队,移除它
        if (updateRunnable != null) {
            handler.removeCallbacks(updateRunnable);
        }
        
        // 创建新的更新任务,延迟执行以合并更新
        updateRunnable = new Runnable() {
            @Override
            public void run() {
                // 更新LiveData
                userLiveData.setValue(pendingUser);
                updateRunnable = null;
            }
        };
        
        // 延迟100ms执行更新,合并短时间内的多次更新
        handler.postDelayed(updateRunnable, 100);
    }
}

9.3 使用生成的BR类

在通知属性变化时,使用生成的BR类常量可以提高性能。

// 使用BR类常量通知属性变化
public class User extends BaseObservable {
    private String name;
    private int age;
    
    // 获取name属性
    @Bindable
    public String getName() {
        return name;
    }
    
    // 设置name属性并通知变化
    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(BR.name);  // 使用BR类常量
    }
    
    // 获取age属性
    @Bindable
    public int getAge() {
        return age;
    }
    
    // 设置age属性并通知变化
    public void setAge(int age) {
        this.age = age;
        notifyPropertyChanged(BR.age);  // 使用BR类常量
    }
}

9.4 优化RecyclerView性能

通过优化RecyclerView的各种设置,可以提高列表的性能。

// 优化RecyclerView性能
public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding binding;
    private UserViewModel viewModel;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 创建ViewModel
        viewModel = new ViewModelProvider(this).get(UserViewModel.class);
        
        // 创建DataBinding
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        
        // 设置ViewModel到DataBinding
        binding.setViewModel(viewModel);
        
        // 设置生命周期所有者
        binding.setLifecycleOwner(this);
        
        // 初始化RecyclerView
        RecyclerView recyclerView = binding.recyclerView;
        
        // 设置固定大小,提高性能
        recyclerView.setHasFixedSize(true);
        
        // 设置布局管理器
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        
        // 设置ItemAnimator
        DefaultItemAnimator itemAnimator = new DefaultItemAnimator();
        itemAnimator.setAddDuration(300);  // 设置添加动画持续时间
        itemAnimator.setRemoveDuration(300);  // 设置移除动画持续时间
        recyclerView.setItemAnimator(itemAnimator);
        
        // 设置ItemDecoration
        recyclerView.addItemDecoration(new DividerItemDecoration(this, layoutManager.getOrientation()));
        
        // 设置适配器
        recyclerView.setAdapter(viewModel.getAdapter());
    }
}

9.5 使用RecyclerView的预取功能

RecyclerView的预取功能可以提前加载数据,提高滚动性能。

// 使用RecyclerView的预取功能
public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding binding;
    private UserViewModel viewModel;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 创建ViewModel
        viewModel = new ViewModelProvider(this).get(UserViewModel.class);
        
        // 创建DataBinding
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        
        // 设置ViewModel到DataBinding
        binding.setViewModel(viewModel);
        
        // 设置生命周期所有者
        binding.setLifecycleOwner(this);
        
        // 初始化RecyclerView
        RecyclerView recyclerView = binding.recyclerView;
        
        // 设置布局管理器
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        
        // 设置预取距离
        layoutManager.setItemPrefetchEnabled(true);
        layoutManager.setInitialPrefetchItemCount(10);  // 设置初始预取数量
        
        recyclerView.setLayoutManager(layoutManager);
        
        // 设置适配器
        recyclerView.setAdapter(viewModel.getAdapter());
    }
}

9.6 使用ViewHolder缓存

ViewHolder缓存可以减少View的创建和销毁,提高性能。

// 使用ViewHolder缓存
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserViewHolder> {
    private List<User> users = new ArrayList<>();
    
    // 设置用户列表
    public void setUsers(List<User> users) {
        this.users = users;
        notifyDataSetChanged();
    }
    
    @NonNull
    @Override
    public UserViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // 使用DataBindingUtil.inflate方法创建Item布局的绑定类
        ItemUserBinding binding = ItemUserBinding.inflate(
                LayoutInflater.from(parent.getContext()), parent, false);
        return new UserViewHolder(binding);
    }
    
    @Override
    public void onBindViewHolder(@NonNull UserViewHolder holder, int position) {
        // 获取当前位置的用户
        User user = users.get(position);
        
        // 设置用户到绑定类
        holder.binding.setUser(user);
        
        // 执行挂起的绑定,确保数据立即更新到视图
        holder.binding.executePendingBindings();
    }
    
    @Override
    public int getItemCount() {
        return users.size();
    }
    
    // ViewHolder类
    public static class UserViewHolder extends RecyclerView.ViewHolder {
        private ItemUserBinding binding;
        
        public UserViewHolder(@NonNull ItemUserBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }
    }
}

9.7 使用RecyclerView的缓存池

RecyclerView的缓存池可以重用ViewHolder,减少View的创建和销毁。

// 使用RecyclerView的缓存池
public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding binding;
    private UserViewModel viewModel;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 创建ViewModel
        viewModel = new ViewModelProvider(this).get(UserViewModel.class);
        
        // 创建DataBinding
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        
        // 设置ViewModel到DataBinding
        binding.setViewModel(viewModel);
        
        // 设置生命周期所有者
        binding.setLifecycleOwner(this);
        
        // 初始化RecyclerView
        RecyclerView recyclerView = binding.recyclerView;
        
        // 设置布局管理器
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        
        // 设置缓存大小
        recyclerView.setItemViewCacheSize(20);  // 设置缓存大小为20个ViewHolder
        
        // 设置RecycledViewPool
        RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();
        viewPool.setMaxRecycledViews(0, 20);  // 设置类型0的最大缓存数量为20
        recyclerView.setRecycledViewPool(viewPool);
        
        // 设置适配器
        recyclerView.setAdapter(viewModel.getAdapter());
    }
}

9.8 使用ItemViewCacheSize

通过设置RecyclerView的ItemViewCacheSize,可以缓存更多的ViewHolder,减少布局计算。

// 设置ItemViewCacheSize
public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding binding;
    private UserViewModel viewModel;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 创建ViewModel
        viewModel = new ViewModelProvider(this).get(UserViewModel.class);
        
        // 创建DataBinding
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        
        // 设置ViewModel到DataBinding
        binding.setViewModel(viewModel);
        
        // 设置生命周期所有者
        binding.setLifecycleOwner(this);
        
        // 初始化RecyclerView
        RecyclerView recyclerView = binding.recyclerView;
        
        // 设置布局管理器
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        
        // 设置ItemViewCacheSize
        recyclerView.setItemViewCacheSize(20);  // 缓存20个ViewHolder
        
        // 设置适配器
        recyclerView.setAdapter(viewModel.getAdapter());
    }
}

9.9 使用setHasStableIds

通过设置setHasStableIds(true),可以提高RecyclerView的性能。

// 使用setHasStableIds
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserViewHolder> {
    private List<User> users = new ArrayList<>();
    
    public UserAdapter() {
        setHasStableIds(true);  // 设置稳定的ID
    }
    
    // 设置用户列表
    public void setUsers(List<User> users) {
        this.users = users;
        notifyDataSetChanged();
    }
    
    @NonNull
    @Override
    public UserViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // 使用DataBindingUtil.inflate方法创建Item布局的绑定类
        ItemUserBinding binding = ItemUserBinding.inflate(
                LayoutInflater.from(parent.getContext()), parent, false);
        return new UserViewHolder(binding);
    }
    
    @Override
    public void onBindViewHolder(@NonNull UserViewHolder holder, int position) {
        // 获取当前位置的用户
        User user = users.get(position);
        
        // 设置用户到绑定类
        holder.binding.setUser(user);
        
        // 执行挂起的绑定,确保数据立即更新到视图
        holder.binding.executePendingBindings();
    }
    
    @Override
    public int getItemCount() {
        return users.size();
    }
    
    @Override
    public long getItemId(int position) {
        // 返回稳定的ID
        return users.get(position).getId();
    }
    
    // ViewHolder类
    public static class UserViewHolder extends RecyclerView.ViewHolder {
        private ItemUserBinding binding;
        
        public UserViewHolder(@NonNull ItemUserBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }
    }
}

9.10 使用AsyncDifferConfig

使用AsyncDifferConfig可以在后台线程计算差异,避免阻塞主线程。

// 使用AsyncDifferConfig
public class UserAdapter extends ListAdapter<User, UserAdapter.UserViewHolder> {
    // 创建DiffUtil.ItemCallback实例
    private static final DiffUtil.ItemCallback<User> DIFF_CALLBACK = new DiffUtil.ItemCallback<User>() {
        @Override
        public boolean areItemsTheSame(@NonNull User oldItem, @NonNull User newItem) {
            // 判断是否是同一个用户(通过ID比较)
            return oldItem.getId() == newItem.getId();
        }
        
        @Override
        public boolean areContentsTheSame(@NonNull User oldItem, @NonNull User newItem) {
            // 判断两个用户的内容是否相同
            return oldItem.getName().equals(newItem.getName()) &&
                    oldItem.getAge() == newItem.getAge();
        }
    };
    
    // 构造方法
    public UserAdapter() {
        super(new AsyncListDifferConfig.Builder<User>(DIFF_CALLBACK)
                .setBackgroundThreadExecutor(Executors.newSingleThreadExecutor())  // 设置后台线程执行器
                .build());
    }
    
    @NonNull
    @Override
    public UserViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // 使用DataBindingUtil.inflate方法创建Item布局的绑定类
        ItemUserBinding binding = ItemUserBinding.inflate(
                LayoutInflater.from(parent.getContext()), parent, false);
        return new UserViewHolder(binding);
    }
    
    @Override
    public void onBindViewHolder(@NonNull UserViewHolder holder, int position) {
        // 获取当前位置的用户
        User user = getItem(position);
        
        // 设置用户到绑定类
        holder.binding.setUser(user);
        
        // 执行挂起的绑定,确保数据立即更新到视图
        holder.binding.executePendingBindings();
    }
    
    // ViewHolder类
    public static class UserViewHolder extends RecyclerView.ViewHolder {
        private ItemUserBinding binding;
        
        public UserViewHolder(@NonNull ItemUserBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }
    }
}

十、双向数据绑定

10.1 双向数据绑定概述

双向数据绑定允许数据的变化自动更新到UI,同时UI的变化也能自动更新到数据。

<!-- 双向数据绑定示例 -->
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="user"
            type="com.example.User" />
    </data>
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={user.name}" /> <!-- 使用@={}语法实现双向绑定 -->
            
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{user.name}" /> <!-- 单向绑定 -->
    </LinearLayout>
</layout>

10.2 实现双向数据绑定

下面是一个实现双向数据绑定的完整示例。

// 支持双向数据绑定的User类
public class User extends BaseObservable {
    private ObservableField<String> name = new ObservableField<>();
    private ObservableInt age = new ObservableInt();
    
    // 获取name属性
    public ObservableField<String> getName() {
        return name;
    }
    
    // 设置name属性
    public void setName(String name) {
        this.name.set(name);
    }
    
    // 获取age属性
    public ObservableInt getAge() {
        return age;
    }
    
    // 设置age属性
    public void setAge(int age) {
        this.age.set(age);
    }
}
<!-- 双向数据绑定布局 -->
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="user"
            type="com.example.User" />
    </data>
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="16dp">
        
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Enter name"
            android:text="@={user.name}" /> <!-- 双向绑定到name属性 -->
            
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Enter age"
            android:inputType="number"
            android:text="@={String.valueOf(user.age)}" /> <!-- 双向绑定到age属性 -->
            
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:text="Name: @{user.name}" />
            
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Age: @{String.valueOf(user.age)}" />
    </LinearLayout>
</layout>
// 在Activity中使用双向数据绑定
public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding binding;
    private User user;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 创建DataBinding
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        
        // 创建User对象
        user = new User();
        user.setName("John Doe");
        user.setAge(30);
        
        // 设置User到DataBinding
        binding.setUser(user);
        
        // 设置生命周期所有者
        binding.setLifecycleOwner(this);
    }
}

10.3 自定义双向数据绑定属性

除了内置的双向绑定属性,还可以自定义双向绑定属性。

// 自定义双向数据绑定适配器
public class BindingAdapters {
    // 自定义双向绑定属性
    @InverseBindingAdapter(attribute = "android:text", event = "android:textAttrChanged")
    public static String getText(EditText view) {
        return view.getText().toString();
    }
    
    // 设置文本变化监听器
    @BindingAdapter(value = {"android:text", "android:textAttrChanged"}, requireAll = false)
    public static void setText(EditText view, String text, final InverseBindingListener listener) {
        // 如果文本不同,则设置新文本
        if (!view.getText().toString().equals(text)) {
            view.setText(text);
        }
        
        // 设置文本变化监听器
        view.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                // 不需要实现
            }
            
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                // 不需要实现
            }
            
            @Override
            public void afterTextChanged(Editable s) {
                // 通知文本已变化
                listener.onChange();
            }
        });
    }
}

10.4 在RecyclerView中使用双向数据绑定

在RecyclerView中也可以使用双向数据绑定。

<!-- 列表项布局 -->
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="user"
            type="com.example.User" />
    </data>
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="16dp">
        
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Enter name"
            android:text="@={user.name}" /> <!-- 双向绑定到name属性 -->
            
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Enter age"
            android:inputType="number"
            android:text="@={String.valueOf(user.age)}" /> <!-- 双向绑定到age属性 -->
    </LinearLayout>
</layout>
// 在RecyclerView适配器中使用双向数据绑定
public class UserAdapter extends ListAdapter<User, UserAdapter.UserViewHolder> {
    // 创建DiffUtil.ItemCallback实例
    private static final DiffUtil.ItemCallback<User> DIFF_CALLBACK = new DiffUtil.ItemCallback<User>() {
        @Override
        public boolean areItemsTheSame(@NonNull User oldItem, @NonNull User newItem) {
            // 判断是否是同一个用户(通过ID比较)
            return oldItem.getId() == newItem.getId();
        }
        
        @Override
        public boolean areContentsTheSame(@NonNull User oldItem, @NonNull User newItem) {
            // 判断两个用户的内容是否相同
            return oldItem.getName().get().equals(newItem.getName().get()) &&
                    oldItem.getAge().get() == newItem.getAge().get();
        }
    };
    
    // 构造方法
    public UserAdapter() {
        super(DIFF_CALLBACK);
    }
    
    @NonNull
    @Override
    public UserViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // 使用DataBindingUtil.inflate方法创建Item布局的绑定类
        ItemUserBinding binding = ItemUserBinding.inflate(
                LayoutInflater.from(parent.getContext()), parent, false);
        return new UserViewHolder(binding);
    }
    
    @Override
    public void onBindViewHolder(@NonNull UserViewHolder holder, int position) {
        // 获取当前位置的用户
        User user = getItem(position);
        
        // 设置用户到绑定类
        holder.binding.setUser(user);
        
        // 执行挂起的绑定,确保数据立即更新到视图
        holder.binding.executePendingBindings();
    }
    
    // ViewHolder类
    public static class UserViewHolder extends RecyclerView.ViewHolder {
        private ItemUserBinding binding;
        
        public UserViewHolder(@NonNull ItemUserBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }
    }
}