Xamarin.Forms MvvmCross框架下如何实现指定页面视图持久保活
实现原理说明
MvvmCross的所有页面展示逻辑都由平台专属的View Presenter控制:ViewModel发起展示请求后,Presenter负责实际的View实例创建、挂载、切换、销毁操作。
标签页保活的核心逻辑非常简单:不需要每次切换到对应ViewModel时都新建View实例,首次创建View后把实例缓存起来,后续收到同类型ViewModel的展示请求时,直接把缓存的View切换到前台即可,完全跳过重新渲染流程。
你可以根据业务场景选择两种实现路径:
- 固定标签页场景:给需要保活的ViewModel加标记接口,Presenter直接判断ViewModel是否实现该接口即可,实现成本最低
- 动态页面场景:自定义
MvxPresentationHint,发起导航请求时携带Hint参数,Presenter根据参数判断是否需要保活,灵活度更高
具体实现代码示例
以下为固定标签页场景的完整实现,你的内容较多的标签页ViewModel只需要实现空标记接口即可触发保活逻辑。
公共类定义(跨平台通用)
// 空标记接口,需要保活的ViewModel实现该接口即可 public interface IKeepAliveTabViewModel { } // 你的重内容页面ViewModel示例 public class HeavyContentViewModel : MvxViewModel, IKeepAliveTabViewModel { // 原有ViewModel业务逻辑不变 }
iOS平台实现
自定义Presenter
public class CustomTabBarPresenter : MvxIosViewPresenter { // 缓存字典:Key为ViewModel类型,Value为对应ViewController实例 private readonly Dictionary<Type, UIViewController> _keepAliveViewCache = new(); public CustomTabBarPresenter(IUIApplicationDelegate applicationDelegate, UIWindow window) : base(applicationDelegate, window) { } public override void ShowViewController(UIViewController viewController, MvxViewModelRequest request) { var viewModelType = request.ViewModelType; // 判断当前要展示的ViewModel是否需要保活 if (typeof(IKeepAliveTabViewModel).IsAssignableFrom(viewModelType)) { // 缓存存在直接用缓存实例展示 if (_keepAliveViewCache.TryGetValue(viewModelType, out var cachedVc)) { base.ShowViewController(cachedVc, request); return; } // 缓存不存在则存入后再展示 _keepAliveViewCache[viewModelType] = viewController; } base.ShowViewController(viewController, request); } // 可选:内存警告时可按需清理缓存避免OOM public override void DidReceiveMemoryWarning() { // _keepAliveViewCache.Clear(); base.DidReceiveMemoryWarning(); } }
注册自定义Presenter
在iOS项目的Setup.cs中重写Presenter创建方法:
protected override IMvxIosViewPresenter CreateViewPresenter() { return new CustomTabBarPresenter(ApplicationDelegate, Window); }
Android平台实现
自定义Presenter
public class CustomTabPresenter : MvxAppCompatViewPresenter { // 缓存字典:Key为ViewModel类型,Value为对应Fragment实例 private readonly Dictionary<Type, Fragment> _keepAliveFragmentCache = new(); public CustomTabPresenter(IEnumerable<Assembly> androidViewAssemblies) : base(androidViewAssemblies) { } protected override void ShowFragment(MvxViewModelRequest request, FragmentTransaction transaction, MvxPanePresentationAttribute attribute) { var viewModelType = request.ViewModelType; // 判断当前要展示的ViewModel是否需要保活 if (typeof(IKeepAliveTabViewModel).IsAssignableFrom(viewModelType)) { // 缓存存在直接显示缓存实例 if (_keepAliveFragmentCache.TryGetValue(viewModelType, out var cachedFragment)) { // 隐藏其他Fragment,显示缓存Fragment foreach (var fragment in SupportFragmentManager.Fragments) { if (fragment != cachedFragment) transaction.Hide(fragment); } transaction.Show(cachedFragment); transaction.CommitAllowingStateLoss(); return; } // 缓存不存在则新建并存入缓存 var newFragment = (Fragment)CreateView(request); _keepAliveFragmentCache[viewModelType] = newFragment; transaction.Add(attribute.FragmentContentId, newFragment, viewModelType.Name); transaction.CommitAllowingStateLoss(); return; } base.ShowFragment(request, transaction, attribute); } }
注册自定义Presenter
在Android项目的Setup.cs中重写Presenter创建方法:
protected override IMvxAndroidViewPresenter CreateViewPresenter() { return new CustomTabPresenter(ViewAssemblies); }
注意事项
- 如果保活页面持有大量内存资源,可以监听应用退后台事件,按需清理缓存避免OOM
- 如果需要支持多个同类型ViewModel的保活,可以把缓存Key从
Type改成ViewModel的唯一标识 - 如果切换标签页时需要传递新参数,可以在ViewModel实现
IMvxViewModelParameterized接口,切换时更新参数即可
内容的提问来源于stack exchange,提问作者Laila
相关产品推荐
相关产品推荐

