MVVM+DataBinding+RxJava架构下,ViewModel向Activity中RecyclerView传数据的正确方式?
兄弟,这个问题问到点子上了——MVVM的核心就是ViewModel和View彻底解耦,绝对不能让ViewModel持有View引用,所以完全不用像MVP那样搞接口回调那套!咱们靠数据驱动就能完美解决,结合你用的DataBinding和RxJava,给你捋清楚步骤:
1. ViewModel只负责暴露可观察的数据源
ViewModel的职责是处理业务逻辑、获取数据,然后把结果放到一个可被观察的数据容器里——用RxJava的Observable/Subject,或者Android Jetpack的LiveData都可以,完全不用管View怎么处理这些数据。
用RxJava的示例:
public class YourViewModel extends ViewModel { // 用PublishSubject来发送数据列表的更新 private final PublishSubject<List<ItemModel>> itemListSubject = PublishSubject.create(); private final CompositeDisposable disposable = new CompositeDisposable(); private final ItemRepository repo; public YourViewModel(ItemRepository repo) { this.repo = repo; } // 给外部提供订阅的入口 public Observable<List<ItemModel>> getItemListObservable() { return itemListSubject; } // 触发加载数据的方法 public void loadItems() { disposable.add( repo.fetchItemsFromNetwork() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( itemList -> itemListSubject.onNext(itemList), throwable -> { // 这里可以处理错误,比如发送错误状态的Subject Log.e("ViewModel", "加载数据失败", throwable); } ) ); } @Override protected void onCleared() { super.onCleared(); // ViewModel销毁时清理订阅,避免内存泄漏 disposable.dispose(); } }
用LiveData(更贴合Android生命周期)的示例:
public class YourViewModel extends ViewModel { private final MutableLiveData<List<ItemModel>> itemListLiveData = new MutableLiveData<>(); private final CompositeDisposable disposable = new CompositeDisposable(); private final ItemRepository repo; public YourViewModel(ItemRepository repo) { this.repo = repo; } // 对外暴露不可变的LiveData,防止外部修改数据 public LiveData<List<ItemModel>> getItemListLiveData() { return itemListLiveData; } public void loadItems() { disposable.add( repo.fetchItemsFromNetwork() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( itemList -> itemListLiveData.setValue(itemList), throwable -> Log.e("ViewModel", "加载数据失败", throwable) ) ); } @Override protected void onCleared() { super.onCleared(); disposable.dispose(); } }
2. Activity订阅数据源,更新RecyclerView
Activity作为View层,只需要持有ViewModel的引用(通过ViewModelProvider获取),然后订阅ViewModel提供的可观察数据源,当数据变化时直接更新RecyclerView的Adapter即可——全程ViewModel不知道Activity的存在,完全解耦。
RxJava订阅的示例:
public class YourActivity extends AppCompatActivity { private YourViewModel viewModel; private ItemAdapter adapter; private final CompositeDisposable activityDisposable = new CompositeDisposable(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化ViewModel viewModel = new ViewModelProvider(this, new ViewModelProvider.Factory() { @NonNull @Override public <T extends ViewModel> T create(@NonNull Class<T> modelClass) { return (T) new YourViewModel(new ItemRepository()); } }).get(YourViewModel.class); // 初始化RecyclerView和Adapter RecyclerView recyclerView = findViewById(R.id.recycler_view); adapter = new ItemAdapter(); recyclerView.setAdapter(adapter); recyclerView.setLayoutManager(new LinearLayoutManager(this)); // 订阅ViewModel的数据源,更新Adapter activityDisposable.add( viewModel.getItemListObservable() .subscribe(itemList -> { // 如果是用ListAdapter,用submitList更高效 adapter.submitList(itemList); // 普通Adapter的话可以用adapter.setData(itemList)然后notifyDataSetChanged() }, throwable -> { // 显示错误提示,比如Toast Toast.makeText(this, "加载失败", Toast.LENGTH_SHORT).show(); }) ); // 触发数据加载 viewModel.loadItems(); } @Override protected void onDestroy() { super.onDestroy(); // 清理Activity的订阅 activityDisposable.dispose(); } }
LiveData订阅的示例(更省心,自动感知生命周期):
// 替换上面的RxJava订阅部分 viewModel.getItemListLiveData().observe(this, itemList -> { adapter.submitList(itemList); });
3. 结合DataBinding的进阶玩法
如果用DataBinding,还能把ViewModel和布局直接绑定,让数据更新更自动化:
- 在布局的
<data>标签里引入ViewModel:
<layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="viewModel" type="com.yourpackage.YourViewModel" /> </data> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" /> </layout>
- 在Activity里设置DataBinding:
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); binding.setViewModel(viewModel); binding.setLifecycleOwner(this); // 让LiveData能感知生命周期
这样ViewModel的LiveData数据变化时,你只需要在Adapter里监听(或者直接在Activity里绑定),就能自动更新RecyclerView。
为什么不需要MVP的接口?
MVP里用接口是因为Presenter要主动命令View更新,是命令式的;而MVVM是数据驱动——ViewModel只负责生产数据,View通过订阅数据来被动更新,ViewModel完全不知道View的存在,自然不需要接口来传递消息。这种方式让ViewModel的复用性极强,不管是Activity、Fragment还是其他自定义View,只要订阅这个数据源就能用!
内容的提问来源于stack exchange,提问作者stav elmashally

