android pro recipes
Post on 17-May-2015
793 Views
Preview:
DESCRIPTION
TRANSCRIPT
Android Pro Recipes
Gabriel Dogarugdogaru@gmail.com
Iasi-JUG, December 11, 2013
Topics
● App Lifecycle● AsyncTask problems● Some frameworks
○ Otto○ Tape○ Dagger
Credits
● Android App Anatomy - Eric Burke● Concurrency in Android - G. Blake Meike ● infoq.com
Where it all starts - lifecyle
App runs forever
Install Uninstall
App runs forever
Process 1 P n…….
App runs forever
Process 1 P n…….
Activity Activity Activity Activity
Activity
App runs forever
Process 1 P n…….
Activity Activity ActivityFragment Fragment
App runs forever
Process 1 P n…….
Activity Activity ActivityFragment Fragment
RIP
App runs forever
Process 1 P n…….
Activity Activity ActivityFragment Fragment
RIP● Terminates application process● Managed by oom_adj● RIP Static Variables
App runs forever
Process 1 P n…….
Activity Activity ActivityFragment Fragment
RIP● Garbage collection
App runs forever
Process 1 P n…….
Activity Activity ActivityFragment Fragment
RIP
Why Care?
What about that background task?
AsyncTask ● enables proper and easy use of the UI thread.
● should ideally be used for short operations (a few
seconds at the most.)
AsyncTaskprivate class SomeTask extends AsyncTask<URL, Integer, Long> { protected Long doInBackground(URL... urls) { //do some stuff return result; }
protected void onProgressUpdate(Integer... progress) { //update progress if needed }
protected void onPreExecute(Long result) { //before }
protected void onPostExecute(Long result) { //after }}
App runs forever
Process 1 P n…….
Activity Activity Activity
AsyncTask
App runs forever
Process 1 P n…….
Activity Activity Activity
AsyncTask
Some AsyncTask
public static class BgTask extends AsyncTask<String, Void, String> { private final Activity act; public BgTask(Activity act) { this.act = act; } @Override protected String doInBackground(String... args) {
// … doesn't matter what goes here... } @Override protected void onPostExecute(String args) { act.onTaskComplete(args) }}
Some AsyncTask 2
public void initButton(Button button) { button.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... args) {// … doesn't matter what goes here... } @Override protected void onPostExecute(String args) { onTaskComplete(args) } } .execute(); } });}
What to do?
● Weak Reference● Persistent● Cancellable● Independent
Weak Reference
● Just make all references to the Activity weak
Weak Reference
● Just make all references to the Activity weak
DON’T
Persistent AsyncTask
● Best effort completion● Hold a reference to the task in static or Application● Manage references to Activities (onPause, onResume)● Preserving “single delivery” AsyncTask semanticsrequires some fancy state management
Persistent AsyncTaskpublic class SafeHeavyweightAsyncTaskActivity extends Activity implements HeavywightSafeTask.CompletionHandler{ static HeavywightSafeTask task; @Override public void onTaskComplete(String result) { task = null; ((TextView) findViewById(R.id.display)).setText(result); } @Override protected void onResume() { super.onResume(); if (null != task) { task.registerCompletionHdlr(this); }}
@Override protected void onPause() { super.onStop(); if (null != task) { task.registerCompletionHdlr(null); }} }
Persistent AsyncTaskpublic final class HeavywightSafeTask extends AsyncTask<String, Void, String> { public static interface CompletionHandler { void onTaskComplete(String result); } private enum State { EXECUTING, FINISHED, NOTIFIED; } private State state = State.EXECUTING; private CompletionHandler handler; private String result; public void registerCompletionHdlr(HeavywightSafeTask.CompletionHandler hdlr) { handler = hdlr; notifyHdlr(); } @Override protected String doInBackground(String... params) {// . . . } @Override protected void onPostExecute(String res) { result = res; state = State.FINISHED; notifyHdlr(); }// . . .
Persistent AsyncTask
// . . .private void notifyHdlr() { if (null == handler) { return; } switch (state) { case EXECUTING: break; case FINISHED: state = State.NOTIFIED; handler.onTaskComplete(result); break; case NOTIFIED: throw new IllegalStateException( "Attempt to register after notification"); }}}
Cancellable
● Addresses tasks that can be abandoned● Implement onCancel● Call it from onPause
Cancellable AsyncTaskpublic class SafeLightweightAsyncTaskActivity extends Activity implements LightweightSafeTask.CompletionHandler { LightweightSafeTask task;// . . . /** * @see android.app.Activity#onPause() */ @Override protected void onPause() { super.onPause(); if (null != task) { task.cancel(true); task = null; } }// . . .
Independent
● Use AsyncTask to submit tasks to a data layer
“If you respect users, persist tasksto disk.”- Jesse Wilson
Tape is a collection of queue-related classes for Android and Java by Square, Inc.
Client UI
Task Task Service
Server
Task Queueadd() peek()remove()
How to update the ui?
App runs forever
Process 1 P n…….
Activity Activity Activity
background task
How to update the ui?
App runs forever
Process 1 P n…….
Activity Activity Activity
background task
Events !!!!!
LocalBroadcastManager● standard Android way● we all read about it
Publish
Intent intent = new Intent(BroadcastIds.LOCATION_UPDATED_ACTION);
intent.putExtra(BroadcastIds.CURRENT_LOCATION_KEY,getCurrentLocation());
LocalBroadcastManager.getInstance( getActivity()).sendBroadcast(intent);
Subscribing
// MyActivity
BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive( Context context, Intent intent) { Location location = (Location) intent.getParcelableExtra( BroadcastIds.CURRENT_LOCATION_KEY); showLocation(location); }};
//….
Subscribe ….IntentFilter locationFilter = new IntentFilter( BroadcastIds.LOCATION_UPDATED_ACTION);
@Override public void onResume() { super.onResume(); LocalBroadcastManager.getInstance(getActivity()) .registerReceiver(receiver, locationFilter);}
@Override public void onPause() { super.onPause(); LocalBroadcastManager.getInstance(getActivity()) .unregisterReceiver(receiver);}
Really?
Otto
*from Square
Registration
public class BaseFragment extends Fragment { @Inject Bus bus; @Override public void onResume() { super.onResume(); bus.register(this); }
@Override public void onPause() { super.onPause(); bus.unregister(this); }}
Subscribing
@Subscribepublic void onLocationUpdated(Location l) { showLocation(l);}
Publishing
bus.post(getCurrentLocation());
//the first time
@Producepublic UserImage produceUserImage() { return cachedUserImage;}
Data Layer (Cache)
Bus
Activity
bus.post(...)@Produce
@Subscribe
Otto API Summary
● register(), unregister(), post()● @Subscribe, @Produce● Thread confinement● Compile time errors● Easy to test!
Dependency Injection to the Rescue
Dagger ● compile time injection● based on Google Guice
@Injectimport javax.inject.Inject; // JSR-330public class PublishFragment extends BaseFragment {
@Inject Bus bus; @Inject LocationManager locationManager; …
}
Constructor Injection
public class AccountUpdater { private final Bus bus; private final AccountService accounts; @Inject public AccountUpdater(Bus bus, AccountService accounts) { this.bus = bus; this.accounts = accounts; }}
Module
@Module(entryPoints = { MainActivity.class }) public static class ExampleModule { Context appContext;
public ExampleModule(Context appContext) { this.appContext = appContext; }
@Provides @Singleton Bus provideBus() { return new Bus(); } }}
Integration 2
public class ExampleApp extends Application { private ObjectGraph objectGraph;
@Override public void onCreate() { super.onCreate(); objectGraph = ObjectGraph.create(new ExampleModule(this)); }
public ObjectGraph objectGraph() { return objectGraph; }
public <T> T get(Class<T> clazz) { return objectGraph.get(clazz); }
Integration 3public class MainActivity extends Activity {
@Inject Bus bus;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
((ExampleApp) getApplication()).objectGraph().inject(this); }
}
Conclusions
● Managing the lifecycle can be tricky● Always think of the corner cases● Find the right tool to do the job and make
your life easier● Event architecture can help
Further studdy
Tape → square.github.com/tape/Otto → square.github.com/otto/Dagger → square.github.com/dagger
top related