2013-07-25 12 views
5

Devo essere in grado di intercettare il framework ed eseguire la re-inizializzazione quando un ViewModel viene ricaricato dalla cache. Poiché il ViewModel non viene ricreato, non posso né utilizzare i metodi Init(), MvxViewModel.InitFromBundle, né MvxViewModel.ReloadFromBundle.MvvmCross ViewModel caching e reinizializzazione

Sto tentando di eseguire il debug di una situazione in cui facendo clic sul pulsante Indietro viene ripristinato un ViewModel con stato incoerente. Una sorta di MvxViewModel.OnReloading() sarebbe d'aiuto.

C'è un modo per farlo in v3?

EDIT:

Si supponga che ho FirstPageViewModel che espone un comando per navigare SecondPageViewModel. In base a ciò che sto osservando, se si fa clic sul pulsante Indietro del simulatore mentre su SecondPageView, FirstPageViewModel non viene creato. Invece, viene recuperato, credo, da qualche cache, quindi legato alla vista. Questa cache è probabilmente un'implementazione della cache IMvxSingleViewModel.

Quindi, il flusso regolare dopo la costruzione di ViewModel, dove si chiama Init(), InitFromBundle() e ReloadFromBundle() non si applica in questo scenario. In altre parole, ho bisogno di un modo per reinizializzare un ViewModel a prescindere dal fatto che sia appena stato appena creato o resuscitato da una cache. Se il primo, posso usare un metodo Init(). Se quest'ultimo è vero, non c'è modo di farlo all'interno del ViewModel stesso.

Questo è il problema:

Ho un'istanza di ICollectionService che è passato da FirstViewModel a SecondViewModel. FirstView contiene anche un controllo ListView associato a questo CollectionService. Poiché CollectionService non è fortemente digitato, posso passarlo e utilizzare il modello di oggetto appropriato per renderizzare i suoi elementi nella vista.

Prima di mostrare SecondViewModel, FirstViewModel recupera alcuni dati remoti e popola CollectionService. Quando viene visualizzato SecondViewModel, la sua vista visualizza i dati da CollectionService utilizzando un modello di elemento diverso. Tuttavia, se si torna indietro, dal momento che FirstViewModel fa ancora riferimento a CollectionService, FirstView eseguirà il rendering dei dati utilizzati da SecondViewModel a meno che FirstViewModel possa essere reinizializzato, cancellando il CollectionService nel processo. Forse l'approccio è sbagliato ma questo è il punto cruciale del mio problema.

Non so se la piattaforma fa la differenza, come mi aspetterei lo stesso comportamento su Windows Phone e iOS poiché questa re-inizializzazione avverrà nel modulo Core. Ciò nonostante sono osservazioni su Android.

TIA.

+0

Non mi è affatto chiaro cosa stai chiedendo, che cos'è "la cache", che cosa è incoerente nel tuo stato, su quale piattaforma o quali piattaforme stai facendo o cosa stai cercando di fare. Un esempio di flusso utente e/o qualche esempio di codice problema potrebbe aiutare. – Stuart

+0

Stuart, grazie per la risposta. Ho appena modificato la mia domanda con informazioni aggiuntive. –

risposta

5

Grazie per l'aggiornamento della tua domanda per fornire molte più informazioni.

L'utilizzo dell'approccio MvvmCross per lo sviluppo multipiattaforma consente di sfruttare le piattaforme dell'interfaccia utente nativa. Ciò significa che tu, lo sviluppatore, hai bisogno di imparare un po 'su queste piattaforme e una delle cose fondamentali da capire è il ciclo di vita della "visualizzazione", anche quando viene utilizzato negli stack di navigazione.

Per impostazione predefinita MvvmCross non memorizza nella cache i modelli di visualizzazione per un periodo di tempo significativo. Ci sono occasionali cache di breve durata che si verificano durante le transizioni dello schermo (ad esempio la rotazione) ma non ci sono cache a lungo termine. Invece, quando viene creata una nuova vista, per impostazione predefinita mvx crea un nuovo viewmodel che la accompagna - e quella coppia resta unita "per tutta la vita" - con la fine della vita determinata dalla vista.

Vorrei incoraggiarvi a dedicare del tempo a leggere i paradigmi di vita e di navigazione di base su ciascuna piattaforma.

  • su iOS questo significa soprattutto imparare a conoscere UINavigationController che mantiene una pila di UIViewControllers in memoria (ciascuno dei quali sarà in mvx essere sposata a un ViewModel individuale)

  • la situazione è simile a Windows Phone con il RootFrame mantiene in RAM una pila di pagine. C'è una complicazione qui - rimozione delle tombe - ma dimenticatene fino a quando non avrete raggiunto il ciclo vitale di base inchiodato.

  • su Android, la situazione è simile, ma leggermente diversa. Per le app di base puoi probabilmente presumere che Android manterrà una pila di pagine di attività nella RAM durante la durata della tua app. Tuttavia, Android è in realtà molto più complesso di così: il sistema operativo può rimuovere gli elementi backstack dalla RAM quando decide di recuperare la memoria. In questi casi c'è un po 'di distacco e disidratazione che a volte ci preoccupa - ma, di nuovo, ti consiglio di ignorarlo fino a quando avrai le basi sotto la cintura.

  • su winrt, per impostazione predefinita la situazione è in realtà ciò che hai capito nella descrizione: il backstack contiene solo informazioni sullo stato - le viste stesse non sono memorizzate nella RAM.

Le storie di cui sopra si spera dare un'idea di vista del ciclo di vita in pile di navigazione su ogni piattaforma - e quindi anche darvi il ciclo di vita ViewModel troppo.


Ora, se si è nella situazione che si desidera che i ViewModels (o alcuni altri oggetti di livello applicazione) di conoscere lo stato di visualizzazione di visibilità, allora avrete bisogno di intercettare alcuni eventi vista su ogni piattaforma e passare questi eventi ai modelli di vista.

Ad esempio, il tuo FirstViewModel potrebbe esporre OnMadeVisible() come Api personalizzato. In tal caso, si potrebbe assicurare questo sono stati chiamati da OnNavigatedTo su Windows, onResume su Android e viewDidAppear su iOS


In alternativa, se siete alla ricerca di meccanismi generali per la comunicazione ViewModel-ViewModel allora vi consiglio si guarda qualcosa come


Nota:

Ovviamente, pile di navigazione non sono l'unico paradigma di navigazione - se la vostra applicazione utilizza anche flyout, schede, splitviews, hamburger, ecc, allora avrete bisogno di capire quelle cicli di vita vista anche.

Se mai siete in dubbio su Vista cicli di vita, quindi l'aggiunta di traccia per i loro costruttori e gli eventi del ciclo di vita chiave è un buon primo passo,


Come nota finale, se si decide la posizione predefinita ViewModel e Il ciclo di vita di viewmodel non è ciò di cui la tua app ha bisogno, ad esempio se vuoi utilizzare i modelli di vista singleton, allora questo può essere facilmente ottenuto - guarda a sovrascrivere il localizzatore del modello di vista nella tua classe App.cs.

+0

Stuart, grazie per la risposta dettagliata. Sto cercando di imparare mentre procedo, quindi questa è una cosa molto utile. Ho letto il ciclo di vita di Andriod Activity fornito al mio Xamarin per acquisire una comprensione di base, ma immagino ci sia di più nella storia. Andriod sembra ricreare attività che sono state allontanate da come il metodo OnCreate viene chiamato ogni volta, anche se il corrispondente ViewModel non viene ricreato. Continuerò a leggere .... grazie. –

+0

"il metodo OnCreate viene chiamato ogni volta, anche se il corrispondente ViewModel non viene ricreato" - non è ciò che dovrebbe accadere. Non c'è motivo di discuterne. Se pensi che ci sia un bug, ti preghiamo di postare un caso riproducibile e di sollevare un problema. – Stuart

+0

Ok, esamineremo questo grazie. Una domanda correlata. Qual è il modello consigliato da ripulire quando un ViewModel viene smaltito? Devo ignorare SaveStateToBundle o implementare IDisposable? Altrimenti, sarebbe una buona idea che MvxViewModel fornisca un metodo virtuale come OnTerminating o qualcosa del genere? –

0

Anche sapendo che questa domanda ha 3 anni, non sono sicuro che ci sia un modo per farlo nella versione attuale, ma l'ho fatto da solo. In questo esempio, creerò una classe statica che contiene tutte le istanze di ViewModels nell'applicazione. Inizia con le variabili statiche nulle e ottiene ogni valore quando ogni ViewModel viene istanziato (sul metodo del costruttore).

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

Questi ViewModels utilizzati come variabili ricevono le istanze quando viene lanciato un costruttore di ogni ViewModel:

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

Il Metodo burnAll() si chiuderanno tutti i ViewModel quando chiamato. È problematico perché quando imposto il tempo che il thread attenderà manualmente, può avere un bug in alcuni dispositivi diversi, deppending sulle sue prestazioni. Ma usando questa classe, puoi fare altre cose, come verificare se un ViewModel è già stato istanziato prima di istanziarne uno nuovo o usare la classe per implementare un metodo OnResume da chiamare quando viene visualizzato nuovamente un ViewModel. Ricorda che un'istanza può essere utilizzata solo quando non è in pausa, vale a dire, puoi solo chiamare i metodi di un ViewModel quando viene utilizzato dall'app.