A questo punto hai probabilmente finito il tuo corso, ma nel caso tu stia ancora cercando, o qualcun altro lo è: il rolling di tuo DI è in realtà molto semplice su Android una volta che sai come farlo.
Creazione del grafico delle dipendenze
Di solito inizio con una classe di applicazione personalizzata (non dimenticarti di registrarla nel file manifest di Android), questa classe vivrà per tutto il ciclo di vita della tua app Android ed è da dove il tuo codice può accedere alle sue dipendenze. Qualcosa del genere:
public class CustomApp extends Application {
private static ObjectGraph objectGraph;
@Override
public void onCreate() {
super.onCreate();
objectGraph = new ObjectGraph(this);
}
// This is where your code accesses its dependencies
public static <T> T get(Class<T> s) {
Affirm.notNull(objectGraph);
return objectGraph.get(s);
}
// This is how you inject mock dependencies when running tests
public <T> void injectMockObject(Class<T> clazz, T object) {
objectGraph.putMock(clazz, object);
}
}
(Affirm.notNull () esplode se qualcosa è nullo, non è necessario usarlo). Le dipendenze effettive sono tutte nella classe ObjectGraph che sostanzialmente assomiglia a questo:
class ObjectGraph {
private final Map<Class<?>, Object> dependencies = new HashMap<>();
public ObjectGraph(Application application) {
// Step 1. create dependency graph
AndroidLogger logger = new AndroidLogger();
Wallet wallet = new Wallet(logger);
//... this list can get very long
// Step 2. add models to a dependencies map if you will need them later
dependencies.put(Wallet.class, wallet);
}
<T> T get(Class<T> model) {
Affirm.notNull(model);
T t = model.cast(dependencies.get(model));
Affirm.notNull(t);
return t;
}
<T> void putMock(Class<T> clazz, T object) {
Affirm.notNull(clazz);
Affirm.notNull(object);
dependencies.put(clazz, object);
}
}
Uso
Ora, ovunque ti trovi nella tua app (in un'attività come ad esempio) puoi inserire le tue dipendenze in questo modo:
private Wallet wallet;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
wallet = CustomApp.get(Wallet.class);
//...
}
Puoi usare Dagger in diversi modi, ma l'equivalente di Dagger2 più vicino sarebbe qualcosa del tipo:
AppComponent appComponent = CustomApp.getAppComponent();
Wallet wallet = appComponent.getWallet();
Dipendenze scopate
Ciò che si sta iniettando qui sarebbe una classe con ambito di livello applicazione . Se desideri solo un oggetto ambito locale che esista solo finché tieni un riferimento ad esso nella tua vista o attività, fai esattamente la stessa cosa ma ciò che inietti è una fabbrica classe:
In ObjectGraph:
WalletFactory walletFactory = new WalletFactory(logger);
Nel tuo frammento, ad esempio:
Wallet wallet = CustomApp.get(WalletFactory.class).getNewWallet();
Test
Tutto questo è fatto in modo da poter testare facilmente il codice del tuo livello di vista. Ad esempio, se vuoi eseguire un espresso test, crei l'applicazione, ma prima di mostrare l'attività, sostituisci l'istanza di wallet con un simulatore:
CustomApp.injectMockObject(Wallet.class, mockedWalletWith100Dollars);
Questa è l'istanza del wallet che verrà poi rilevata dal resto del codice durante il test.
In un certo senso questo stile di DI non è flessibile come Dagger2, ma penso che sia molto più chiaro - semplicemente non c'è bisogno di complicare DI ma è in realtà una cosa abbastanza basilare. Questo stile si traduce spesso in piastre di riscaldamento meno rispetto all'utilizzo di un framework DI (una volta incluse le classi di componenti e moduli).
Esempi completi
Ho scritto qualcosa di simile per 5 app di esempio come parte di un framework che ho pubblicato (volendo mantenere gli esempi il più accessibili possibile - non a tutti piace Dagger). Puoi vedere gli esempi completi qui: link