You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

MVVM+DataBinding环境下Activity中Adapter设置及ViewModel数据填充问题

嘿,刚接触MVVM和DataBinding的话,你的问题绝对是入门阶段最常见的困惑之一,我来一步步帮你捋清楚,保证你能快速上手~

一、先解决Activity中设置Adapter的问题

假设你已经用DataBinding完成了ViewHolder和Adapter的编写,在Activity里设置Adapter的核心逻辑其实和传统方式类似,只是借助DataBinding来简化控件的获取。我先补全你的ScoresActivity代码,带你走一遍流程:

public class ScoresActivity extends AppCompatActivity {
    private ActivityScoresBinding binding; // 自动生成的DataBinding类,对应你的activity_scores.xml布局
    private ScoresAdapter scoresAdapter; // 你已经实现的Adapter类

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initBinding();
        initAdapter();
        // 后面会加入ViewModel的初始化逻辑
    }

    private void initBinding() {
        // 用DataBinding替代传统的setContentView,直接获取布局绑定实例
        binding = DataBindingUtil.setContentView(this, R.layout.activity_scores);
        // 让DataBinding感知Activity生命周期,配合LiveData使用更安全
        binding.setLifecycleOwner(this);
    }

    private void initAdapter() {
        // 1. 创建Adapter实例(如果你的Adapter需要初始数据,也可以在这里传入空列表)
        scoresAdapter = new ScoresAdapter();
        // 2. 绑定Adapter到RecyclerView(通过binding直接访问布局中的RecyclerView,无需findViewById)
        binding.recyclerView.setAdapter(scoresAdapter);
        // 别忘了设置LayoutManager,否则RecyclerView不会显示内容
        binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
    }
}
二、要不要用ViewModel填充ArrayList?当然要!

MVVM的核心就是UI与数据逻辑分离,ViewModel就是专门用来托管数据和业务逻辑的角色,用它来管理你的ArrayList有两大好处:

  1. 解耦:Activity只负责UI展示,数据加载/填充交给ViewModel,代码更清晰
  2. 数据持久化:屏幕旋转等配置变化时,ViewModel会保留数据,不会丢失

下面是具体的实现步骤:

1. 编写ViewModel类,托管可观察数据

我们用LiveData来包装数据列表,因为它能自动感知Activity生命周期,避免内存泄漏:

public class ScoresViewModel extends ViewModel {
    // 用MutableLiveData存储可修改的列表数据,对外暴露不可变的LiveData防止外部篡改
    private final MutableLiveData<List<Score>> scoresLiveData = new MutableLiveData<>();

    public ScoresViewModel() {
        // 初始化数据,这里用模拟数据举例,实际可以替换成网络请求/本地数据库查询
        loadMockScores();
    }

    // 对外提供观察数据的入口
    public LiveData<List<Score>> getScoresLiveData() {
        return scoresLiveData;
    }

    // 模拟填充ArrayList的方法
    private void loadMockScores() {
        List<Score> scoreList = new ArrayList<>();
        scoreList.add(new Score("张三", 95));
        scoreList.add(new Score("李四", 88));
        scoreList.add(new Score("王五", 92));
        // 更新LiveData,通知观察者(也就是Activity)数据变化
        scoresLiveData.setValue(scoreList);
    }

    // 如果是异步加载数据(比如网络请求),要用postValue在子线程更新数据
    public void loadRemoteScores() {
        // 假设这里发起网络请求,请求成功后:
        // scoresLiveData.postValue(remoteScoreList);
    }
}

对应的Score数据实体类(记得写getter方法,DataBinding需要通过getter访问属性):

public class Score {
    private final String name;
    private final int score;

    public Score(String name, int score) {
        this.name = name;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public int getScore() {
        return score;
    }
}

2. 在Activity中关联ViewModel,观察数据变化

修改ScoresActivity,加入ViewModel的初始化和数据观察逻辑:

public class ScoresActivity extends AppCompatActivity {
    private ActivityScoresBinding binding;
    private ScoresAdapter scoresAdapter;
    private ScoresViewModel scoresViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initBinding();
        initViewModel();
        initAdapter();
    }

    private void initBinding() {
        binding = DataBindingUtil.setContentView(this, R.layout.activity_scores);
        binding.setLifecycleOwner(this);
    }

    private void initViewModel() {
        // 通过ViewModelProvider获取ViewModel实例,确保生命周期与Activity绑定
        scoresViewModel = new ViewModelProvider(this).get(ScoresViewModel.class);
        // 观察LiveData的变化,数据更新时通知Adapter
        scoresViewModel.getScoresLiveData().observe(this, scores -> {
            // 调用Adapter的方法更新数据
            scoresAdapter.setScores(scores);
        });
    }

    private void initAdapter() {
        scoresAdapter = new ScoresAdapter();
        binding.recyclerView.setAdapter(scoresAdapter);
        binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
    }
}

3. 让Adapter支持数据更新

你的Adapter需要提供一个更新数据的方法,替换内部的列表并通知RecyclerView刷新:

public class ScoresAdapter extends RecyclerView.Adapter<ScoresAdapter.ScoreViewHolder> {
    private List<Score> scoreList = new ArrayList<>();

    @NonNull
    @Override
    public ScoreViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // 用DataBinding加载Item布局
        ItemScoreBinding binding = ItemScoreBinding.inflate(
                LayoutInflater.from(parent.getContext()),
                parent,
                false
        );
        return new ScoreViewHolder(binding);
    }

    @Override
    public void onBindViewHolder(@NonNull ScoreViewHolder holder, int position) {
        Score score = scoreList.get(position);
        // 把数据绑定到Item的Binding对象
        holder.binding.setScore(score);
        // 立即执行绑定,避免UI更新延迟
        holder.binding.executePendingBindings();
    }

    @Override
    public int getItemCount() {
        return scoreList.size();
    }

    // 对外提供数据更新方法
    public void setScores(List<Score> scores) {
        this.scoreList.clear();
        this.scoreList.addAll(scores);
        // 入门阶段用notifyDataSetChanged即可,进阶可以用DiffUtil提升性能
        notifyDataSetChanged();
    }

    public static class ScoreViewHolder extends RecyclerView.ViewHolder {
        private final ItemScoreBinding binding;

        public ScoreViewHolder(ItemScoreBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }
    }
}
三、额外小提示
  • 如果想让布局直接和ViewModel交互,可以在activity_scores.xml中声明ViewModel变量,不过对于RecyclerView列表,还是通过Adapter处理更灵活。
  • 进阶阶段可以用DiffUtil替代notifyDataSetChanged(),只刷新变化的Item,提升RecyclerView性能。

内容的提问来源于stack exchange,提问作者Riddhi Shah

火山引擎 最新活动