SlideShare a Scribd company logo
1 of 81
@android2ee
by(MathiasSeguy ==Android2EE){
French AndroidTrainer}
Europe / Africa / US
MVP ou MVVM
n-tiers
Architecture: Goals
Simplicity
Tests
SplittingMaintenance
EvolutionConcern
Unit Tests Integration Tests Fonctionnal Tests
Robustness
A piece of History
public class HistoryBattleActivity extends AppCompatActivity {
private static final String TAG = "HistoryBattleActivity";
private static final int CONTEXT_CURRENT=110274;
private static final int CONTEXT_HISTORY=131274;
/***********************************************************
* Attributes
**********************************************************/
BattleFragment battleFragment;
/**
* Current context History/current
*/
int currentContext=CONTEXT_CURRENT;
/***********************************************************
* Managing RoundTrip animation (VectorDrawable1 to VectorDrawable 2 and back again
**********************************************************
/**
* The LevelList that contains only two AnimatedVectorDrawable,
* the ones used to go from on to the other
*/
LevelListDrawable backupRoundTrip;
/**
* The current AnimatedVector diaplsyed by the RoundTrip
*/
AnimatedVectorDrawable contextDrawable;
/**
* To know is the animation have been already launched
*/
boolean backupRoundTripFirstLaunched=true;
/**
* Historical battles
*/
ArrayList<Long> battlesId=null;
/***********************************************************
* Attributes for the ViewPager
**********************************************************/
/**
* The TabLayout itself :)
*/
TabLayout tabLayout;
/**
* The page Adapter : Manage the list of views (in fact here, it's fragments)
* And send them to the ViewPager
*/
private MyPagerAdapter pagerAdapter;
/**
* The ViewPager is a ViewGroup that manage the swipe from left to right to left
* Like a listView with a gesture listener...
*/
private ViewPager viewPager;
/***********************************************************
* Managing the Life cycle
**********************************************************/
**********************************************************/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e(TAG, "onCreate() called");
setContentView(R.layout.activity_history);
//find the Toolbar
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
//use it as your action bar
setSupportActionBar(toolbar);
getSupportActionBar().setSubtitle(getString(R.string.history_fragment_subtitle));
getSupportActionBar().setTitle(getString(R.string.history_fragment_title));
tabLayout = (TabLayout) findViewById(R.id.tabLayout);
//Define its gravity and its mode
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
//Define the color to use (depending on the state a different color should be disaplyed)
//Works only if done before adding tabs
tabLayout.setTabTextColors(getResources().getColorStateList(R.color.tab_selector_color));
//instanciate the PageAdapter
pagerAdapter=new MyPagerAdapter(this,true);
//Find the viewPager
viewPager = (ViewPager) super.findViewById(R.id.viewpager);
// Affectation de l'adapter au ViewPager
viewPager.setAdapter(pagerAdapter);
viewPager.setClipToPadding(true);
//Add animation when the page are swiped
//this instanciation only works with honeyComb and more
//if you want it all version use AnimatorProxy of the nineoldAndroid lib
//@see:http://stackoverflow.com/questions/15767729/backwards-compatible-pagetransformer
//TODO uncomment those lines and the opengl bug disappears
// if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB){
// viewPager.setPageTransformer(true, new MyPageTransformer());
// }
//AND CLUE TABLAYOUT AND VIEWPAGER
tabLayout.setupWithViewPager(viewPager);
}
@Override
protected void onStart() {
super.onStart();
//track entrance
Log.e(TAG, "onStart() has been called");
EventBus.getDefault().register(this);
}
@Override
protected void onResume() {
super.onResume();
//track entrance
Log.e(TAG, "onResume() has been called");
}
} @Override
protected void onStop() {
super.onStop();
//track entrance
Log.e(TAG, "onStop() has been called");
EventBus.getDefault().unregister(this);
}
@Override
public void onBackPressed() {
if(((MyApplication)getApplication()).isCigaretPanelOpen){
//do nothing the fragment will just change its state
battleFragment.onBack();
}else{
super.onBackPressed();
}
}
@Subscribe(threadMode = ThreadMode.MAIN)//EventBus
public void updateUI(FullUpdateEvent event) {
//TODO update properly
Log.e(TAG, "fullUpdate() called with: " + "notUsed = [" + event + "]");
//rebuild every thing:$
pagerAdapter.notifyRebuildAll();
if(event.isSwitchActivity()){
switchContext();
}else{
tabLayout.setupWithViewPager(viewPager);
}
}
/***********************************************************
* Managing menu
**********************************************************/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater=getMenuInflater();
inflater.inflate(R.menu.history_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.menu_switch_context:
switchContext();
break;
}
return super.onOptionsItemSelected(item);
}
/***********************************************************
* Managing backup button round trip
**********************************************************/
/**
* Switch context from history to current (and vis versa)
* Launch the animation on the currentAnimatedVectorDrawable
*/
private void switchContext(){
Intent startNewContext=new Intent(this, CurrentBattleActivity.class);
startNewContext.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(startNewContext);
}
}
When all began, we had the God Class
We need a small
evolution!
We want to test it…
Yep… We did huge shit
A piece of history
public class HistoryBattleActivity extends AppCompatActivity {
private static final String TAG = "HistoryBattleActivity";
private static final int CONTEXT_CURRENT=110274;
private static final int CONTEXT_HISTORY=131274;
/***********************************************************
* Attributes
**********************************************************/
BattleFragment battleFragment;
/**
* Current context History/current
*/
int currentContext=CONTEXT_CURRENT;
/***********************************************************
* Managing RoundTrip animation (VectorDrawable1 to VectorDrawable 2 and back again
**********************************************************
/**
* The LevelList that contains only two AnimatedVectorDrawable,
* the ones used to go from on to the other
*/
LevelListDrawable backupRoundTrip;
/**
* The current AnimatedVector diaplsyed by the RoundTrip
*/
AnimatedVectorDrawable contextDrawable;
/**
* To know is the animation have been already launched
*/
boolean backupRoundTripFirstLaunched=true;
/**
* Historical battles
*/
ArrayList<Long> battlesId=null;
/***********************************************************
* Attributes for the ViewPager
**********************************************************/
/**
* The TabLayout itself :)
*/
TabLayout tabLayout;
/**
* The page Adapter : Manage the list of views (in fact here, it's fragments)
* And send them to the ViewPager
*/
private MyPagerAdapter pagerAdapter;
/**
* The ViewPager is a ViewGroup that manage the swipe from left to right to left
* Like a listView with a gesture listener...
*/
private ViewPager viewPager;
/***********************************************************
* Managing the Life cycle
**********************************************************/
**********************************************************/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e(TAG, "onCreate() called");
setContentView(R.layout.activity_history);
//find the Toolbar
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
//use it as your action bar
setSupportActionBar(toolbar);
getSupportActionBar().setSubtitle(getString(R.string.history_fragment_subtitle));
getSupportActionBar().setTitle(getString(R.string.history_fragment_title));
tabLayout = (TabLayout) findViewById(R.id.tabLayout);
//Define its gravity and its mode
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
//Define the color to use (depending on the state a different color should be disaplyed)
//Works only if done before adding tabs
tabLayout.setTabTextColors(getResources().getColorStateList(R.color.tab_selector_color));
//instanciate the PageAdapter
pagerAdapter=new MyPagerAdapter(this,true);
//Find the viewPager
viewPager = (ViewPager) super.findViewById(R.id.viewpager);
// Affectation de l'adapter au ViewPager
viewPager.setAdapter(pagerAdapter);
viewPager.setClipToPadding(true);
//Add animation when the page are swiped
//this instanciation only works with honeyComb and more
//if you want it all version use AnimatorProxy of the nineoldAndroid lib
//@see:http://stackoverflow.com/questions/15767729/backwards-compatible-pagetransformer
//TODO uncomment those lines and the opengl bug disappears
// if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB){
// viewPager.setPageTransformer(true, new MyPageTransformer());
// }
//AND CLUE TABLAYOUT AND VIEWPAGER
tabLayout.setupWithViewPager(viewPager);
}
@Override
protected void onStart() {
super.onStart();
//track entrance
Log.e(TAG, "onStart() has been called");
EventBus.getDefault().register(this);
}
@Override
protected void onResume() {
super.onResume();
//track entrance
Log.e(TAG, "onResume() has been called");
}
} @Override
protected void onStop() {
super.onStop();
//track entrance
Log.e(TAG, "onStop() has been called");
EventBus.getDefault().unregister(this);
}
@Override
public void onBackPressed() {
if(((MyApplication)getApplication()).isCigaretPanelOpen){
//do nothing the fragment will just change its state
battleFragment.onBack();
}else{
super.onBackPressed();
}
}
@Subscribe(threadMode = ThreadMode.MAIN)//EventBus
public void updateUI(FullUpdateEvent event) {
//TODO update properly
Log.e(TAG, "fullUpdate() called with: " + "notUsed = [" + event + "]");
//rebuild every thing:$
pagerAdapter.notifyRebuildAll();
if(event.isSwitchActivity()){
switchContext();
}else{
tabLayout.setupWithViewPager(viewPager);
}
}
/***********************************************************
* Managing menu
**********************************************************/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater=getMenuInflater();
inflater.inflate(R.menu.history_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.menu_switch_context:
switchContext();
break;
}
return super.onOptionsItemSelected(item);
}
/***********************************************************
* Managing backup button round trip
**********************************************************/
/**
* Switch context from history to current (and vis versa)
* Launch the animation on the currentAnimatedVectorDrawable
*/
private void switchContext(){
Intent startNewContext=new Intent(this, CurrentBattleActivity.class);
startNewContext.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(startNewContext);
}
}
We gonna split the view and the rest of the
application
public class HistoryBattleActivity extends AppCompatActivity {
private static final String TAG = "HistoryBattleActivity";
private static final int CONTEXT_CURRENT=110274;
private static final int CONTEXT_HISTORY=131274;
/***********************************************************
* Attributes
**********************************************************/
BattleFragment battleFragment;
/**
* Current context History/current
*/
int currentContext=CONTEXT_CURRENT;
/***********************************************************
* Managing RoundTrip animation (VectorDrawable1 to VectorDrawable 2 and back again
**********************************************************
/**
* The LevelList that contains only two AnimatedVectorDrawable,
* the ones used to go from on to the other
*/
LevelListDrawable backupRoundTrip;
/**
* The current AnimatedVector diaplsyed by the RoundTrip
*/
AnimatedVectorDrawable contextDrawable;
/**
* To know is the animation have been already launched
*/
boolean backupRoundTripFirstLaunched=true;
/**
* Historical battles
*/
ArrayList<Long> battlesId=null;
/***********************************************************
* Attributes for the ViewPager
**********************************************************/
/**
* The TabLayout itself :)
*/
TabLayout tabLayout;
/**
* The page Adapter : Manage the list of views (in fact here, it's fragments)
* And send them to the ViewPager
*/
private MyPagerAdapter pagerAdapter;
/**
* The ViewPager is a ViewGroup that manage the swipe from left to right to left
* Like a listView with a gesture listener...
*/
private ViewPager viewPager;
/***********************************************************
* Managing the Life cycle
**********************************************************/
**********************************************************/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e(TAG, "onCreate() called");
setContentView(R.layout.activity_history);
//find the Toolbar
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
//use it as your action bar
setSupportActionBar(toolbar);
getSupportActionBar().setSubtitle(getString(R.string.history_fragment_subtitle));
getSupportActionBar().setTitle(getString(R.string.history_fragment_title));
tabLayout = (TabLayout) findViewById(R.id.tabLayout);
//Define its gravity and its mode
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
//Define the color to use (depending on the state a different color should be disaplyed)
//Works only if done before adding tabs
tabLayout.setTabTextColors(getResources().getColorStateList(R.color.tab_selector_color));
//instanciate the PageAdapter
pagerAdapter=new MyPagerAdapter(this,true);
//Find the viewPager
viewPager = (ViewPager) super.findViewById(R.id.viewpager);
// Affectation de l'adapter au ViewPager
viewPager.setAdapter(pagerAdapter);
viewPager.setClipToPadding(true);
//Add animation when the page are swiped
//this instanciation only works with honeyComb and more
//if you want it all version use AnimatorProxy of the nineoldAndroid lib
//@see:http://stackoverflow.com/questions/15767729/backwards-compatible-pagetransformer
//TODO uncomment those lines and the opengl bug disappears
// if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB){
// viewPager.setPageTransformer(true, new MyPageTransformer());
// }
//AND CLUE TABLAYOUT AND VIEWPAGER
tabLayout.setupWithViewPager(viewPager);
}
@Override
protected void onStart() {
super.onStart();
//track entrance
Log.e(TAG, "onStart() has been called");
EventBus.getDefault().register(this);
}
@Override
protected void onResume() {
super.onResume();
//track entrance
Log.e(TAG, "onResume() has been called");
}
} @Override
protected void onStop() {
super.onStop();
//track entrance
Log.e(TAG, "onStop() has been called");
EventBus.getDefault().unregister(this);
}
@Override
public void onBackPressed() {
if(((MyApplication)getApplication()).isCigaretPanelOpen){
//do nothing the fragment will just change its state
battleFragment.onBack();
}else{
super.onBackPressed();
}
}
@Subscribe(threadMode = ThreadMode.MAIN)//EventBus
public void updateUI(FullUpdateEvent event) {
//TODO update properly
Log.e(TAG, "fullUpdate() called with: " + "notUsed = [" + event + "]");
//rebuild every thing:$
pagerAdapter.notifyRebuildAll();
if(event.isSwitchActivity()){
switchContext();
}else{
tabLayout.setupWithViewPager(viewPager);
}
}
/***********************************************************
* Managing menu
**********************************************************/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater=getMenuInflater();
inflater.inflate(R.menu.history_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.menu_switch_context:
switchContext();
break;
}
return super.onOptionsItemSelected(item);
}
/***********************************************************
* Managing backup button round trip
**********************************************************/
/**
* Switch context from history to current (and vis versa)
* Launch the animation on the currentAnimatedVectorDrawable
*/
private void switchContext(){
Intent startNewContext=new Intent(this, CurrentBattleActivity.class);
startNewContext.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(startNewContext);
}
}
We gonna split the view and the rest of the
application
Model
View Controller
Modifies
Prevents
Updates
The MVC model was born!
A piece of history
Then came the M(VC) model (a Swing’s pattern)
Model
View&Controller
ModifiesUpdates
View Controller
A piece of history
Manages the data
displayed
Displays the data and
Interacts with the user
The Swing M(VC) model
Model
View&Controller
1
1
A piece of history
The Swing M(VC) model
Manages the data
displayed
Model
Displays the data and
Interacts with the user
View&Controller
1
1
A piece of history
And the MVP was created
Manages the data
displayed
Model
Displays the data and
Interacts with the user
Vue&Controller
Presenter
Data management
Business Logic
And Treatments
Model
View
A piece of history
And the MVP was created
Manages the data
displayed
Presenter
Displays the data and
Interacts with the user
View
Data management
Business Logic
And Treatments
Model
1
1
ModifiesUpdates
Talks
A piece of history
The programmation by contract was born
(Interfaces)
Manages the data
displayed
Presenter
Displays the data and
Interacts with the user
View
Data management
Business Logic
And Treatments
Model
1
0
PresenterIntf
ViewIntf
0
1
A piece of history
For the TESTS !
Model
Presenter
View
PresenterIntf
ViewIntf
MockPresenter
MockView
A piece of history
Flavor=TestPresenter
And with Gradle, happiness knocks on your door.
Flavor=TestVueFlavor=PROD
Model
Presenter
View
0
1
MockPresenter
MockViewView
Presenter
0
1
0
1
MockModel
A piece of history
Then came MVVM
Manages the data
displayed
Presenter
Displays the data and
Interacts with the user
View
Data management
Business Logic
And Treatments
Model
1
1
ModifiesUpdates
Talks
ViewModel
1
n
A piece of history
Architecture
Why all that complexity ?
Test!
Split
responsabilities
Reuse Simplify
Architecture
But wait ! First remark.
MVC MVP MVVM FLUX
We don’t care about fashion.
Architecture
The important is to split concerns
Manages the data
displayed
Displays the data and
Interacts with the user
Data management
Business Logic
And Treatments
Architecture
But wait !
Don’t you have forget a damned element?
It all View’s architecture, only View
Architecture
You forgot your whole application!
N-Tier model
Application
Services
View Presenter
AndroidServices
SingletonServices
BroadcastReceiver
ExceptionManager
POJO
Tools
knows
knows
starts
starts
knows
View =
MVP
Transverse
I
N
T
F
Service
I
N
T
F Communication
Com
D.A.O.
I
N
T
F
DAO
knows
Warning
BAD NOMENCLATURE
The Android curse
Services
AndroidServices
SingletonServices
I
N
T
F
Service
AndroidServices
Service Business Treatments Logic
Simplicity SplittingMaintenance
EvolutionConcerns Robustness
Back to our goals
Test
Reuse Contract Mock
Splitting concerns
NTiers Model
Services
View Presenter
AndroidServices
SingletonServices
BroadcastReceiver
ExceptionManager
POJO
Tools
knows
knows
knows
starts
starts
knows
View =
MVP
Service Communication
Com
D.A.O.
DAO
Transverse
Application
I
N
T
F
I
N
T
F
I
N
T
F
Simplification
NTiers Model
Services
View Presenter
AndroidServices
SingletonServices
BroadcastReceiver
ExceptionManager
POJO
Tools
knows
knows
knows
starts
starts
knows
View =
MVP
Service Communication
Com
D.A.O.
DAO
Transverse
Application
I
N
T
F
I
N
T
F
I
N
T
F
Contract programming
NTiers Model
Services
View Presenter
AndroidServices
SingletonServices
BroadcastReceiver
ExceptionManager
POJO
Tools
knows
knows
knows
starts
starts
knows
View =
MVP
Service Communication
Com
D.A.O.
DAO
Transverse
Application
I
N
T
F
I
N
T
F
I
N
T
F
Evolution
NTiers Model
Services
View Presenter
AndroidServices
SingletonServices
BroadcastReceiver
ExceptionManager
POJO
Tools
knows
knows
knows
starts
starts
knows
View =
MVP
Service Communication
Com
D.A.O.
DAO
Transverse
Application
I
N
T
F
I
N
T
F
I
N
T
F
NTiers Model
BroadcastReceiver
Communication
Com
D.A.O.
DAO
ExceptionManagerTools
Testing
Tests
JUNIT
Tests
Tests
Transverse
Transverse
NTiers Model
Services
AndroidServices
SingletonServices
Service
knows Communication
Com
I
N
T
F
knows
D.A.O.
DAO
I
N
T
F
Tests
JUNIT
Testing
NTiers Model
MockView
View = MVP
Presenter
ViewIntf
1
1
JUNIT
Services
AndroidServices
SingletonServices
Service
I
N
T
F
Tests
Testing
NTiers Model
View = MVP
Presenter
View
1
1
Services
AndroidServices
SingletonServices
Service
I
N
T
F
Espresso
AndroidTest SDK
Tests
Testing
Complete Testing
NTiers Model
Services
View Presenter
AndroidServices
SingletonServices
BroadcastReceiver
ExceptionManager
POJO
Tools
knows
knows
knows
starts
starts
knows
View =
MVP
Service Communication
Com
D.A.O.
DAO
Transverse
Application
Maintenance
Robustness
NTiers Model
Services
View Presenter
AndroidServices
SingletonServices
BroadcastReceiver
ExceptionManager
POJO
Tools
knows
knows
knows
starts
starts
knows
View =
MVP
Service Communication
Com
D.A.O.
DAO
Transverse
Application
MVP + N-Tier
Establish the principlae of
separation of concerns
Being unitary testable easely
Allow adaptation to framework’s
changes
Synthesis
Evolutions with no impact on the application.
Being independent of the implementation,
able to change it and test it.
Allow evolutions (DataBase,
communication, …)
Allow to change Libraries
The Application objects
Business services
When my application is in foreground,
I want all the power that I need
Goals
When my applications goes in background,
I want to free as much resources to the system as I can.
(because of the tragedy of the Commons).
Fuck I am
going in
background
Take that
services !
Goals
And I don’t want my users to experience that :
Goals
And I don’t want my users to experience that
My philosophy is LazyLoading
Goals
47
To do that all plays here
ArchiDroid
HERE
Aside
The Application object
Application
Starts before any of your classes
The Application object
Keeps the global state of your application
Ends after any of your classes
Is the Application Context
Application
Application
The Application object
You have to own it
public class DesignApplication extends Application {
}
<manifest package=
<application
...
android:name=".DesignApplication">
Application
The Application object
And reach it from anywhere: Singleton Design Pattern
public class DesignApplication extends Application {
private static DesignApplication instance;
public static DesignApplication getInstance() {
return instance;}
public void onCreate() {
super.onCreate();
instance = this;…}
Application
The Application object
Can be reached from anywhere,
from any thread
All its public methods have to be
synchronized.
Application
The Application object
The Application object has the responsability of the
instantiation of all objects it persists, it returns.
Application
User user=null;
public void getUser() {
if(user==null) {
//Do what you need to do
//1)startActivity(LoginActivtyIntent);
//ou 2)retireve it from a SharedPreference||DataBase||File...
}
return user;
}
Business Services
Business
Services
AndroidServices
SingletonServices
Business Services
"Service (The Android class):
Service is how an application indicates to the operating system that it
needs to perform a longer-running operation outside of the normal
Activity UI flow.
It may be self-running (through Context.startService()), or running on
behalf of of another process (through Context.bindService()).
If you do not need either of these behaviors, you should not use a
Service."
Service Android == System Service
Business Services
The layer service in N-Tiers architecture:
It corresponds to the functional part of the application that implements
the “Logic” and which describes the operations the application has to
do on the data.
The different Business Rules and System Controls are implemented in
this layer.
This is the treatments layer.
Business Services
Should be thought as an activity
without UI
6
Services
AndroidServices
SingletonServices
Insure unique instance(best to do that
using a ServiceManager instead of
static)
Executed in the Main Thread
Is made for long running process
When active, Process is keept in the
LRU-Cach as long as possible
Bigger than a simple POJO
Is lightweight (simple POJO)
Your Business services are like this on
server side
You have to manage their life cycle.
??
Business Services
Services
AndroidServices
SingletonServices
??
Need to be launch by the system?
Need to make some data caching?
Business Services
Services
AndroidServices
SingletonServices
??
Need to keep going without any visible activity (like Music Player)?
No particular need
End of Aside
Instantiate them only when needed
With our Business Services we have to:
ArchiDroid
Instantiate them only once
Be asynchronous
Do not follow the life cycle of activities
but the life cycle of the application
Let their treatments end
Instantiation on demand
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
View Presenter
HumanService
LazyLoading
Services
Manager
Activity
AndroidServices
SingletonServices
Threads management
View Presenter
HumanService
Manage Threads
Services
Manager
DAO
Cancelable
KeepAlive
ThreadsPools
public class ServiceManager {
/**
* The list of the bound services to this used to unbind the service. A service is pointed by its serviceConnection. */
List<ServiceConnection> boundServices = null;
List<Service> serviceAndroid = null; List<ServiceBusiness> singletonServices = null;
/** * Empty constructor to instantiate the list of bound services */
private ServiceManager() {boundServices = new ArrayList<ServiceConnection>();...}
/** 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
MAppInstance.ins.getApplication().unbindService(sConn);
}
for (Service servAndroid: servicesAndroid) {
servAndroid = null;} boundServices.clear();
//Do the same with your Singleton Service
for (ServiceBuisness singleton : singletonServices) {
singleton=null;}
//Kill your executor services
//the ones that has to let your thread finish
//the ones that has to finish right now
}
Service Manager
private ExecutorService keepAliveThreadsExcecutor = null;
/*** @return the cancelableThreadsExceutor */
public final ExecutorService getKeepAliveThreadsExecutor() {
if (keepAliveThreadsExceutor == null) {
keepAliveThreadsExceutor = Executors.newFixedThreadPool(4, new BackgroundThreadFactory());
}
return keepAliveThreadsExceutor;
}
/**ShutDown the ExecutorService but wait for thread to finish their job */
private void killKeepAliveThreadExecutor() {
if (keepAliveThreadsExceutor != null) {
keepAliveThreadsExceutor.shutdown(); // Disable new tasks from being submitted
try {// as long as your threads hasn't finished
while (!keepAliveThreadsExceutor.isTerminated()) {
// Wait a while for existing tasks to terminate
if (!keepAliveThreadsExceutor.awaitTermination(5, TimeUnit.SECONDS)) {
// Cancel currently executing tasks
keepAliveThreadsExceutor.shutdown();
Log.e("MyApp", "Probably a memory leak here");
}
}
} catch (InterruptedException ie) { keepAliveThreadsExceutor.shutdownNow();
keepAliveThreadsExceutor=null;
Log.e("MyApp", "Probably a memory leak here too");
} }
keepAliveThreadsExceutor=null;}
Service Manager
Persist instantiation
Application
View Presenter
HumanService
LazyLoading
Services
Manager
DAO
Cancelable
KeepAlive
ThreadsPools
Do not follow the Activity’s life cycle
But the application’s life cycle
Persist instantiation
Application
0-1
HumanService
Services
Manager
0-1
But wait !
AndroidServices
Persist instantiation
Application
0-1
HumanService
Services
Manager
0-1
Dead Lock occurs !
AndroidServices
Keep the service alive
(because keep ServiceManager alive)
Keep the Application object alive
(still Bound with the ServiceManager)
Persist instantiation
Application
0-1
HumanService
Services
Manager
0-1
Dead Lock occurs !
AndroidServices
Keep the service alive
(because keep ServiceManager alive)
Keep the Application object alive
(still Bound with the ServiceManager)
Persist instantiation
Application
0-1
HumanService
Services
Manager
0-1
Dead Lock occurs !
AndroidServices
Garde le Service en vie
(car conserve le ServiceManager en vie)
Garde l'application en vie
(car toujours Bound avec le ServiceManager)
Persist instantiation
Application
0-1
HumanService
Services
Manager
0-1
Dead Lock occurs !
AndroidServices
DO NOT FOLLOW ACTIVITIES’ LIFE CYCLES
FOLLOW APPLICATION’S LIFE CYCLE
The solution :
Application’s Life Cycle
What is the life cycle of an application ?
When there is no more visible activities since one second,
I can consider the application is over.
Application’s Life Cycle
The One Second pattern: A release memory pattern
IsActivity
Alive
7
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
Application’s Life Cycle
React to onMemoryLow
ApplicationServices
Manager
onLowMemory (...)
System
unbindAndDie()
LazyLoading is our philosophy
Be Asynchronous
On Android, every body knows, we have to be asynchronous!
Those who code the D.A.O. layer, know it.
Those who code the View layer, know it.
Thread(Thread(Thread(Thread(do something))))
Those who code the Service layer, know it.
Those who code the Communication layer, know it.
Be Asynchronous
Only One Rule:
The Service layer is your Asynchronicity gate.
Each public method of each service class has to be executed in a
background Thread.
Nowhere else Threads are launched.
(except for animation Threads in Ginger, putain de gingerbread)
Use events to return result.
Be Asynchronous
public class MyBusinessService{...
public void loadDataAsync(int itemId) {
MyApp.instance.getServiceManager()
.getCancelableThreadsExecutor()
.submit(new RunnableLoadData(itemId));
}
private class RunnableLoadData implements Runnable {
public int itemId;
public RunnableLoadData(int itemId) {this.itemId=itemId}
public void run() {
loadDataSync(itemId);}
}
public void loadDataSync(int itemId) {
// your code here}
You can use AysncTaskYou can use AysncTask
Be Asynchronous
You should use PoolExecutor and Runnables
You can use IntentService
https://www.youtube.com/watch?v=jtlRNNhane0&index=4&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE
You can use HandlerThread
Instanciate them only when needed
Instanciate them only once
Be asynchronous
Do not follow the life cycle of activities
but the life cycle of the application
Let their treatments end
With our Business Services, we wanted to:
ArchiDroid
Available on my GitHub
I use Live Template to generate it
What about the code
arch_Service_Method_WithArgs
arch_ServManager_CancelableThread
arch_ServManager_KeepAliveThread
arch_Service_Method
And more...
I can train your team !
Or
And engage myself
On the success of your Android product
(with a high quality lens)
I can be your Android tech lead
#android2ee
mathias.seguy@android2ee.com
www.android2ee.com
Thank you!Mathias Seguy
Android2EE
@android2ee
Slides:
http://fr.slideshare.net/Android2EE
Code:
https://github.com/MathiasSeguy-Android2EE
Android2EE
http://android2ee.com
Thank you!Mathias Seguy
Android2EE
@android2ee
Slides:
http://fr.slideshare.net/Android2EE
Code:
https://github.com/MathiasSeguy-Android2EE
Android2EE
http://android2ee.com

More Related Content

What's hot

Angular 1 + es6
Angular 1 + es6Angular 1 + es6
Angular 1 + es6장현 한
 
st_launcher: Tonel-based Smalltalk shell Scripts
 st_launcher: Tonel-based Smalltalk shell Scripts st_launcher: Tonel-based Smalltalk shell Scripts
st_launcher: Tonel-based Smalltalk shell ScriptsESUG
 
STYLISH FLOOR
STYLISH FLOORSTYLISH FLOOR
STYLISH FLOORABU HASAN
 
Standford 2015 week6
Standford 2015 week6Standford 2015 week6
Standford 2015 week6彼得潘 Pan
 
ES6, 잘 쓰고 계시죠?
ES6, 잘 쓰고 계시죠?ES6, 잘 쓰고 계시죠?
ES6, 잘 쓰고 계시죠?장현 한
 
Dirty Durham: Dry cleaning solvents leaked into part of Trinity Park | News
Dirty Durham: Dry cleaning solvents leaked into part of Trinity Park | NewsDirty Durham: Dry cleaning solvents leaked into part of Trinity Park | News
Dirty Durham: Dry cleaning solvents leaked into part of Trinity Park | Newsdizzyspiral5631
 

What's hot (7)

201104 iphone navigation-based apps
201104 iphone navigation-based apps201104 iphone navigation-based apps
201104 iphone navigation-based apps
 
Angular 1 + es6
Angular 1 + es6Angular 1 + es6
Angular 1 + es6
 
st_launcher: Tonel-based Smalltalk shell Scripts
 st_launcher: Tonel-based Smalltalk shell Scripts st_launcher: Tonel-based Smalltalk shell Scripts
st_launcher: Tonel-based Smalltalk shell Scripts
 
STYLISH FLOOR
STYLISH FLOORSTYLISH FLOOR
STYLISH FLOOR
 
Standford 2015 week6
Standford 2015 week6Standford 2015 week6
Standford 2015 week6
 
ES6, 잘 쓰고 계시죠?
ES6, 잘 쓰고 계시죠?ES6, 잘 쓰고 계시죠?
ES6, 잘 쓰고 계시죠?
 
Dirty Durham: Dry cleaning solvents leaked into part of Trinity Park | News
Dirty Durham: Dry cleaning solvents leaked into part of Trinity Park | NewsDirty Durham: Dry cleaning solvents leaked into part of Trinity Park | News
Dirty Durham: Dry cleaning solvents leaked into part of Trinity Park | News
 

Viewers also liked

Google Plus SignIn : l'Authentification Google
Google Plus SignIn : l'Authentification GoogleGoogle Plus SignIn : l'Authentification Google
Google Plus SignIn : l'Authentification GoogleMathias Seguy
 
Mise en place de l'ActionBarCompat dans vos projets Android.
Mise en place de l'ActionBarCompat dans vos projets Android.Mise en place de l'ActionBarCompat dans vos projets Android.
Mise en place de l'ActionBarCompat dans vos projets Android.Mathias Seguy
 
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part2
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part2Architecture et Bonnes pratiques Android #DevoxxFr2016 Part2
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part2Mathias Seguy
 
Android un nouveau futur s'ouvre à nous
Android un nouveau futur s'ouvre à nousAndroid un nouveau futur s'ouvre à nous
Android un nouveau futur s'ouvre à nousMathias Seguy
 
Conférence "Architecture Android" du 19 Mars 2013 par Mathias Seguy fondateur...
Conférence "Architecture Android" du 19 Mars 2013 par Mathias Seguy fondateur...Conférence "Architecture Android" du 19 Mars 2013 par Mathias Seguy fondateur...
Conférence "Architecture Android" du 19 Mars 2013 par Mathias Seguy fondateur...Mathias Seguy
 
ProTips DroidCon Paris 2013
ProTips DroidCon Paris 2013ProTips DroidCon Paris 2013
ProTips DroidCon Paris 2013Mathias Seguy
 
Eclispe daytoulouse combining the power of eclipse with android_fr_1024_768_s...
Eclispe daytoulouse combining the power of eclipse with android_fr_1024_768_s...Eclispe daytoulouse combining the power of eclipse with android_fr_1024_768_s...
Eclispe daytoulouse combining the power of eclipse with android_fr_1024_768_s...Mathias Seguy
 
Voyage en monde Android. Trucs et astuces tout au long de la route.
Voyage en monde Android. Trucs et astuces tout au long de la route.Voyage en monde Android. Trucs et astuces tout au long de la route.
Voyage en monde Android. Trucs et astuces tout au long de la route.Mathias Seguy
 
Animate Me, if you don't do it for me do it for chet (DroidCon Paris)
Animate Me, if you don't do it for me do it for chet (DroidCon Paris)Animate Me, if you don't do it for me do it for chet (DroidCon Paris)
Animate Me, if you don't do it for me do it for chet (DroidCon Paris)Mathias Seguy
 
Android2EE training: Tutorials list of Android projects
Android2EE training: Tutorials list of Android projectsAndroid2EE training: Tutorials list of Android projects
Android2EE training: Tutorials list of Android projectsMathias Seguy
 
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part1
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part1Architecture et Bonnes pratiques Android #DevoxxFr2016 Part1
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part1Mathias Seguy
 
CocoaHeads An Android Overview (fr)
CocoaHeads An Android Overview (fr)CocoaHeads An Android Overview (fr)
CocoaHeads An Android Overview (fr)Mathias Seguy
 
Android Processes, Threads Slidenerd Style
Android Processes, Threads Slidenerd StyleAndroid Processes, Threads Slidenerd Style
Android Processes, Threads Slidenerd Styleayman diab
 
Red Hat OpenStack Technical Overview
Red Hat OpenStack Technical OverviewRed Hat OpenStack Technical Overview
Red Hat OpenStack Technical Overviewayman diab
 
The Nervous System
The Nervous SystemThe Nervous System
The Nervous SystemVijay A Raj
 
Android Material Design Slidenerd Style
Android Material Design Slidenerd StyleAndroid Material Design Slidenerd Style
Android Material Design Slidenerd Styleayman diab
 
WordPress for Beginners Create Professional Websites
WordPress for Beginners Create Professional WebsitesWordPress for Beginners Create Professional Websites
WordPress for Beginners Create Professional Websitesayman diab
 
The 2016 Android Developer Toolbox [NANTES]
The 2016 Android Developer Toolbox [NANTES]The 2016 Android Developer Toolbox [NANTES]
The 2016 Android Developer Toolbox [NANTES]Nilhcem
 
Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015
Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015
Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015Mathias Seguy
 

Viewers also liked (20)

Google Plus SignIn : l'Authentification Google
Google Plus SignIn : l'Authentification GoogleGoogle Plus SignIn : l'Authentification Google
Google Plus SignIn : l'Authentification Google
 
Mise en place de l'ActionBarCompat dans vos projets Android.
Mise en place de l'ActionBarCompat dans vos projets Android.Mise en place de l'ActionBarCompat dans vos projets Android.
Mise en place de l'ActionBarCompat dans vos projets Android.
 
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part2
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part2Architecture et Bonnes pratiques Android #DevoxxFr2016 Part2
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part2
 
Android un nouveau futur s'ouvre à nous
Android un nouveau futur s'ouvre à nousAndroid un nouveau futur s'ouvre à nous
Android un nouveau futur s'ouvre à nous
 
Conférence "Architecture Android" du 19 Mars 2013 par Mathias Seguy fondateur...
Conférence "Architecture Android" du 19 Mars 2013 par Mathias Seguy fondateur...Conférence "Architecture Android" du 19 Mars 2013 par Mathias Seguy fondateur...
Conférence "Architecture Android" du 19 Mars 2013 par Mathias Seguy fondateur...
 
ProTips DroidCon Paris 2013
ProTips DroidCon Paris 2013ProTips DroidCon Paris 2013
ProTips DroidCon Paris 2013
 
Eclispe daytoulouse combining the power of eclipse with android_fr_1024_768_s...
Eclispe daytoulouse combining the power of eclipse with android_fr_1024_768_s...Eclispe daytoulouse combining the power of eclipse with android_fr_1024_768_s...
Eclispe daytoulouse combining the power of eclipse with android_fr_1024_768_s...
 
Voyage en monde Android. Trucs et astuces tout au long de la route.
Voyage en monde Android. Trucs et astuces tout au long de la route.Voyage en monde Android. Trucs et astuces tout au long de la route.
Voyage en monde Android. Trucs et astuces tout au long de la route.
 
Animate Me, if you don't do it for me do it for chet (DroidCon Paris)
Animate Me, if you don't do it for me do it for chet (DroidCon Paris)Animate Me, if you don't do it for me do it for chet (DroidCon Paris)
Animate Me, if you don't do it for me do it for chet (DroidCon Paris)
 
Android2EE training: Tutorials list of Android projects
Android2EE training: Tutorials list of Android projectsAndroid2EE training: Tutorials list of Android projects
Android2EE training: Tutorials list of Android projects
 
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part1
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part1Architecture et Bonnes pratiques Android #DevoxxFr2016 Part1
Architecture et Bonnes pratiques Android #DevoxxFr2016 Part1
 
CocoaHeads An Android Overview (fr)
CocoaHeads An Android Overview (fr)CocoaHeads An Android Overview (fr)
CocoaHeads An Android Overview (fr)
 
5.ateliers avancés
5.ateliers avancés5.ateliers avancés
5.ateliers avancés
 
Android Processes, Threads Slidenerd Style
Android Processes, Threads Slidenerd StyleAndroid Processes, Threads Slidenerd Style
Android Processes, Threads Slidenerd Style
 
Red Hat OpenStack Technical Overview
Red Hat OpenStack Technical OverviewRed Hat OpenStack Technical Overview
Red Hat OpenStack Technical Overview
 
The Nervous System
The Nervous SystemThe Nervous System
The Nervous System
 
Android Material Design Slidenerd Style
Android Material Design Slidenerd StyleAndroid Material Design Slidenerd Style
Android Material Design Slidenerd Style
 
WordPress for Beginners Create Professional Websites
WordPress for Beginners Create Professional WebsitesWordPress for Beginners Create Professional Websites
WordPress for Beginners Create Professional Websites
 
The 2016 Android Developer Toolbox [NANTES]
The 2016 Android Developer Toolbox [NANTES]The 2016 Android Developer Toolbox [NANTES]
The 2016 Android Developer Toolbox [NANTES]
 
Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015
Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015
Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015
 

Similar to Treatment, Architecture and Threads

Commenting in Agile Development
Commenting in Agile DevelopmentCommenting in Agile Development
Commenting in Agile DevelopmentJan Rybák Benetka
 
DWR, Hibernate and Dojo.E - A Tutorial
DWR, Hibernate and Dojo.E - A TutorialDWR, Hibernate and Dojo.E - A Tutorial
DWR, Hibernate and Dojo.E - A Tutorialjbarciauskas
 
MBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&CoMBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&Coe-Legion
 
JavaScript, React Native and Performance at react-europe 2016
JavaScript, React Native and Performance at react-europe 2016JavaScript, React Native and Performance at react-europe 2016
JavaScript, React Native and Performance at react-europe 2016Tadeu Zagallo
 
OOP2017: Containerized End-2-End Testing – automate it!
OOP2017: Containerized End-2-End Testing – automate it!OOP2017: Containerized End-2-End Testing – automate it!
OOP2017: Containerized End-2-End Testing – automate it!Tobias Schneck
 
Containerized End-2-End Testing - Agile Testing Meetup at Süddeutsche Zeitung...
Containerized End-2-End Testing - Agile Testing Meetup at Süddeutsche Zeitung...Containerized End-2-End Testing - Agile Testing Meetup at Süddeutsche Zeitung...
Containerized End-2-End Testing - Agile Testing Meetup at Süddeutsche Zeitung...Tobias Schneck
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2Hugo Hamon
 
Effecient javascript
Effecient javascriptEffecient javascript
Effecient javascriptmpnkhan
 
オレオレSecurityバンドル作っちゃいました
オレオレSecurityバンドル作っちゃいましたオレオレSecurityバンドル作っちゃいました
オレオレSecurityバンドル作っちゃいましたKatsuhiro Ogawa
 
Microsoft word java
Microsoft word   javaMicrosoft word   java
Microsoft word javaRavi Purohit
 
Don't Make Android Bad... Again
Don't Make Android Bad... AgainDon't Make Android Bad... Again
Don't Make Android Bad... AgainPedro Vicente
 
ActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group PresentationActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group Presentationipolevoy
 
JSUG - Spring by Christoph Pickl
JSUG - Spring by Christoph PicklJSUG - Spring by Christoph Pickl
JSUG - Spring by Christoph PicklChristoph Pickl
 
Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2Matt Raible
 
PhoneGap_Javakuche0612
PhoneGap_Javakuche0612PhoneGap_Javakuche0612
PhoneGap_Javakuche0612Yuhei Miyazato
 
case3h231diamond.gifcase3h231energy.jpgcase3h231moder.docx
case3h231diamond.gifcase3h231energy.jpgcase3h231moder.docxcase3h231diamond.gifcase3h231energy.jpgcase3h231moder.docx
case3h231diamond.gifcase3h231energy.jpgcase3h231moder.docxtidwellveronique
 
Gift-VT Tools Development Overview
Gift-VT Tools Development OverviewGift-VT Tools Development Overview
Gift-VT Tools Development Overviewstn_tkiller
 

Similar to Treatment, Architecture and Threads (20)

Commenting in Agile Development
Commenting in Agile DevelopmentCommenting in Agile Development
Commenting in Agile Development
 
DWR, Hibernate and Dojo.E - A Tutorial
DWR, Hibernate and Dojo.E - A TutorialDWR, Hibernate and Dojo.E - A Tutorial
DWR, Hibernate and Dojo.E - A Tutorial
 
MBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&CoMBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&Co
 
Ssaw08 1021
Ssaw08 1021Ssaw08 1021
Ssaw08 1021
 
JavaScript, React Native and Performance at react-europe 2016
JavaScript, React Native and Performance at react-europe 2016JavaScript, React Native and Performance at react-europe 2016
JavaScript, React Native and Performance at react-europe 2016
 
OOP2017: Containerized End-2-End Testing – automate it!
OOP2017: Containerized End-2-End Testing – automate it!OOP2017: Containerized End-2-End Testing – automate it!
OOP2017: Containerized End-2-End Testing – automate it!
 
Containerized End-2-End Testing - Agile Testing Meetup at Süddeutsche Zeitung...
Containerized End-2-End Testing - Agile Testing Meetup at Süddeutsche Zeitung...Containerized End-2-End Testing - Agile Testing Meetup at Süddeutsche Zeitung...
Containerized End-2-End Testing - Agile Testing Meetup at Süddeutsche Zeitung...
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
 
Effecient javascript
Effecient javascriptEffecient javascript
Effecient javascript
 
オレオレSecurityバンドル作っちゃいました
オレオレSecurityバンドル作っちゃいましたオレオレSecurityバンドル作っちゃいました
オレオレSecurityバンドル作っちゃいました
 
Microsoft word java
Microsoft word   javaMicrosoft word   java
Microsoft word java
 
Don't Make Android Bad... Again
Don't Make Android Bad... AgainDon't Make Android Bad... Again
Don't Make Android Bad... Again
 
ActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group PresentationActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group Presentation
 
My java file
My java fileMy java file
My java file
 
JSUG - Spring by Christoph Pickl
JSUG - Spring by Christoph PicklJSUG - Spring by Christoph Pickl
JSUG - Spring by Christoph Pickl
 
Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2
 
002207866
002207866002207866
002207866
 
PhoneGap_Javakuche0612
PhoneGap_Javakuche0612PhoneGap_Javakuche0612
PhoneGap_Javakuche0612
 
case3h231diamond.gifcase3h231energy.jpgcase3h231moder.docx
case3h231diamond.gifcase3h231energy.jpgcase3h231moder.docxcase3h231diamond.gifcase3h231energy.jpgcase3h231moder.docx
case3h231diamond.gifcase3h231energy.jpgcase3h231moder.docx
 
Gift-VT Tools Development Overview
Gift-VT Tools Development OverviewGift-VT Tools Development Overview
Gift-VT Tools Development Overview
 

Recently uploaded

Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsRoshan Dwivedi
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vázquez
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesBoston Institute of Analytics
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 

Recently uploaded (20)

Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 

Treatment, Architecture and Threads

  • 5. A piece of History public class HistoryBattleActivity extends AppCompatActivity { private static final String TAG = "HistoryBattleActivity"; private static final int CONTEXT_CURRENT=110274; private static final int CONTEXT_HISTORY=131274; /*********************************************************** * Attributes **********************************************************/ BattleFragment battleFragment; /** * Current context History/current */ int currentContext=CONTEXT_CURRENT; /*********************************************************** * Managing RoundTrip animation (VectorDrawable1 to VectorDrawable 2 and back again ********************************************************** /** * The LevelList that contains only two AnimatedVectorDrawable, * the ones used to go from on to the other */ LevelListDrawable backupRoundTrip; /** * The current AnimatedVector diaplsyed by the RoundTrip */ AnimatedVectorDrawable contextDrawable; /** * To know is the animation have been already launched */ boolean backupRoundTripFirstLaunched=true; /** * Historical battles */ ArrayList<Long> battlesId=null; /*********************************************************** * Attributes for the ViewPager **********************************************************/ /** * The TabLayout itself :) */ TabLayout tabLayout; /** * The page Adapter : Manage the list of views (in fact here, it's fragments) * And send them to the ViewPager */ private MyPagerAdapter pagerAdapter; /** * The ViewPager is a ViewGroup that manage the swipe from left to right to left * Like a listView with a gesture listener... */ private ViewPager viewPager; /*********************************************************** * Managing the Life cycle **********************************************************/ **********************************************************/ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.e(TAG, "onCreate() called"); setContentView(R.layout.activity_history); //find the Toolbar Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); //use it as your action bar setSupportActionBar(toolbar); getSupportActionBar().setSubtitle(getString(R.string.history_fragment_subtitle)); getSupportActionBar().setTitle(getString(R.string.history_fragment_title)); tabLayout = (TabLayout) findViewById(R.id.tabLayout); //Define its gravity and its mode tabLayout.setTabGravity(TabLayout.GRAVITY_FILL); tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE); //Define the color to use (depending on the state a different color should be disaplyed) //Works only if done before adding tabs tabLayout.setTabTextColors(getResources().getColorStateList(R.color.tab_selector_color)); //instanciate the PageAdapter pagerAdapter=new MyPagerAdapter(this,true); //Find the viewPager viewPager = (ViewPager) super.findViewById(R.id.viewpager); // Affectation de l'adapter au ViewPager viewPager.setAdapter(pagerAdapter); viewPager.setClipToPadding(true); //Add animation when the page are swiped //this instanciation only works with honeyComb and more //if you want it all version use AnimatorProxy of the nineoldAndroid lib //@see:http://stackoverflow.com/questions/15767729/backwards-compatible-pagetransformer //TODO uncomment those lines and the opengl bug disappears // if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB){ // viewPager.setPageTransformer(true, new MyPageTransformer()); // } //AND CLUE TABLAYOUT AND VIEWPAGER tabLayout.setupWithViewPager(viewPager); } @Override protected void onStart() { super.onStart(); //track entrance Log.e(TAG, "onStart() has been called"); EventBus.getDefault().register(this); } @Override protected void onResume() { super.onResume(); //track entrance Log.e(TAG, "onResume() has been called"); } } @Override protected void onStop() { super.onStop(); //track entrance Log.e(TAG, "onStop() has been called"); EventBus.getDefault().unregister(this); } @Override public void onBackPressed() { if(((MyApplication)getApplication()).isCigaretPanelOpen){ //do nothing the fragment will just change its state battleFragment.onBack(); }else{ super.onBackPressed(); } } @Subscribe(threadMode = ThreadMode.MAIN)//EventBus public void updateUI(FullUpdateEvent event) { //TODO update properly Log.e(TAG, "fullUpdate() called with: " + "notUsed = [" + event + "]"); //rebuild every thing:$ pagerAdapter.notifyRebuildAll(); if(event.isSwitchActivity()){ switchContext(); }else{ tabLayout.setupWithViewPager(viewPager); } } /*********************************************************** * Managing menu **********************************************************/ @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater=getMenuInflater(); inflater.inflate(R.menu.history_menu, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()){ case R.id.menu_switch_context: switchContext(); break; } return super.onOptionsItemSelected(item); } /*********************************************************** * Managing backup button round trip **********************************************************/ /** * Switch context from history to current (and vis versa) * Launch the animation on the currentAnimatedVectorDrawable */ private void switchContext(){ Intent startNewContext=new Intent(this, CurrentBattleActivity.class); startNewContext.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(startNewContext); } } When all began, we had the God Class We need a small evolution! We want to test it… Yep… We did huge shit
  • 6. A piece of history public class HistoryBattleActivity extends AppCompatActivity { private static final String TAG = "HistoryBattleActivity"; private static final int CONTEXT_CURRENT=110274; private static final int CONTEXT_HISTORY=131274; /*********************************************************** * Attributes **********************************************************/ BattleFragment battleFragment; /** * Current context History/current */ int currentContext=CONTEXT_CURRENT; /*********************************************************** * Managing RoundTrip animation (VectorDrawable1 to VectorDrawable 2 and back again ********************************************************** /** * The LevelList that contains only two AnimatedVectorDrawable, * the ones used to go from on to the other */ LevelListDrawable backupRoundTrip; /** * The current AnimatedVector diaplsyed by the RoundTrip */ AnimatedVectorDrawable contextDrawable; /** * To know is the animation have been already launched */ boolean backupRoundTripFirstLaunched=true; /** * Historical battles */ ArrayList<Long> battlesId=null; /*********************************************************** * Attributes for the ViewPager **********************************************************/ /** * The TabLayout itself :) */ TabLayout tabLayout; /** * The page Adapter : Manage the list of views (in fact here, it's fragments) * And send them to the ViewPager */ private MyPagerAdapter pagerAdapter; /** * The ViewPager is a ViewGroup that manage the swipe from left to right to left * Like a listView with a gesture listener... */ private ViewPager viewPager; /*********************************************************** * Managing the Life cycle **********************************************************/ **********************************************************/ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.e(TAG, "onCreate() called"); setContentView(R.layout.activity_history); //find the Toolbar Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); //use it as your action bar setSupportActionBar(toolbar); getSupportActionBar().setSubtitle(getString(R.string.history_fragment_subtitle)); getSupportActionBar().setTitle(getString(R.string.history_fragment_title)); tabLayout = (TabLayout) findViewById(R.id.tabLayout); //Define its gravity and its mode tabLayout.setTabGravity(TabLayout.GRAVITY_FILL); tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE); //Define the color to use (depending on the state a different color should be disaplyed) //Works only if done before adding tabs tabLayout.setTabTextColors(getResources().getColorStateList(R.color.tab_selector_color)); //instanciate the PageAdapter pagerAdapter=new MyPagerAdapter(this,true); //Find the viewPager viewPager = (ViewPager) super.findViewById(R.id.viewpager); // Affectation de l'adapter au ViewPager viewPager.setAdapter(pagerAdapter); viewPager.setClipToPadding(true); //Add animation when the page are swiped //this instanciation only works with honeyComb and more //if you want it all version use AnimatorProxy of the nineoldAndroid lib //@see:http://stackoverflow.com/questions/15767729/backwards-compatible-pagetransformer //TODO uncomment those lines and the opengl bug disappears // if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB){ // viewPager.setPageTransformer(true, new MyPageTransformer()); // } //AND CLUE TABLAYOUT AND VIEWPAGER tabLayout.setupWithViewPager(viewPager); } @Override protected void onStart() { super.onStart(); //track entrance Log.e(TAG, "onStart() has been called"); EventBus.getDefault().register(this); } @Override protected void onResume() { super.onResume(); //track entrance Log.e(TAG, "onResume() has been called"); } } @Override protected void onStop() { super.onStop(); //track entrance Log.e(TAG, "onStop() has been called"); EventBus.getDefault().unregister(this); } @Override public void onBackPressed() { if(((MyApplication)getApplication()).isCigaretPanelOpen){ //do nothing the fragment will just change its state battleFragment.onBack(); }else{ super.onBackPressed(); } } @Subscribe(threadMode = ThreadMode.MAIN)//EventBus public void updateUI(FullUpdateEvent event) { //TODO update properly Log.e(TAG, "fullUpdate() called with: " + "notUsed = [" + event + "]"); //rebuild every thing:$ pagerAdapter.notifyRebuildAll(); if(event.isSwitchActivity()){ switchContext(); }else{ tabLayout.setupWithViewPager(viewPager); } } /*********************************************************** * Managing menu **********************************************************/ @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater=getMenuInflater(); inflater.inflate(R.menu.history_menu, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()){ case R.id.menu_switch_context: switchContext(); break; } return super.onOptionsItemSelected(item); } /*********************************************************** * Managing backup button round trip **********************************************************/ /** * Switch context from history to current (and vis versa) * Launch the animation on the currentAnimatedVectorDrawable */ private void switchContext(){ Intent startNewContext=new Intent(this, CurrentBattleActivity.class); startNewContext.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(startNewContext); } } We gonna split the view and the rest of the application
  • 7. public class HistoryBattleActivity extends AppCompatActivity { private static final String TAG = "HistoryBattleActivity"; private static final int CONTEXT_CURRENT=110274; private static final int CONTEXT_HISTORY=131274; /*********************************************************** * Attributes **********************************************************/ BattleFragment battleFragment; /** * Current context History/current */ int currentContext=CONTEXT_CURRENT; /*********************************************************** * Managing RoundTrip animation (VectorDrawable1 to VectorDrawable 2 and back again ********************************************************** /** * The LevelList that contains only two AnimatedVectorDrawable, * the ones used to go from on to the other */ LevelListDrawable backupRoundTrip; /** * The current AnimatedVector diaplsyed by the RoundTrip */ AnimatedVectorDrawable contextDrawable; /** * To know is the animation have been already launched */ boolean backupRoundTripFirstLaunched=true; /** * Historical battles */ ArrayList<Long> battlesId=null; /*********************************************************** * Attributes for the ViewPager **********************************************************/ /** * The TabLayout itself :) */ TabLayout tabLayout; /** * The page Adapter : Manage the list of views (in fact here, it's fragments) * And send them to the ViewPager */ private MyPagerAdapter pagerAdapter; /** * The ViewPager is a ViewGroup that manage the swipe from left to right to left * Like a listView with a gesture listener... */ private ViewPager viewPager; /*********************************************************** * Managing the Life cycle **********************************************************/ **********************************************************/ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.e(TAG, "onCreate() called"); setContentView(R.layout.activity_history); //find the Toolbar Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); //use it as your action bar setSupportActionBar(toolbar); getSupportActionBar().setSubtitle(getString(R.string.history_fragment_subtitle)); getSupportActionBar().setTitle(getString(R.string.history_fragment_title)); tabLayout = (TabLayout) findViewById(R.id.tabLayout); //Define its gravity and its mode tabLayout.setTabGravity(TabLayout.GRAVITY_FILL); tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE); //Define the color to use (depending on the state a different color should be disaplyed) //Works only if done before adding tabs tabLayout.setTabTextColors(getResources().getColorStateList(R.color.tab_selector_color)); //instanciate the PageAdapter pagerAdapter=new MyPagerAdapter(this,true); //Find the viewPager viewPager = (ViewPager) super.findViewById(R.id.viewpager); // Affectation de l'adapter au ViewPager viewPager.setAdapter(pagerAdapter); viewPager.setClipToPadding(true); //Add animation when the page are swiped //this instanciation only works with honeyComb and more //if you want it all version use AnimatorProxy of the nineoldAndroid lib //@see:http://stackoverflow.com/questions/15767729/backwards-compatible-pagetransformer //TODO uncomment those lines and the opengl bug disappears // if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB){ // viewPager.setPageTransformer(true, new MyPageTransformer()); // } //AND CLUE TABLAYOUT AND VIEWPAGER tabLayout.setupWithViewPager(viewPager); } @Override protected void onStart() { super.onStart(); //track entrance Log.e(TAG, "onStart() has been called"); EventBus.getDefault().register(this); } @Override protected void onResume() { super.onResume(); //track entrance Log.e(TAG, "onResume() has been called"); } } @Override protected void onStop() { super.onStop(); //track entrance Log.e(TAG, "onStop() has been called"); EventBus.getDefault().unregister(this); } @Override public void onBackPressed() { if(((MyApplication)getApplication()).isCigaretPanelOpen){ //do nothing the fragment will just change its state battleFragment.onBack(); }else{ super.onBackPressed(); } } @Subscribe(threadMode = ThreadMode.MAIN)//EventBus public void updateUI(FullUpdateEvent event) { //TODO update properly Log.e(TAG, "fullUpdate() called with: " + "notUsed = [" + event + "]"); //rebuild every thing:$ pagerAdapter.notifyRebuildAll(); if(event.isSwitchActivity()){ switchContext(); }else{ tabLayout.setupWithViewPager(viewPager); } } /*********************************************************** * Managing menu **********************************************************/ @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater=getMenuInflater(); inflater.inflate(R.menu.history_menu, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()){ case R.id.menu_switch_context: switchContext(); break; } return super.onOptionsItemSelected(item); } /*********************************************************** * Managing backup button round trip **********************************************************/ /** * Switch context from history to current (and vis versa) * Launch the animation on the currentAnimatedVectorDrawable */ private void switchContext(){ Intent startNewContext=new Intent(this, CurrentBattleActivity.class); startNewContext.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(startNewContext); } } We gonna split the view and the rest of the application Model View Controller Modifies Prevents Updates The MVC model was born! A piece of history
  • 8. Then came the M(VC) model (a Swing’s pattern) Model View&Controller ModifiesUpdates View Controller A piece of history
  • 9. Manages the data displayed Displays the data and Interacts with the user The Swing M(VC) model Model View&Controller 1 1 A piece of history
  • 10. The Swing M(VC) model Manages the data displayed Model Displays the data and Interacts with the user View&Controller 1 1 A piece of history
  • 11. And the MVP was created Manages the data displayed Model Displays the data and Interacts with the user Vue&Controller Presenter Data management Business Logic And Treatments Model View A piece of history
  • 12. And the MVP was created Manages the data displayed Presenter Displays the data and Interacts with the user View Data management Business Logic And Treatments Model 1 1 ModifiesUpdates Talks A piece of history
  • 13. The programmation by contract was born (Interfaces) Manages the data displayed Presenter Displays the data and Interacts with the user View Data management Business Logic And Treatments Model 1 0 PresenterIntf ViewIntf 0 1 A piece of history
  • 14. For the TESTS ! Model Presenter View PresenterIntf ViewIntf MockPresenter MockView A piece of history
  • 15. Flavor=TestPresenter And with Gradle, happiness knocks on your door. Flavor=TestVueFlavor=PROD Model Presenter View 0 1 MockPresenter MockViewView Presenter 0 1 0 1 MockModel A piece of history
  • 16. Then came MVVM Manages the data displayed Presenter Displays the data and Interacts with the user View Data management Business Logic And Treatments Model 1 1 ModifiesUpdates Talks ViewModel 1 n A piece of history
  • 17. Architecture Why all that complexity ? Test! Split responsabilities Reuse Simplify
  • 18. Architecture But wait ! First remark. MVC MVP MVVM FLUX We don’t care about fashion.
  • 19. Architecture The important is to split concerns Manages the data displayed Displays the data and Interacts with the user Data management Business Logic And Treatments
  • 20. Architecture But wait ! Don’t you have forget a damned element? It all View’s architecture, only View
  • 21. Architecture You forgot your whole application!
  • 23. Warning BAD NOMENCLATURE The Android curse Services AndroidServices SingletonServices I N T F Service AndroidServices Service Business Treatments Logic
  • 25. Splitting concerns NTiers Model Services View Presenter AndroidServices SingletonServices BroadcastReceiver ExceptionManager POJO Tools knows knows knows starts starts knows View = MVP Service Communication Com D.A.O. DAO Transverse Application I N T F I N T F I N T F
  • 27. Contract programming NTiers Model Services View Presenter AndroidServices SingletonServices BroadcastReceiver ExceptionManager POJO Tools knows knows knows starts starts knows View = MVP Service Communication Com D.A.O. DAO Transverse Application I N T F I N T F I N T F
  • 31. NTiers Model MockView View = MVP Presenter ViewIntf 1 1 JUNIT Services AndroidServices SingletonServices Service I N T F Tests Testing
  • 32. NTiers Model View = MVP Presenter View 1 1 Services AndroidServices SingletonServices Service I N T F Espresso AndroidTest SDK Tests Testing
  • 33. Complete Testing NTiers Model Services View Presenter AndroidServices SingletonServices BroadcastReceiver ExceptionManager POJO Tools knows knows knows starts starts knows View = MVP Service Communication Com D.A.O. DAO Transverse Application
  • 35. MVP + N-Tier Establish the principlae of separation of concerns Being unitary testable easely Allow adaptation to framework’s changes Synthesis Evolutions with no impact on the application. Being independent of the implementation, able to change it and test it. Allow evolutions (DataBase, communication, …) Allow to change Libraries
  • 37. When my application is in foreground, I want all the power that I need Goals
  • 38. When my applications goes in background, I want to free as much resources to the system as I can. (because of the tragedy of the Commons). Fuck I am going in background Take that services ! Goals
  • 39. And I don’t want my users to experience that : Goals
  • 40. And I don’t want my users to experience that My philosophy is LazyLoading Goals
  • 41. 47 To do that all plays here ArchiDroid HERE
  • 42. Aside
  • 44. Starts before any of your classes The Application object Keeps the global state of your application Ends after any of your classes Is the Application Context Application
  • 45. Application The Application object You have to own it public class DesignApplication extends Application { } <manifest package= <application ... android:name=".DesignApplication">
  • 46. Application The Application object And reach it from anywhere: Singleton Design Pattern public class DesignApplication extends Application { private static DesignApplication instance; public static DesignApplication getInstance() { return instance;} public void onCreate() { super.onCreate(); instance = this;…}
  • 47. Application The Application object Can be reached from anywhere, from any thread All its public methods have to be synchronized.
  • 48. Application The Application object The Application object has the responsability of the instantiation of all objects it persists, it returns. Application User user=null; public void getUser() { if(user==null) { //Do what you need to do //1)startActivity(LoginActivtyIntent); //ou 2)retireve it from a SharedPreference||DataBase||File... } return user; }
  • 50. Business Services "Service (The Android class): Service is how an application indicates to the operating system that it needs to perform a longer-running operation outside of the normal Activity UI flow. It may be self-running (through Context.startService()), or running on behalf of of another process (through Context.bindService()). If you do not need either of these behaviors, you should not use a Service." Service Android == System Service
  • 51. Business Services The layer service in N-Tiers architecture: It corresponds to the functional part of the application that implements the “Logic” and which describes the operations the application has to do on the data. The different Business Rules and System Controls are implemented in this layer. This is the treatments layer.
  • 52. Business Services Should be thought as an activity without UI 6 Services AndroidServices SingletonServices Insure unique instance(best to do that using a ServiceManager instead of static) Executed in the Main Thread Is made for long running process When active, Process is keept in the LRU-Cach as long as possible Bigger than a simple POJO Is lightweight (simple POJO) Your Business services are like this on server side You have to manage their life cycle. ??
  • 53. Business Services Services AndroidServices SingletonServices ?? Need to be launch by the system? Need to make some data caching?
  • 54. Business Services Services AndroidServices SingletonServices ?? Need to keep going without any visible activity (like Music Player)? No particular need
  • 56. Instantiate them only when needed With our Business Services we have to: ArchiDroid Instantiate them only once Be asynchronous Do not follow the life cycle of activities but the life cycle of the application Let their treatments end
  • 57. Instantiation on demand 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 View Presenter HumanService LazyLoading Services Manager Activity AndroidServices SingletonServices
  • 58. Threads management View Presenter HumanService Manage Threads Services Manager DAO Cancelable KeepAlive ThreadsPools
  • 59. public class ServiceManager { /** * The list of the bound services to this used to unbind the service. A service is pointed by its serviceConnection. */ List<ServiceConnection> boundServices = null; List<Service> serviceAndroid = null; List<ServiceBusiness> singletonServices = null; /** * Empty constructor to instantiate the list of bound services */ private ServiceManager() {boundServices = new ArrayList<ServiceConnection>();...} /** 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 MAppInstance.ins.getApplication().unbindService(sConn); } for (Service servAndroid: servicesAndroid) { servAndroid = null;} boundServices.clear(); //Do the same with your Singleton Service for (ServiceBuisness singleton : singletonServices) { singleton=null;} //Kill your executor services //the ones that has to let your thread finish //the ones that has to finish right now } Service Manager
  • 60. private ExecutorService keepAliveThreadsExcecutor = null; /*** @return the cancelableThreadsExceutor */ public final ExecutorService getKeepAliveThreadsExecutor() { if (keepAliveThreadsExceutor == null) { keepAliveThreadsExceutor = Executors.newFixedThreadPool(4, new BackgroundThreadFactory()); } return keepAliveThreadsExceutor; } /**ShutDown the ExecutorService but wait for thread to finish their job */ private void killKeepAliveThreadExecutor() { if (keepAliveThreadsExceutor != null) { keepAliveThreadsExceutor.shutdown(); // Disable new tasks from being submitted try {// as long as your threads hasn't finished while (!keepAliveThreadsExceutor.isTerminated()) { // Wait a while for existing tasks to terminate if (!keepAliveThreadsExceutor.awaitTermination(5, TimeUnit.SECONDS)) { // Cancel currently executing tasks keepAliveThreadsExceutor.shutdown(); Log.e("MyApp", "Probably a memory leak here"); } } } catch (InterruptedException ie) { keepAliveThreadsExceutor.shutdownNow(); keepAliveThreadsExceutor=null; Log.e("MyApp", "Probably a memory leak here too"); } } keepAliveThreadsExceutor=null;} Service Manager
  • 64. Keep the service alive (because keep ServiceManager alive) Keep the Application object alive (still Bound with the ServiceManager) Persist instantiation Application 0-1 HumanService Services Manager 0-1 Dead Lock occurs ! AndroidServices
  • 65. Keep the service alive (because keep ServiceManager alive) Keep the Application object alive (still Bound with the ServiceManager) Persist instantiation Application 0-1 HumanService Services Manager 0-1 Dead Lock occurs ! AndroidServices
  • 66. Garde le Service en vie (car conserve le ServiceManager en vie) Garde l'application en vie (car toujours Bound avec le ServiceManager) Persist instantiation Application 0-1 HumanService Services Manager 0-1 Dead Lock occurs ! AndroidServices DO NOT FOLLOW ACTIVITIES’ LIFE CYCLES FOLLOW APPLICATION’S LIFE CYCLE The solution :
  • 67. Application’s Life Cycle What is the life cycle of an application ? When there is no more visible activities since one second, I can consider the application is over.
  • 68. Application’s Life Cycle The One Second pattern: A release memory pattern IsActivity Alive 7 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
  • 69. Application’s Life Cycle React to onMemoryLow ApplicationServices Manager onLowMemory (...) System unbindAndDie() LazyLoading is our philosophy
  • 70. Be Asynchronous On Android, every body knows, we have to be asynchronous! Those who code the D.A.O. layer, know it. Those who code the View layer, know it. Thread(Thread(Thread(Thread(do something)))) Those who code the Service layer, know it. Those who code the Communication layer, know it.
  • 71. Be Asynchronous Only One Rule: The Service layer is your Asynchronicity gate. Each public method of each service class has to be executed in a background Thread. Nowhere else Threads are launched. (except for animation Threads in Ginger, putain de gingerbread) Use events to return result.
  • 72. Be Asynchronous public class MyBusinessService{... public void loadDataAsync(int itemId) { MyApp.instance.getServiceManager() .getCancelableThreadsExecutor() .submit(new RunnableLoadData(itemId)); } private class RunnableLoadData implements Runnable { public int itemId; public RunnableLoadData(int itemId) {this.itemId=itemId} public void run() { loadDataSync(itemId);} } public void loadDataSync(int itemId) { // your code here}
  • 73. You can use AysncTaskYou can use AysncTask Be Asynchronous You should use PoolExecutor and Runnables You can use IntentService https://www.youtube.com/watch?v=jtlRNNhane0&index=4&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE You can use HandlerThread
  • 74. Instanciate them only when needed Instanciate them only once Be asynchronous Do not follow the life cycle of activities but the life cycle of the application Let their treatments end With our Business Services, we wanted to: ArchiDroid
  • 75. Available on my GitHub I use Live Template to generate it What about the code arch_Service_Method_WithArgs arch_ServManager_CancelableThread arch_ServManager_KeepAliveThread arch_Service_Method And more...
  • 76.
  • 77. I can train your team ! Or
  • 78. And engage myself On the success of your Android product (with a high quality lens) I can be your Android tech lead

Editor's Notes

  1. 20 minutes
  2. La classe Dieu, elle fait tout dans une meme classe, presentation des données, interactions utilisateurs, animations, appel BD, appel réseau... 100 000 lignes de code, aucun tests
  3. La classe Dieu, elle fait tout dans une meme classe, presentation des données, interactions utilisateurs, animations, appel BD, appel réseau...
  4. Et on a inventé le MVC : decouple la vue, de l'interaction, de la representation.
  5. On a relié View et Controller, c'est là qu'on a mis les listener dans les vues
  6. La liaison est 1-1, on sait alors que c'est du pipo pour l'rdi que c'est fait pour les humains et pour les tests
  7. La classe Dieu, elle fait tout dans une meme classe, presentation des données, interactions utilisateurs, animations, appel BD, appel réseau...
  8. La classe Dieu, elle fait tout dans une meme classe, presentation des données, interactions utilisateurs, animations, appel BD, appel réseau...
  9. La classe Dieu, elle fait tout dans une meme classe, presentation des données, interactions utilisateurs, animations, appel BD, appel réseau...
  10. La classe Dieu, elle fait tout dans une meme classe, presentation des données, interactions utilisateurs, animations, appel BD, appel réseau...
  11. La classe Dieu, elle fait tout dans une meme classe, presentation des données, interactions utilisateurs, animations, appel BD, appel réseau...
  12. Grace a gradle et aux saveurs on peut automatiser les confs poru executer les tests
  13. Et aussi il y a du DataBinding
  14. J'ai vu des flux tweeter où les gars s'engueulaient pedant 500 tweets sur le sujet (mais tu fais du MVPM toi, ... blazbla)
  15. Principe de separation des couches, des responsabilités Isolation des composants = Interfaces Chaque bloc est indépendant des autres L'importance des flêches de dependence. Qui connait qui.? n-tier== n niveau logique (tier=niveau logique)
  16. Les services métiers ne sont pas des services Android ce sont les traitements métiers, la couche business/métier Les services Android c'est une toute autre notion
  17. On sépare le code, on le ventile, on l'aère
  18. A scindé en plein de partie, c'est globalement compliqué, mais localement simple
  19. Chaque couche est responsable d'une partie precise de l'application: Algorithme, HTTP, DAO, Vues...
  20. Car chaque couche/composant possède un contrat très précis décrit par son interface
  21. Car modulaire
  22. Car ils ne dependent de personne
  23. JUnit et bouchons
  24. Les tests apportent la sécurité pour le projet
  25. Les tests apportent la sécurité pour le projet
  26. 30 minutes
  27. En effet, les vues possèdent le MVP qui est rodé et sont gérées plus ou moins directement par le système Les couches Com et Dao n'ont rien de particulières dans ce système Il nous reste donc à affiner les services, leur instanciations, leur fonctionnement
  28. Le point fondamental de toute application est l'utilisation de l'objet application
  29. Le point fondamental de toute application est l'utilisation de l'objet application
  30. Tu dois te l'approprier car tu vas en avoir besoin un peu partout dans ton app.
  31. Le principe du Singleton est ultra important, la question que je me pose encore est quand est-ce qu'il doit être garbage collecté et si ça pose un problème.
  32. Le principe du Singleton est ultra important, la question que je me pose encore est quand est-ce qu'il doit être garbage collecté et si ça pose un problème.
  33. Le principe du Singleton est ultra important, la question que je me pose encore est quand est-ce qu'il doit être garbage collecté et si ça pose un problème.
  34. Le point fondamental de toute application est l'utilisation de l'objet application
  35. HandlerThread, c'est comme l'IntentService, ca nous donne un Thread avec son looper Pourquoi pas les AsyncTask... ben c'est que c'est facile de All Asynctask will use the same thread to execute themself=> it will be executed in sequential (can kill your work) How can you cancel an AsyncTask ??? => en fait n'annule pas la task mais annule le bordel et on passe dans onCancel et pas dans onPostExecite MemoryLeak (AsyncTask declare as an inner class of the Activity fuite memoire commune, ou qui pointe vers un champ de l'activité...)
  36. 15 minutes
  37. C'est là où GCManager ou JobScheduler entrent en action