Architettura disaccoppiata in Android

4

Sto costruendo un'app per Android che avrà più origini dati a seconda di chi lo sta utilizzando. L'architettura N-tier con un pattern di repository sembra il modo giusto per farlo, ma sto cercando di attenermi ad alcune regole di base.

Da quello che ho capito dovrei essere in grado di scrivere il BL senza sapere realmente nulla sull'interfaccia utente o sul DAL. Il mio problema è che una volta iniziato a scrivere il livello dell'interfaccia utente ho capito che ho bisogno del DAL per funzionare su un thread in background. Questo mi obbliga a modificare il mio BL / DAL per eseguire asincroni w / callback in base a un requisito del livello dell'interfaccia utente che urla "NO" a me.

Ecco i 4 livelli che ho adesso e le loro dipendenze.

UI - dipendenze su BL e Common / Repository = Attività / frammenti Android. UI Layer dirà al BL quale tipo di repository / DAL concreto usare

BL - dipendenze su interfacce Common / Repository = Pacchetto separato con regole aziendali. Usa il repository concreto che è stato passato dal livello dell'interfaccia utente per fare cose

Comune / Repository - nessuna dipendenza = Pacchetto separato con modelli e interfacce che consente a tutti gli altri livelli di interagire senza conoscersi l'un l'altro. E 'anche considerato uno strato? I modelli dovrebbero essere classi o interfacce concrete?

DAL - dipendenze dal pacchetto Common / Repository = Pacchetto separato con le implementazioni concrete dei repository. Se Common non ha modelli concreti, ogni strato deve avere i propri modelli concreti per creare oggetti da passare tra i livelli?

Cosa mi manca? Sto cercando di forzarmi a uscire dalla mia zona di comfort su questo :)

    
posta LukeP 31.08.2015 - 20:14
fonte

1 risposta

1

Su Android, la risposta canonica a questo è usare una combinazione di attività, frammenti, adattatori, caricatori e servizi.

Nel mio progetto siamo piuttosto severi su come facciamo le cose. Le attività vengono utilizzate per impostare la vista di base, che di solito è solo un FrameLayout o qualcosa di simile. Non abbiamo alcuna logica dell'interfaccia utente. Un'attività è appena usata per collegare tutto. L'interfaccia utente è gestita da Fragments (tranne alcuni frammenti speciali che trattiamo come un'attività). Le letture di rete sono tutte eseguite in Loader e utilizziamo gli adattatori per inviare i dati all'interfaccia utente. Gli adattatori sono di proprietà dei frammenti, ma l'attività li collega ai caricatori con i callback. I servizi vengono utilizzati per le scritture di rete.

Questa configurazione richiede una quantità di tempo abbastanza decente per configurare l'infrastruttura e sviluppare il flusso di lavoro di base, ma una volta che hai un modello funzionante, puoi semplicemente farti strada attraverso il resto. Desideri un pulsante di azione mobile, includi solo il frammento corretto e le classi di base gestiscono il boilerplate.

Quindi alla fine è più uno stack MVP che un MVC. Le nostre opinioni sono consapevoli di ciò che un utente sta tentando di fare e lo indicano tramite interfacce. Ecco un tipico flusso di lavoro:

L'utente sta guardando una cosa e vuole votarla. Il frammento che contiene il pulsante upvote cattura il clic. Innanzitutto aggiorna il conteggio dei voti localmente al nuovo valore atteso. Nota che questo non è ufficiale, e non è persistito da nessuna parte. Migliora la latenza nel caso più comune in cui il voto non è cambiato. Getta il genitore (Activity o Fragment) su un'interfaccia con un metodo upvote() e lo chiama. L'attività (o frammento) riceve la chiamata upvote e la inoltra al servizio, con una richiamata. Il servizio mette l'azione in una coda (noi le scritture a thread singolo) e infine chiama l'API. L'API restituisce il nuovo numero di voti. Il servizio chiama il callback, che viene instradato nel caricatore. Il caricatore aggiorna la sezione pertinente del modello e quindi segnala all'adapter che sono disponibili nuovi dati, che l'interfaccia utente quindi preleva e mostra. Nota che se è troppo difficile applicare una patch al modello, Loader potrebbe semplicemente richiederne la richiesta.

Quindi è un bel boccone, ma la nostra logica è separata, l'intera UI è costruita tramite la composizione, i componenti sono tutti altamente testabili, e di solito è abbastanza facile rintracciare cosa è successo quando c'è un bug.

    
risposta data 08.12.2015 - 07:51
fonte

Leggi altre domande sui tag