Skip to content

Commit 3c354b9

Browse files
committed
Merge pull request pullrequest#13 from johanpoirier/master
New article on RoboGuice 2.0
2 parents 903a80f + b1ffb02 commit 3c354b9

File tree

1 file changed

+223
-0
lines changed

1 file changed

+223
-0
lines changed
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
---
2+
layout: post
3+
title: RoboGuice 2.0
4+
author: johanpoirier
5+
tags: [roboguice, google, guice, di, ioc, android, framework]
6+
---
7+
8+
Dans le cadre de mon étude des divers frameworks pour le développement java sur Android (voir mes articles précedents : [Tour d'horizon des frameworks pour Android](http://pullrequest.org/2012/02/29/tour-d-horizon-des-frameworks-java-pour-android.html) et [ORMLite pour Android](http://ormlite.com/sqlite_java_android_orm.shtml)), et après avoir introduit ORMLite pour Android dans mon application démo (à voir [ici](https://github.com/johanpoirier/Android-Booking-Demo) sur Github), j'ai ajouté le framework **RoboGuice** dans sa version 2.0. [RoboGuice](http://code.google.com/p/roboguice/) est un framework d'injection de dépendance basé sur le fameux Google Guice 3.0 et adapté pour les besoins d'Android.
9+
10+
<p class="center">
11+
<img src="http://roboguice.googlecode.com/files/roboguice.png" border="0" width="220" />
12+
</p>
13+
14+
15+
## L'injection de dépendances
16+
17+
L'injection dans RoboGuice (et Google Guice) se fait via la description du graph de dépendances. Cela se fait via la déclaration de modules :
18+
19+
{% highlight java %}
20+
// Main module for the app
21+
public class BookingModule extends AbstractModule {
22+
23+
private Context context;
24+
25+
public BookingModule(Context context) {
26+
this.context = context;
27+
}
28+
29+
@Override
30+
protected void configure() {
31+
bind(UserDao.class).toProvider(new DaoProvider<User, UserDao>(OpenHelperManager.getHelper(context, DatabaseHelper.class).getConnectionSource(), User.class));
32+
bind(HotelDao.class).toProvider(new DaoProvider<Hotel, HotelDao>(OpenHelperManager.getHelper(context, DatabaseHelper.class).getConnectionSource(), Hotel.class));
33+
bind(BookingDao.class).toProvider(new DaoProvider<Booking, BookingDao>(OpenHelperManager.getHelper(context, DatabaseHelper.class).getConnectionSource(), Booking.class));
34+
bind(BookingService.class).to(BookingServiceImpl.class);
35+
}
36+
}
37+
{% endhighlight %}
38+
39+
Pour faire court, on dit à RoboGuice quels sont nos "beans" à instancier et comment les instancier.
40+
Pour qu'Android connaisse nos modules, il faut lui indiquer où les chercher via un seul fichier de configuration XML **roboguice.xml** situé dans res/values :
41+
42+
{% highlight xml %}
43+
<resources>
44+
<string-array name="roboguice_modules">
45+
<item>org.pullrequest.android.bookingnative.module.BookingModule</item>
46+
</string-array>
47+
</resources>
48+
{% endhighlight %}
49+
50+
51+
### La configuration : les "bindings"
52+
53+
Dans l'exemple précédent, nous pouvons voir deux types de binding différents (et les plus courrament utilisés) :
54+
55+
- Les **linked bindings** : on lie une interface à une implémation
56+
- Les **provider bindings** : un provider lie une interface à une instance selon certains paramètres
57+
58+
{% highlight java %}
59+
// DAO provider for ORMLite
60+
public class DaoProvider<T, D extends Dao<T, ?>> implements Provider<D> {
61+
protected ConnectionSource conn;
62+
protected Class<T> clazz;
63+
64+
public DaoProvider(ConnectionSource conn, Class<T> clazz) {
65+
this.conn = conn;
66+
this.clazz = clazz;
67+
}
68+
69+
@Override
70+
public D get() {
71+
try {
72+
D dao = DaoManager.createDao(conn, clazz);
73+
return dao;
74+
} catch (SQLException e) {
75+
e.printStackTrace();
76+
return null;
77+
}
78+
}
79+
}
80+
{% endhighlight %}
81+
82+
Dans l'exemple ci-dessus, nous avons besoin d'un provider pour créer nos DAOs car ORMLite nous fournit une fabrique de DAO. Le provider prend simplement la source de connexion à la bdd et la classe de l'objet du modèle pour générer le DAO correspondant (UserDaoImpl) et le lier à l'interface en question (UserDao). Nous ne pouvons pas utiliser un linked binding ici car la ConnectionSource ne peut pas être injectée.
83+
84+
Vous trouverez toute la documentation sur les bindings sur le site de [Google Guice](http://code.google.com/p/google-guice/wiki/Bindings).
85+
86+
87+
### L'utilisation dans nos classes
88+
89+
Pour que l'injection ait lieu, il faut que l'injector de RoboGuice soit appelé. Nous pouvons distinguer 3 cas de figures :
90+
91+
#### L'injection dans les "beans" déjà pris en charge par RoboGuice
92+
93+
{% highlight java %}
94+
// Main service for the app
95+
public class BookingServiceImpl implements BookingService {
96+
97+
@Inject
98+
private UserDao userDao;
99+
100+
@Inject
101+
private BookingDao bookingDao;
102+
103+
@Inject
104+
private HotelDao hotelDao;
105+
106+
...
107+
}
108+
{% endhighlight %}
109+
110+
BookingServiceImpl est l'implémentation de BookingService qui est déclaré dans mes modules. Il est donc déjà pris en charge par RoboGuice et l'injection de champs via les **@Inject** est effectué à l'instantiation de celui-ci. D'autres type d'injections sont possibles comme l'injection de constructeurs, de méthodes ou encore l'injection statique (voir la doc [ici](http://code.google.com/p/google-guice/wiki/Injections)).
111+
112+
#### L'injection dans les Activity, Service, AsyncTask et autres classes d'Android
113+
114+
RoboGuice est une version de Google Guice pour Android, il a donc quelques spécificités. Il surcharge donc certaines classes de base du framework de développement natif indispensables à la création d'une application. Pour en citer quelques unes (voir la [liste complète](http://code.google.com/p/roboguice/wiki/InheritingFromRoboGuice)) :
115+
116+
- RoboActivity
117+
- RoboService
118+
- RoboAsyncTask
119+
120+
Les classes surchargées sont donc prises en compte par RoboGuice et l'injection aura donc lieu, comme dans l'exemple suivant :
121+
122+
{% highlight java %}
123+
// Display bookings
124+
public class MyBookings extends RoboActivity {
125+
126+
@Inject
127+
private UserDao userDao;
128+
129+
@InjectView(R.id.buttonHotels)
130+
private Button hotelsButton;
131+
132+
@InjectResource(R.drawable.ic_book_hotel)
133+
private Drawable newContentImg;
134+
135+
...
136+
}
137+
{% endhighlight %}
138+
139+
#### L'injection manuelle
140+
141+
Dans certains cas, il n'est pas possible d'hériter directement d'une classe de RoboGuice et il va falloir appeler l'injecteur manuellement :
142+
143+
{% highlight java %}
144+
// Inject only members, no ui available
145+
@Override
146+
protected void onCreate(Bundle savedInstanceState) {
147+
RoboGuice.getInjector(this).injectMembersWithoutViews(this);
148+
super.onCreate(savedInstanceState);
149+
}
150+
151+
@Override
152+
public void onContentChanged() {
153+
super.onContentChanged();
154+
RoboGuice.getInjector(this).injectViewMembers(this);
155+
}
156+
157+
@Override
158+
protected void onDestroy() {
159+
try {
160+
RoboGuice.destroyInjector(this);
161+
} finally {
162+
super.onDestroy();
163+
}
164+
}
165+
{% endhighlight %}
166+
167+
168+
## Les injections spécifiques à Android
169+
170+
La liste complète est disponible [ici](http://code.google.com/p/roboguice/wiki/ProvidedInjections) mais en voilà quelques exemples :
171+
172+
### La vue de l'activité
173+
174+
{% highlight java %}
175+
// Replaces setContent
176+
@ContentView(R.layout.my_bookings)
177+
public class MyBookings extends RoboActivity {
178+
...
179+
}
180+
{% endhighlight %}
181+
182+
### Les widgets
183+
184+
{% highlight java %}
185+
@InjectView(R.id.hotelsButton)
186+
private Button hotelsButton;
187+
{% endhighlight %}
188+
189+
### Les ressources
190+
191+
{% highlight java %}
192+
@InjectResource(R.drawable.ic_book_hotel)
193+
private Drawable bookHotelImage;
194+
{% endhighlight %}
195+
196+
### Les services systèmes d'Android (WifiManager, LocationManager, ...)
197+
198+
{% highlight java %}
199+
@Inject
200+
private LocationManager locationManager;
201+
{% endhighlight %}
202+
203+
204+
## Les performances
205+
206+
L'utilisation d'un tel framework sur un mobile nous pousse bien évidemment à nus intéresser aux performances. RoboGuice va-t-il pénaliser l'expérience utilisateur de mon application ? et bien... oui et non. Je m'explique :
207+
208+
- **oui** car le temps de démarrage de mon application en a pris un coup (nous allons voir les chiffres juste après)
209+
- **non** car après le démarrage, je n'ai pas vu ni mesuré de latences dans l'utilisation de l'application
210+
211+
En chiffres donc, j'ai utilisé [traceview](http://developer.android.com/guide/developing/debugging/debugging-tracing.html) pour mesurer le temps de démarrage de l'application sur mon Nexus S. J'ai utilisé 2 versions de l'application, une avec RoboGuice et l'autre sans :
212+
213+
- avec : environ 2,2 secondes (dont 1,4s alloué à la création de l'injecteur)
214+
- sans : environ 0,2 seconde
215+
216+
On voit donc qu'au démarrage de l'application, l'instanciation du framework prend quelques secondes si l'application n'est pas en mémoire (pour des utilisations ultérieurs et si le process n'a pas été tué par Android, le démarrage sera quasi immédiat).
217+
218+
219+
## Conclusion
220+
221+
RoboGuice est un très bon framework, qui nous facilite l'écriture de nos applications. Il apporte l'injection de dépendances à laquelle nous sommes tant habitués en tant qu'utilisateur de Spring. [Spring for Android](http://www.springsource.org/spring-android) n'apportant pas cette fonctionnalité, RoboGuice est la meilleure alternative sur Android.
222+
223+
Pourtant l'impact de RoboGuice sur le temps de démarrage de l'application me fait émettre quelques réserves. Tout dépendera de l'utilisation cible de votre application. Si elle doit être utilisée souvent mais pour une durée brève (prendre des notes par exemple), je ne recommande pas RoboGuice. Pour des applications plus complexes et qui nécessitent une utilisation plus longue, quelques secondes de démarrage bien gérées (tout est une histoire de ressenti, n'est-ce pas Apple ?) ne devraient pas poser de problème.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy