Изменение языка на лету в Android-приложении, написанном на Xamarin с помощью MvvmCross - PullRequest
0 голосов
/ 05 февраля 2019

У меня есть проект Xamarin.Android с MvvmCross 6.1.2 и ресурсами Resx в стандартной библиотеке .NET ( Базовый проект ).

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, я также звонил Recreate() в моем BaseActivity.Это, однако, вызывало какие-то проблемы с производительностью.После нескольких таких языковых переключений приложение было необычайно медленным и зависало из-за высокого потребления памяти.Кажется, что модели представлений и представления были воссозданы, но старые модели представлений были сохранены в фоновом режиме.

Я также попробовал официальный подход с файлами strings.xml для соответствующих локалей в каталоге values, ноизменение языка было видно только после Recreate() вызова или перезапуска приложения.

Как сейчас

Затем я отказался от Recreate() подхода и вместо этого попытался просто обновить представления Android после смены языка.К сожалению, это было связано с несколькими проблемами:

  • Мне пришлось заменить привязки MvxLang на более общую привязку для обновления при изменении свойства, т. Е. local:MvxBind="Text Language(TextSource, 'translated_term')" (MvxLang только OneTime)
  • Мне пришлось позвонить RaiseAllPropertiesChanged() в BaseViewModel
  • , но только текущее действие было обновлено, и, например, панель вкладок и другие действия и фрагменты остались на предыдущем языке

Только сейчасперезапуск приложения позволяет использовать приложение на другом языке.

Что бы я хотел иметь

Я хотел бы иметь возможность обновлять представления Android без перезапуска приложения, или я бы хотелиспользуйте Recreate() вызов, не заполняя память (т. е. либо удаляя старые виды и просматривая модели, либо используя их повторно).Есть ли какой-нибудь правильный способ достичь этого?

1 Ответ

0 голосов
/ 06 февраля 2019

Что вам нужно сделать, это позвонить RaiseAllPropertiesChanged на все ViewModels, которые еще живы.Вот один из способов сделать это:

Создать сообщение, которое будет передаваться при вызове ChangeLocally in в вашем AppLanguageService:

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