如何在Xamarin Android的MVVM Light架构中运用ViewModel(RecyclerView场景)
Hey there! Let's break down how to implement RecyclerView with MVVM Light in your Xamarin Android PCL project step by step—this will make the architecture's purpose and workflow click for you.
在Xamarin Android PCL中结合MVVM Light实现RecyclerView功能
先搞懂核心逻辑:为什么这么做?
MVVM的核心意义就是解耦UI、业务逻辑和数据:
- RecyclerView所在的Activity/Fragment只负责展示界面、响应用户操作
- ViewModel持有数据、处理业务规则,是UI和数据之间的桥梁
- 服务/接口负责抽象数据获取(比如API、本地数据库),让ViewModel不用关心数据从哪来
这样你的代码会更易维护、易测试,修改某一部分不会牵一发而动全身。
第一步:设计ViewModel与数据模型
首先定义RecyclerView每一项的数据模型:
public class ItemModel { public int Id { get; set; } public string Title { get; set; } public string Description { get; set; } }
然后创建继承自MVVM Light ViewModelBase的ViewModel,用ObservableCollection<ItemModel>来存储列表数据(它会自动通知UI数据变化),同时注入数据服务接口:
public class ItemsViewModel : ViewModelBase { private readonly IItemDataService _itemDataService; private ObservableCollection<ItemModel> _items; public ObservableCollection<ItemModel> Items { get => _items; set => Set(ref _items, value); // MVVM Light的Set方法自动触发PropertyChanged事件 } // 构造函数注入服务接口(依赖倒置,不依赖具体实现) public ItemsViewModel(IItemDataService itemDataService) { _itemDataService = itemDataService; LoadItemsCommand = new RelayCommand(async () => await LoadItemsAsync()); } // 绑定到UI的初始化加载命令 public ICommand LoadItemsCommand { get; } private async Task LoadItemsAsync() { // 调用服务获取数据,ViewModel不用关心数据是从API还是本地来的 var fetchedItems = await _itemDataService.GetItemsAsync(); Items = new ObservableCollection<ItemModel>(fetchedItems); } }
第二步:定义数据服务与接口
先写接口抽象数据获取逻辑,这样你可以轻松替换实现(比如从真实API换成Mock数据):
public interface IItemDataService { Task<List<ItemModel>> GetItemsAsync(); }
然后写具体的服务实现(比如从API获取数据):
public class ItemDataService : IItemDataService { public async Task<List<ItemModel>> GetItemsAsync() { // 这里写实际的API请求逻辑,示例用HttpClient using var client = new HttpClient(); var response = await client.GetAsync("https://your-api-endpoint/items"); response.EnsureSuccessStatusCode(); var jsonContent = await response.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject<List<ItemModel>>(jsonContent); } }
最后在MVVM Light的ViewModelLocator里注册服务和ViewModel,实现依赖注入:
public class ViewModelLocator { static ViewModelLocator() { ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); // 注册服务:接口对应具体实现 SimpleIoc.Default.Register<IItemDataService, ItemDataService>(); // 注册ViewModel SimpleIoc.Default.Register<ItemsViewModel>(); } public ItemsViewModel ItemsViewModel => ServiceLocator.Current.GetInstance<ItemsViewModel>(); public static void Cleanup() { // 清理资源,可选 } }
第三步:实现RecyclerView的UI层
首先写一个能监听ObservableCollection变化的Adapter,这样数据更新时自动刷新RecyclerView:
public class ItemsAdapter : RecyclerView.Adapter, INotifyPropertyChanged { private ObservableCollection<ItemModel> _items; public ObservableCollection<ItemModel> Items { get => _items; set { if (_items != null) { _items.CollectionChanged -= OnItemsCollectionChanged; } _items = value; if (_items != null) { _items.CollectionChanged += OnItemsCollectionChanged; } NotifyDataSetChanged(); } } public ItemsAdapter(ObservableCollection<ItemModel> items) { Items = items; } // 监听集合变化,精准刷新对应位置 private void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { switch (e.Action) { case NotifyCollectionChangedAction.Add: NotifyItemRangeInserted(e.NewStartingIndex, e.NewItems.Count); break; case NotifyCollectionChangedAction.Remove: NotifyItemRangeRemoved(e.OldStartingIndex, e.OldItems.Count); break; case NotifyCollectionChangedAction.Replace: NotifyItemRangeChanged(e.NewStartingIndex, e.NewItems.Count); break; case NotifyCollectionChangedAction.Reset: NotifyDataSetChanged(); break; } } // 实现RecyclerView.Adapter的核心方法 public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType) { var itemView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.item_list_layout, parent, false); return new ItemViewHolder(itemView); } public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position) { var item = Items[position]; var viewHolder = holder as ItemViewHolder; viewHolder.TitleTxt.Text = item.Title; viewHolder.DescTxt.Text = item.Description; } public override int ItemCount => Items?.Count ?? 0; // ViewHolder类 public class ItemViewHolder : RecyclerView.ViewHolder { public TextView TitleTxt { get; } public TextView DescTxt { get; } public ItemViewHolder(View itemView) : base(itemView) { TitleTxt = itemView.FindViewById<TextView>(Resource.Id.titleTxt); DescTxt = itemView.FindViewById<TextView>(Resource.Id.descTxt); } } // INotifyPropertyChanged实现 public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
然后在Activity中绑定ViewModel和RecyclerView:
public class MainActivity : AppCompatActivity { private ItemsViewModel _viewModel; private RecyclerView _recyclerView; private ItemsAdapter _adapter; protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.activity_main); // 通过ViewModelLocator获取ViewModel实例 _viewModel = ViewModelLocator.Instance.ItemsViewModel; // 初始化RecyclerView _recyclerView = FindViewById<RecyclerView>(Resource.Id.recyclerView); _recyclerView.SetLayoutManager(new LinearLayoutManager(this)); // 创建Adapter并绑定ViewModel的Items集合 _adapter = new ItemsAdapter(_viewModel.Items); _recyclerView.SetAdapter(_adapter); // 触发数据加载命令 _viewModel.LoadItemsCommand.Execute(null); } }
第四步:理解各部分的协作流程
- 启动Activity时,通过ViewModelLocator获取ViewModel实例,同时注入数据服务
- 执行
LoadItemsCommand,ViewModel调用数据服务获取数据 - 数据返回后,ViewModel更新
ObservableCollection<ItemModel>,自动通知Adapter - Adapter监听集合变化,刷新RecyclerView展示数据
- 如果后续数据有更新(比如下拉刷新),ViewModel只需要更新
Items集合,UI会自动同步
内容的提问来源于stack exchange,提问作者Venky
相关产品推荐
相关产品推荐

