2013-07-25 3 views
5

Мне нужно уметь перехватывать фреймворк и выполнять такую ​​повторную инициализацию, когда ViewModel перезагружается из кеша. Поскольку ViewModel не воссоздается, я не могу использовать методы Init(), MvxViewModel.InitFromBundle или MvxViewModel.ReloadFromBundle.MvvmCross ViewModel кэширование и повторная инициализация

Я пытаюсь отлаживать ситуацию, когда нажатие на кнопку возврата восстанавливает ViewModel с несогласованным состоянием. Может помочь какой-то MvxViewModel.OnReloading().

Есть ли способ сделать это в v3?

EDIT:

Предположим, у меня есть FirstPageViewModel, который выставляет команду, чтобы перейти к SecondPageViewModel. Основываясь на том, что я наблюдаю, если вы нажмете на кнопку «Назад» симулятора, а на SecondPageView, FirstPageViewModel не сконструирован. Вместо этого он, как мне кажется, извлекается из некоторого кеша, а затем привязывается к представлению. Этот кеш, возможно, представляет собой реализацию кэша IMvxSingleViewModel.

Таким образом, регулярный поток после конструкции ViewModel, где вы вызываете Init(), InitFromBundle() и ReloadFromBundle(), не применяется в этом сценарии. Другими словами, мне нужен способ повторной инициализации ViewModel независимо от того, была ли она только что построена или была воскрешена из кеша. Если первый, я могу использовать метод Init(). Если последнее верно, в самой ViewModel нет способа сделать это.

Это проблема:

У меня есть экземпляр ICollectionService, который передается от FirstViewModel к SecondViewModel. FirstView также содержит ListView, привязанный к этому CollectionService. Поскольку CollectionService не строго типизирован, я могу передать его и использовать соответствующий шаблон элемента для отображения его элементов в представлении.

Прежде чем показывать SecondViewModel, FirstViewModel извлекает некоторые удаленные данные и заполняет CollectionService. Когда SecondViewModel отображается, его представление отображает данные из CollectionService с использованием другого шаблона элемента. Однако, если я вернусь назад, поскольку FirstViewModel все еще ссылается на CollectionService, FirstView будет отображать данные, которые были использованы SecondViewModel, если FirstViewModel не может быть повторно инициализирован, очищая CollectionService в этом процессе. Может быть, подход неправильный, но это суть моей проблемы.

Я не знаю, имеет ли платформа разницу, поскольку я ожидал бы такого же поведения на Windows Phone и iOS, поскольку эта повторная инициализация будет происходить в модуле Core. Тем не менее, это наблюдения на Android.

TIA.

+0

Это совсем не ясно, что вы спрашиваете, что такое «кеш», что непоследовательно в вашем состоянии, на какой платформе вы находитесь или что вы пытаетесь сделать. Примерный поток пользователей и/или некоторые примеры проблемного кода могут помочь. – Stuart

+0

Стюарт, спасибо за ответ. Я только что редактировал свой вопрос с дополнительной информацией. –

ответ

5

Спасибо за обновление вашего вопроса, чтобы предоставить гораздо больше информации.

Использование подхода MvvmCross для кросс-платформенной разработки позволяет использовать собственные платформы пользовательского интерфейса. Это означает, что вам - разработчику - нужно немного узнать об этих платформах, и одним из ключевых моментов, которые нужно понять, является жизненный цикл «вид», в том числе при использовании в стеках навигации.

По умолчанию MvvmCross не кэширует модели просмотра в течение какого-либо значительного периода времени. Бывают случайные кратковременные тайники, которые происходят во время переходов экрана (например, вращение), но больше нет кехов термина. Вместо этого, когда создается новое представление, mvx по умолчанию создает новую модель просмотра, чтобы идти с ней - и эта пара остается вместе «на всю жизнь» - с концом жизни, определяемым точкой зрения.

Я бы посоветовал вам занять некоторое время, чтобы прочитать о базовых жизненных циклах и парадигмах навигации на каждой платформе.

  • на прошивке это означает, в частности изучения UINavigationController, который поддерживает стек UIViewControllers в памяти (каждый из которых будет в MVX быть женатым на индивидуальную ViewModel)

  • ситуация похожа на WindowsPhone с RootFrame поддерживает в ОЗУ стек страниц. Здесь есть сложность - гробница - но забывайте об этом до тех пор, пока вы не наберете основной жизненный цикл.

  • на Android, ситуация похожа, но немного отличается. Для базовых приложений вы можете предположить, что Android будет поддерживать стек страниц активности в ОЗУ во время вашего приложения. Тем не менее, Android на самом деле гораздо сложнее, чем это - ОС может удалять элементы backstack из ОЗУ, когда он решает вернуть память. В этих случаях есть некоторые «гробницы» и обезвоживание, о которых иногда беспокоят, но, опять же, я бы рекомендовал вам проигнорировать это до тех пор, пока у вас не будет оснований под поясом.

  • на winrt, по умолчанию ситуация на самом деле то, что вы поняли в своем описании - в backstack только хранится информация о состоянии - сами представления не кэшируются в ОЗУ.

Вышеприведенные историй, мы надеемся дать вам некоторое представление о жизненном цикле просмотра в навигационных стеков на каждой платформе - и, следовательно, также даст вам жизненный цикл ViewModel тоже.


Теперь, если вы находитесь в ситуации, что вы хотите, чтобы ваши ViewModels (или какие-то другие объекты уровня приложения), чтобы узнать о состоянии зрения видимости, то вам нужно перехватить некоторые просматривать события на каждой платформе и передать эти события в модели просмотра.

Например, ваш FirstViewModel может выставить OnMadeVisible() как пользовательский Api. В этом случае, вы могли бы обеспечить это было вызвано из OnNavigatedTo на Windows, OnResume на Android и ViewDidAppear на прошивке


В качестве альтернативы, если вы смотрите на общих механизмы для ViewModel-ViewModel связи, то я бы порекомендовал вам взглянуть на что-то как


Примечание:

Очевидно, что навигационные стеки не только навигационная парадигмы - если ваше приложение использует Всплывающее меню, вкладки, splitviews, гамбургеры и т.д., то вы должны понимать те просматривать жизненные циклы тоже.

Если бы вы сомневаетесь Посмотреть жизненный цикл, а затем добавить след в их конструкторы и ключевых события жизненного цикла является хорошим первым шагом,


В качестве последнего замечания, если вы решите местоположение по ViewModel по умолчанию и жизненный цикл viewmodel - это не то, что нужно вашему приложению - например, если вы хотите использовать одномодовые режимы просмотра, тогда это можно легко достичь - посмотрите на переопределение локатора представлений в классе App.cs.

+0

Стюарт, спасибо за подробный ответ. Я пытаюсь учиться, когда я иду, так что это очень полезный материал. Я прочитал жизненный цикл деятельности Andriod, при условии, что мой Xamarin получит базовое понимание, но я думаю, что в истории есть больше. Кажется, что Andriod воссоздает активности, которые были перемещены, поскольку метод OnCreate вызывается каждый раз, хотя соответствующий ViewModel не воссоздается. Продолжаю читать .... спасибо. –

+0

«Метод OnCreate вызывается каждый раз, хотя соответствующая ViewModel не воссоздается» - это не то, что должно происходить. Нет смысла обсуждать это. Если вы считаете, что есть ошибка, разместите где-нибудь воспроизводимый случай и поднимите вопрос. – Stuart

+0

Хорошо, посмотрим на это спасибо. Связанный с этим вопрос. Каков рекомендуемый шаблон для очистки при удалении ViewModel? Должен ли я переопределять SaveStateToBundle или реализовать IDisposable? В противном случае было бы хорошей идеей для MvxViewModel предоставить виртуальный метод, например, OnTerminating или что-то еще? –

0

Даже зная, что этому вопросу 3 года, я не уверен, есть ли способ сделать это в текущей версии, но я сделал это сам. В этом примере я создам статический класс, содержащий все экземпляры ViewModels в приложении. Он начинается с нулевых статических переменных и получает каждое значение, когда каждый экземпляр ViewModel создается (по методу конструктора).

public static class ViewStackService 
{ 
    //Stack 
    private static exmp1ViewModel exmp1 = null; 
    private static exmp2ViewModel exmp2 = null; 
    private static exmp3ViewModel exmp3 = null; 

    public static void addStackLevel(exmp1ViewModel _parent) 
    { 
     exmp1 = _parent; 
    } 

    public static void addStackLevel(exmp2ViewModel _parent) 
    { 
     exmp2 = _parent; 
    } 

    public static void addStackLevel(exmp3ViewModel _parent) 
    { 
     exmp3 = _parent; 
    } 


    public static async void burnAll() 
    { 

     if (exmp3 != null) 
     { 
      exmp3.DoBackCommand(); 
      await Task.Delay(250); 
      exmp3 = null; 
     } 
     if (exmp2 != null) 
     { 
      //the OnResume method can be implemented here 
      exmp2.DoBackCommand(); 
      await Task.Delay(250); 
      exmp2 = null; 
     } 
     if (exmp1 != null) 
     { 
      //the OnResume method can be implemented here 
      exmp1.DoBackCommand(); 
      await Task.Delay(250); 
      exmp1 = null; 
     } 
    } 
} 

Эти ViewModels, используемые в качестве переменных получить случаи, когда конструктор каждого ViewModel запускается:

public class exmp1ViewModel 
    : MvxViewModel 
{ 
    public exmp3ViewModel(){ 
     ViewStackService.addStackLevel (this); 
    } 
} 

Метод burnAll() будет закрыть все ViewModels при вызове. Это проблематично, потому что, когда я устанавливаю время, когда поток будет ждать вручную, он может иметь ошибку в некоторых разных устройствах, что зависит от его производительности. Но используя этот класс, вы можете сделать некоторые другие вещи, например, проверить, был ли ранее создан экземпляр ViewModel, чтобы создать экземпляр нового или использовать класс для реализации метода OnResume, который будет вызываться, когда снова отображается ViewModel. Просто имейте в виду, что экземпляр можно использовать только тогда, когда он не приостановлен, т. Е. Вы можете вызывать методы ViewModel, только когда он используется приложением.

Смежные вопросы