代码之家  ›  专栏  ›  技术社区  ›  Dominik Roszkowski

使用MvvmCross在Xamarin编写的Android应用程序中动态更改语言

  •  0
  • Dominik Roszkowski  · 技术社区  · 7 年前

    我有一个Xamarin。Android项目中有MvvmCross 6.1.2和Resx资源。NET标准库( 核心项目 ).

    tl;博士: 我想在不重新启动应用程序的情况下更改应用程序中的语言设置。当前的方法需要重新启动应用程序,或者在几个小时后由于高内存使用率导致应用程序崩溃 开关 .

    最近怎么样

    到目前为止,我一直在使用自定义 AppLanguageService 这改变了语言 CultureInfo .

    private void ChangeLocally(string code)
    {
        Settings.ApplicationLanguage = code;
        Strings.Culture = new CultureInfo(code);
        CultureInfo.DefaultThreadCurrentUICulture = Strings.Culture;
        ((MvxResxTextProvider) textProvider).CurrentLanguage = Strings.Culture;
    }
    

    在我的Android布局中,我使用的是 MvxLang 绑定以显示翻译的术语。为了改变安卓系统的语言,我也打了电话 Recreate() 在我的 BaseActivity .然而,这导致了一些性能问题。在两次这样的语言切换之后,应用程序速度异常缓慢,并且由于高内存消耗而崩溃。视图模型和视图似乎正在重新创建,但旧的视图模型仍保留在后台。

    我还尝试了官方的方法 strings.xml 中相应地区的文件 values 目录,但语言更改只有在 重新创建() 呼叫或重新启动应用程序。

    现在怎么样

    然后我放弃了 这个 重新创建() 方法 而是试图 刷新 语言变化后的Android视图。不幸的是,这涉及到几个问题:

    • 我不得不用更通用的绑定替换MvxLang绑定,以便在属性更改时进行更新。 local:MvxBind="Text Language(TextSource, 'translated_term')" ( MvxLang OneTime (仅限)
    • 我必须打电话 RaiseAllPropertiesChanged() 在里面 BaseViewModel
    • 仍然只有当前活动正在更新,例如选项卡栏和其他活动和片段仍保留在以前的语言中

    现在,只有重新启动应用程序才能使用不同语言的应用程序。

    我想要什么

    我希望能够在不重启应用程序的情况下更新Android视图,或者我想使用 重新创建() 调用时不要占用内存(即,处理旧视图和视图模型或重用它们)。有没有合适的方法来实现这一点?

    1 回复  |  直到 7 年前
        1
  •  0
  •   pnavk    7 年前

    你需要做的是打电话 RaiseAllPropertiesChanged 在所有仍处于活动状态的ViewModels上。以下是一种方法:

    创建一条消息,当在AppLanguageService中本地调用ChangeIn时,该消息将被广播:

    public class CultureChangedMessage : MvxMessage
    {
        public CultureInfo CultureInfo { get; private set; }
    
        public CultureChangedMessage(object sender, CultureInfo cultureInfo) : base(sender)
        {
            CultureInfo = cultureInfo;
        }
    }
    

    在BaseViewModel中订阅此消息:

    public class BaseViewModel : MvxViewModel
    {
        private readonly MvxSubscriptionToken _cultureChangedToken;
    
        public BaseViewModel(IMvxMessenger messenger)
        {
            _cultureChangedToken = messenger.Subscribe<CultureChangedMessage>(OnCultureChanged);
        }
    
        private async void OnCultureChanged(CultureChangedMessage cultureChangedMessage)
        {
            await RaiseAllPropertiesChanged();
        }
        ...
    }
    

    每次在AppLanguageService中更改区域性时发布消息:

    private void ChangeLocally(string code)
    {
        Settings.ApplicationLanguage = code;
        Strings.Culture = new CultureInfo(code);
        CultureInfo.DefaultThreadCurrentUICulture = Strings.Culture;
        ((MvxResxTextProvider) textProvider).CurrentLanguage = Strings.Culture;
    
        //let all ViewModels that are active know the culture changed
        Mvx.IoCProvider.Resolve<IMvxMessenger>().Publish<CultureChangedMessage>(new CultureChangedMessage(new CultureInfo(code)));
    }