Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Développer une app Android en 2015

Développer une app Android en 2015

Retour d'expérience chez BlaBlaCar - PAUG 3 mars 2015

Alexandra Tritz

March 03, 2015
Tweet

More Decks by Alexandra Tritz

Other Decks in Programming

Transcript

  1. ButterKnife public class ForgotPasswordActivity extends Activity { @InjectView(R.id.new_password_header) TextView newPasswordHeader;

    @InjectView(R.id.new_password_editText) EditText newPasswordEditText; @InjectView(R.id.confirm_password_editText) EditText confirmPasswordEditText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_forgot_password); ButterKnife.inject(this); // Instead of // newPasswordHeader = (TextView) findViewById(R.id.new_password_header); // …
  2. ButterKnife @Optional @OnClick(R.id.drawer_logout_textView) public void logout() { // ... }

    @Optional @OnClick(R.id.drawer_login_textView) public void login() { // ... } @OnItemSelected(R.id.listView) public void onItemSelected(int position){ // ... }
  3. Universal Image Loader public void displayUser(User user) { ImageLoader.getInstance().displayImage( user.getPictureUrl(),

    userImageView ); // ... } public void displayUser(User user) { ImageLoader.getInstance().displayImage( user.getPictureUrl(), userImageView, options, listener ); // ... }
  4. Merge Adapter public class UpcomingRidesAdapter extends MergeAdapter { private TripOfferAdapter

    driverAdapter; private SeatBookedAdapter seatsBookedAdapter; private TripListAdapter visitedAdapter; public UpcomingRidesAdapter(Context context) { // driver trip offers sub-adapter driverAdapter = new TripOfferAdapter(context); addAdapter(driverAdapter); //booked seats seatsBookedAdapter = new SeatBookedAdapter(context); addAdapter(seatsBookedAdapter); // visited trips sub-adapter visitedAdapter = new TripListAdapter(context); addAdapter(visitedAdapter); } }
  5. Otto public class BusManager { private static BusManager instance; public

    Bus bus; private BusManager() { bus = new Bus(); } public static BusManager getInstance() { if (instance == null) { instance = new BusManager(); } return instance; } }
  6. Otto // Subscribing @Override public void onResume() { super.onResume(); BusManager.getInstance().bus.register(this);

    } @Override public void onPause() { super.onPause(); BusManager.getInstance().bus.unregister(this); } @Subscribe public void onNotificationCountEvent(NotificationCountEvent event) { // Update UI }
  7. Déploiement des traductions Les traductions sont synchronisés sur openl10n Une

    fois éditées elles sont directement déployées en prod (S3)
  8. strings-en.json { "contact.item.text.call_phone": "Call", "contact.item.text.text_phone": "Send a SMS", ... }

    strings-fr.json { "contact.item.text.call_phone": "Appeler", "contact.item.text.text_phone": "Envoyer un SMS", ... }
  9. Values-fr/context.xml <?xml version="1.0" encoding="utf-8"?> <resources> <string name="locale">fr_FR</string> <string name="cur">EUR</string> <bool

    name="show_date_filter_in_settings">false</bool> <bool name="show_using_highways_setting">true</bool> <bool name="is_booking">true</bool> <string name="tagmanager_container_id">GTM-XXXXXX</string> <bool name="can_select_currency">false</bool> </resources> getResources().getString(R.string.locale);
  10. Now

  11. RoboSpice private SpiceManager spiceManager = new SpiceManager(SpiceService.class); @Override protected void

    onStart() { super.onStart(); spiceManager.start(this); } @Override protected void onStop() { spiceManager.shouldStop(); super.onStop(); } spiceManager.execute(spiceRequest, requestListener);
  12. RoboSpice // Request public class MySpiceRequest extends SpiceRequest<T> { public

    MySpiceRequest(Class<T> clazz) { super(clazz); } @Override public T loadDataFromNetwork() throws Exception { // Background process } }
  13. RoboSpice // Listener public class MyRequestListener implements RequestListener<T> { @Override

    public void onRequestFailure(SpiceException spiceException) { } @Override public void onRequestSuccess(T t) { } }
  14. RoboSpice + Retrofit // RetrofitGsonSpiceService public class MyRetrofitSpiceService extends RetrofitGsonSpiceService

    { @Override public void onCreate() { super.onCreate(); addRetrofitInterface(RetrofitInterface.class); } @Override protected String getServerUrl() { return "http://www.base-url.com/"; } }
  15. RoboSpice + Retrofit // Interface: public class GetPublicSessionRequest extends RetrofitSpiceRequest<Session,

    RetrofitInterface> { public GetPublicSessionRequest(Class<Session> clazz, Class<RetrofitInterface> interfaceClass) { super(clazz, interfaceClass); } @Override public Session loadDataFromNetwork() throws Exception { return getService().getPublicSession(); } }
  16. RoboSpice + Retrofit // Callback Interfaces public interface ManagerErrorCallback {

    public void onFailed(BlablacarError error); public void onFailed(List<BlablacarFormError> error); public void onNoNetworkError(); } public interface ManagerCallback<T> extends ManagerErrorCallback { public void onSuccess(T result); }
  17. RoboSpice + Retrofit public class BaseActivity extends Activity implements ManagerErrorCallback

    { // ... } public class SomeActivity extends BaseActivity implements ManagerCallback<T> { // ... }
  18. RoboSpice + Retrofit public class BaseManager<T> implements RequestListener<T> { protected

    ManagerCallback<T> callback; protected SpiceManager spiceManager; protected BaseManager(SpiceManager spiceManager, ManagerCallback<T> callback) { this.spiceManager = spiceManager; this.callback = callback; } @Override public void onRequestFailure(SpiceException spiceException) { // Read exception and call the right callback accordingly // callback.onFailed(BlablacarError error); // callback.onFailed(List<BlablacarFormError> error); // callback.onNoNetworkError(); } @Override public void onRequestSuccess(T result) { callback.onSuccess(result); } protected void execute(RetrofitSpiceRequest request) { spiceManager.execute(request, this); } } BaseManager UserManager TripManager PaymentManager
  19. RoboSpice + Retrofit public class UserManager extends BaseManager { public

    UserManager(SpiceManager spiceManager, ManagerCallback callback) { super(spiceManager, callback); } public void getPublicSession(){ execute(new GetPublicSessionRequest()); } } BaseManager UserManager TripManager PaymentManager
  20. RoboSpice + Retrofit public class SomeActivity extends BaseActivity implements ManagerCallback<Session>

    { private SpiceManager spiceManager = new SpiceManager(MyRetrofitGsonSpiceService.class); private void someMethod(){ // ... UserManager userManager = new UserManager(spiceManager, this); userManager.getPublicSession(); // ... } @Override public void onSuccess(Session result) { } }
  21. public SpiceManager(Class<? extends SpiceService> spiceServiceClass, Boolean withMonitoring) { super(spiceServiceClass); this.isMonitored.set(withMonitoring);

    //AtomicBoolean } @Override public synchronized void start(Context context) { super.start(context); if (this.isMonitored.get()) { MonitoringService.getInstance().start(); } } @Override public synchronized void shouldStop() { super.shouldStop(); if (isMonitored.get()) { MonitoringService.getInstance().stop(); } } Network monitoring
  22. private static AtomicInteger monitoredServiceNumber ; private ConcurrentLinkedQueue<MonitoringData> inMemoryQueue ; public

    synchronized void start() { if ( monitoredServiceNumber.getAndIncrement() > 0) { return; } startMonitoring(); } private void flush() { int size = inMemoryQueue.size(); if (size == 0) { return; } MonitoringData[] monitoringDatas = new MonitoringData[size]; for (int i = 0; i < size; i++) { monitoringDatas[i] = inMemoryQueue.poll(); } MonitoringRequest monitoringRequest = new MonitoringRequest(monitoringDatas); spiceManager.execute(monitoringRequest, new MonitoringListener()); } Network monitoring
  23. protected RestAdapter.Builder createRestAdapterBuilder() { RestAdapter.Builder bbcRestAdapter = new RestAdapter.Builder() .setProfiler(new

    MonitoringProfiler()); return bbcRestAdapter; } public class MonitoringProfiler implements Profiler<Object> { @Override public void afterCall(RequestInformation requestInfo, long elapsedTime, int statusCode, Object beforeCallData) { MonitoringService.getInstance().sendReq(requestInfo, elapsedTime, statusCode); } } Network monitoring
  24. Google+ Group Plus de 150 membres dont une vingtaine de

    très actifs. Des retours chaque semaine sur le fonctionnement produit, des bugs ou des suggestions d’amélioration. Sélection de membres pour tester nos prochaines features.