【问题标题】:Change language on the fly in Android app writen in Xamarin with MvvmCross使用 MvvmCross 在 Xamarin 中编写的 Android 应用程序中即时更改语言
【发布时间】:2019-02-05 19:38:15
【问题描述】:

我在 .NET Standard 库(Core 项目)中有一个包含 MvvmCross 6.1.2 和 Resx 资源的 Xamarin.Android 项目。

tl;dr:我想在不重启应用的情况下更改应用设置中的语言。当前的方法需要在多次切换后重新启动应用或由于高内存使用导致应用崩溃。

过得怎么样

到目前为止,我一直在使用自定义 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 绑定来显示翻译后的术语。为了在 Android 上更改语言,我还在我的 BaseActivity 中调用了 Recreate()。然而,这导致了某种性能问题。在进行了几次这样的语言切换后,应用程序变得异常缓慢,并且由于内存消耗高而崩溃。似乎正在重新创建视图模型和视图,但旧的视图模型保留在后台。

我还尝试了在values 目录中使用strings.xml 文件的官方方法,但语言更改仅在Recreate() 调用或重新启动应用程序后可见。

现在怎么样了

然后我放弃了Recreate() 方法,而是尝试在语言更改后刷新 Android 视图。不幸的是,这涉及到几个问题:

  • 我不得不将 MvxLang 绑定替换为更通用的绑定以更新属性更改,即 local:MvxBind="Text Language(TextSource, 'translated_term')"MvxLang 仅适用于 OneTime
  • 我不得不在BaseViewModel 中致电RaiseAllPropertiesChanged()
  • 仍然只有当前活动被更新,例如标签栏和其他活动和片段仍使用以前的语言

现在只有重启应用才能使用不同语言的应用。

我想要什么

我希望能够在不重新启动应用程序的情况下更新 Android 视图,或者我希望使用 Recreate() 调用而不会使内存泛滥(即处置旧视图和视图模型或重用它们)。有什么合适的方法可以实现吗?

【问题讨论】:

    标签: android xamarin xamarin.android internationalization mvvmcross


    【解决方案1】:

    您需要做的是在所有仍然存在的 ViewModel 上调用 RaiseAllPropertiesChanged。这是执行此操作的一种方法:

    创建一条消息,当在您的 AppLanguageService 中调用 ChangeLocally 时将广播该消息:

    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)));
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-03
      • 1970-01-01
      • 2013-12-19
      • 1970-01-01
      • 1970-01-01
      • 2015-06-19
      相关资源
      最近更新 更多