Conférence donnée au Paris Android User Group du 18/06/2014
Toi, oui, toi, le développeur Android, expert ou débutant, prends ton billet, je t’emmène.
Je te propose un périple au sein du monde du développement Android. Je te parlerai de Design et d'UX, de techniques de dèv, d'asynchronicité et de sécurité, de bonnes pratiques, d'architecture, de librairies, de stratégies réseau... et de bien d'autres choses encore. De tous ces détails qui font qu'une application devient une application d'excellence.
Je te montrerai la rue des pro-tips, l'avenue des bonnes pratiques, les monts d'archis. Tu parcourras avec moi tous ces chemins qui amélioreront ton développement, ta pensée, ta conception, ton application Android.
Et quand, je te ramènerai dans ton port d'origine, les yeux qui brillent tu auras et mettre à jour ton application Android tu iras.
Simple matelot ou capitaine de navire, ne laisse pas passer ce voyage, il t'ouvrira de nouvelles voies du monde Android.
2. Android2EE est référencé en tant qu’organisme de formation, vous pouvez faire prendre en charge tout ou partie du montant de cette
formation par votre OPCA. Cette formation Initiation avancée à Android est éligible au titre du DIF et CIF.
Lieu : Paris, Toulouse, Lyon,
Rennes, Nantes, Lille
Durée : 3 jours
Prix : 1680 €
Lieu : Paris, Toulouse, Lyon,
Rennes, Nantes, Lille
Durée : 5 jours
Prix : 2980 €
Lieu : Paris, Toulouse, Lyon,
Rennes, Nantes, Lille
Durée : 3 jours
Prix : 1780 €
5. 0
10
20
30
40
50
60
70
Telephone Electricity Computer Mobile phone internet Radio Television Smartphone Tablet
Taux de pénétration (G8)
10% time from 10% to 40%
5
Penetration rate to reach 40% of the population for a technology (G8)
•They are still at "the earth is flat"
•Do not know how Android works
•Do not use it
•Want what they already have (IOs)
•Underestimate the complexity
13. 13
2.The native Android mode:
Google Authentification
Benefits:
No password, No Permission needed
Works everywhere with every users,
Real authentification
User have a name
14. 14
3.The Social mode:
Facebook, Twitter and co
Disadvantages:
Need password (sometimes),
Don't work with every users,
Need a social user
Benefits:
Real authentification
User have a name
15. 15
4.The hardcore mode:
OAuth FROM scratch
(hard and bleeding)
Disavantages:
Need password, user name
Hard to code, Hard to maintain
Bleeding
NEED SKILL
Benefits:
Sometimes there is no other choice
16. 16
You user is
Bruce Wayne
Your application behaves as
Alfred or Lucius
Through you
Your user becomes
17. !--Style for TextView-->
<!-- ************************-->
<style name=“mainTxv“ parent="@android:style/TextAppearance">
<item name=“android:textSize“>12sp</item>
<item name=“android:textStyle“>bold</item>
<item name=“android:background“>"@color/background"</item>
<item name=“android:paddingLeft“>3dip</item>
<item name=“android:paddingRight“>3dip</item>
<item name=“android:textColor“> "@color/foreground" </item>
<item name=“android:layout_width“>wrap_content</item>
<item name=“android:layout_height“>wrap_content</item>
</style>
<style name=“mainEdt“ parent="mainTxv">
<item name=“android:textSize“>12sp</item>
<item name=“android:textStyle“>bold</item>
</style>
17
Manage your ressources, they are your best friends: Inherit, redirect, smile
MyBaseTheme
Theme Theme.Holo
MyThemeColorChart RefColors
RefDimensions Style
TxvStyle TxvTitleStyle
EdtStyle
BtnStyle
And so on
TxvWarningStyle
TxvErrorStyle
EdtTitleStyle
EdtWarningStyle
EdtErrorStyle
BtnTitleStyle
BtnWarningStyle
<TextView
style=“@style/ TxvStyle“
android:text=“@string/hello“ />
20. 20
Only code what you need
Focus on main features
Limit features
No generic stuff for future/for fun
No gaz factory for future feature
No complex mechanism for evolutivity
Only load what you need
when you need it
Use ViewsStub
Use Dynamic Fragment
Never use NestedFragments
24. Thread I.H.M Thread de traitement
Activity Handler
sendMessage()
message
Thread I.H.M
Thread de traitement
Activity
sendMessage()
message
Handler
OnDestroy()
OnCreate()
Thread de traitement initiale
sendMessage()
Activity
fantôme
Handler
fantôme
24
Fight against memory leaks
25. 25
Centralize your thread management
/** * The ThreadPool Executor for caching background */
ExecutorService executor = Executors.newFixedThreadPool(6,
new BackgroundThreadFactory());
/** * And its associated factory */
public class BackgroundThreadFactory implements ThreadFactory {
public Thread newThread(Runnable r) {Thread t = new Thread(r);return t;}
}
/** * This method draw the background and store it in a bitmap that can be reused */
public synchronized void cacheBackGround() {
executor.submit(mCacheBackgroundRunnnable);
}
Fight against memory leaks
MyApplication
PoolExecutor
Never let a thread unmanaged:
Use PoolExecutor
Always know when the thread needs to finish and ensure its death
void cleanMemory() {if (executor != null) {
executor.shutdown(); // Disable new tasks from being submitted
try {//as long as your threads hasn't finished
while (!executor.isTerminated()) {
// Wait a while for existing tasks to terminate
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
// Cancel currently executing tasks
executor.shutdownNow();
Log.e("MyApp","Probably a memory leak here");
}
}
} catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
executor.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
Log.e("MyApp","Probably a memory leak here too");
}}}
27. 27
if(Wifi) if(NoWifi) if(NoConnection)
Factory
Implementation
Com
Interface
knows
ask for
real
returns the implementation adapted to the
connection context
MyApplication
Server
Backend
send your com
context
receive
PrefetchData
load
first
cach
after
receive your com
status
Persistence
BootAndWifi Receiever
BigCookies strategy
State Design Pattern
28. 28
Never use nested fragments (launch a new activity instead)
Fragments: Redirect layout and set in stone the number of fragments displayed
•reslayout
activity_a_two_panes_layout.xml (le vrai layout)
activity_a_one_panes_layout.xml (le vrai layout)
layout_redirection.xml
<resources>
<item name="main_activity" type="layout">@layout/activity_one_panes</item>
<bool name="twoPane">false</bool>
</resources>
Dans ActivityA
setContentView(R.layout.main_activity)
•reslayout-land||reslayout-large||reslayout-xlarge
layout_redirection.xml
<resources>
<item name="main_activity" type="layout">@layout/activity_two_panes</item>
<bool name="twoPane">true</bool>
</resources>
getRessource().getBoolean(R.bool.twoPane)
34. 34
Add version to your servlet url
/myservlet_v1.2
MyOnlyObject in Json+GZip
Add timestamp to your data (your database)
Request data based on your timestamp
Use json + gzip
It's on server side that prefetch is done (depending on the connectivity status)
TimeStamp
TimeStamp
/myservlet_v1.2?timespan=11215982/myservlet_v1.2?timespan=11215982&net=wifi
Add you connectivity status in your request
Use the big cookies strategy
Manage your DataBase size.
Never exceed :
SQLiteDataBase.getMaximumSize()
36. 36
And I want to Lazy Load every think
When my app is in foreground I want the max available memory when I need it
When my app goes in background I want to realease my memories
Fuck I am
going in
background
Take that
services !
38. private void launchServiceAsync() {
// load your service...
ServiceManager.instance.getHumanService(new OnServiceCallBack() {
public void onServiceCallBack(MService service) {
// so just call the method you want of your service
((HumanService) service).getHuman("toto");
}});}
the callBack pattern
38
View Model
HumanService
LazyLoading
Services
Manager
Activity
40. IsActivity
Alive
40
The release memory pattern.
Application
View
Services
Manager
onStop
onStart
Runnable mServiceKiller;
Launch it
In1Second
if(false) unbindAndDie()
if false
/** Destructor **/
/** * This method is called by MApplication to unbind all
the services and let them die when your application die */
public synchronized void unbindAndDie() {
// Browse all the services and unbind them all
for (ServiceConnection sConn : boundServices) {
//first unbind the service
unbindService(sConn);}
dService = null;boundServices.clear();}
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
public void onActivityStopped(Activity activity) {isActivityAlive.set(false);}
public void onActivityCreated(Activity activity) {isActivityAlive.set(true);}});
// launch the Runnable mServiceKiller in 1 seconds
getServiceKillerHanlder().postDelayed(getServiceKiller(), 1000);
IsActivity
Alive
41. 41
The release memory principle.
ApplicationServices
Manager
onLowMemory (...)
System
unbindAndDie()
You are lazy loading your services, so you can kill them at any time,
they will be reloaded if needed.
42. 42
every one wants to be asynchronous:
So Views launch Threads,
Services launch Threads,
Com launch Threads,
D.A.O launch Threads,
It gives Thread(Thread(Thread(Thread{Do the work})))
We are at the top !
44. 44
Activty's methods need to be split each time a call to services is done
Services
View Model
doSomething()
{
//code...
Human hum =getHumanService().getHuman("toto");
//other code using hum
txvHumanName.setText(hum.getName());
}
call
Failed
It's asynchronous
What we used to do
before
45. 45
Activty's methods need to be split each time a call to services is done
Services
View Model
doSomething()
{ //code...
getHumanService().getHuman("toto");
}
call
What we need to do now
doSomethingPart2(Human hum)
{
//other code using hum
txvHumanName.setText(hum.getName());
}
async return
Yes
good way
46. 46
Services
Buisness services have to
Finish their threatments
Be instanciate on demand
Persist their instanciation
not follow activities lifecycle but follow application life cycle
47. Keep in LRU if active as
long as possible
47
Services
AndroidServicesSingletonServices
?
System
Need to be launched by the system ?
Need to cach data?
No particular need
Insure unique
instanciation (best to do
that using the
application instead of
static)
48. G.U.I. Thread Background Thread
View Model
ServiceData
DataCom
DataDao
Services
Manager
ServiceUpdater
call
BIND
START
load
return data
Intent|Event
call
return data
Caching
return data
fire
DataUpdateEvent
Intent
ContentObserver
51. Use a library because you have too, not for fun
Less library your project have, better you are
Choose carefully your lib, it's critical, don't mess around
52. 52
Never use annotations at runtime
1 librairy = 1 feature = 1 goal
Don't use library that does too much when you use 1% of it
Don't use unmaintained library
If you can copy/paste the code within your project it's better
because it means it's a simple library that does what it have too without a gaz factory. (But don't copy/paste
code anyway for bug corrections reasons)
54. 54
Use Square Libraries (http://square.github.io/)
Use GooglePlayServices (even if it's beta like)
Use Haptic library (for your user): Immersion (http://www.immersion.com/haptic/sdk)
Use SqlCipher to encrypt your database and your sharedPreferences
Use EventBus, Gson, Jackson, Sax, Dom when needed
Use Crashlytics or ACCRA for bug reporting/tracking
Go and see http://www.androidviews.net/category/libraries/
A lot of View libraries are available
Go and see : Android Project on Github
https://plus.google.com/communities/100609058582053363304
Genymotion instead of native emulators
For librairy without reputation, always check the code
Try not to mix too much librairies (redundency, dependencies conflict)
59. 59
Use GIT
Use Gradle
Do continous integration (Jenkins)
Use the Android Test SDK
Use Robotium || expresso || RoboElectric
Have a look at Rational Mobile (if you are CapGemini)
Use your users (Alpha and Beta channel on PlayStore)
Et pourtant vous en avez besoin, pour sauvegarder leur donner, leur préférences et leur permettre de communiquer entre eux.
Et pourtant vous en avez besoin, pour sauvegarder leur donner, leur préférences et leur permettre de communiquer entre eux.
Vous ne le trahissez pas, vous êtes toujours disponible pour lui, il a confiance en vous, vous lui parlez avec gentillesse et déference tout en étant proche de lui