Upload
anders-goeransson
View
37.579
Download
0
Embed Size (px)
DESCRIPTION
Citation preview
Efficient Android Threading
Anders Göransson
www.jayway.com
www.jayway.com/blog
www.oredev.org
Agenda
Optimize UI thread execution
Threads on Android
Asynchronous Techniques
Threads on Android
UI
AndroidApp
LinuxProcess
Native ThreadsJava Threads
BG BG BG
Android Scheduling
1. Foreground
2. Visible
3. Service
4. Background
Process level:
AndroidApp
Threads on Android
Android Scheduling
1. Foreground
2. Visible
3. Service
4. Background
Process level:
App A
App A
Foreground Thread Group
Background Thread Group
App BApp B
Threads on Android
> 90%
< 10%
Android Scheduling
1. Foreground
2. Visible
3. Service
4. Background
Process level:
App A
App A
Foreground Thread Group
Background Thread Group
App BApp B
Threads on Android
> 90%
< 10%
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
LifecyclesThreads on Android
Activity Service
BroadcastReceiver
ContentProvider
Android Components
Java Objects
BroadcastReceiver
Activity Service
ContentProvider
LinuxProcess
Threads
BGBG
BG
UI
Process
ApplicationStart
ApplicationEnd
LinuxProcess
Native Thread LifecycleThreads on Android
UI
BG
Time
Example: Activity Lifecycle
Time
ActivityComponent
onCreate() onDestroy() onCreate() onDestroy()
ActivityObject
new() GC
ActivityObject
new() GC
Threads on Android
Example: Activity Lifecycle
Time
ActivityComponent
onCreate() onDestroy() onCreate() onDestroy()
ActivityObject
new()
ActivityObject
new()
Threads on Android
Start
BG
Reference
Background Threads
• A thread is a GC root
• Implement cancellation policy for your background threads!
Threads on Android
Use Cases
Get off the UI thread
early!
Do long running task
Get off the UI thread
early!
Report result or
update UI
Do long running task
UIThread
BGThread
UIThread
BGThread
Goal
What technique shall I use for my background thread
execution?
Asynchronous Techniques
• Thread• Executor• HandlerThread• AsyncTask• Service• IntentService• AsyncQueryHandler• Loader
Thread
• Plain old Java Thread
Creation and StartThread
Thread t = new MyThread();t.start();
External Class
new Thread(new Runnable() {public void run() {
// Do long task}
}).start();
Anonymous Inner Class
Implicit reference to outer class
Pitfalls
• Non-retained threads
• Missing cancellation policy
• Starting over and over again
Thread
Good Use Cases
• One-shot tasks
• Post messages to the UI thread at end.
Thread
Thread
One shot tasks
Executor
• Powerful task execution framework.public interface Executor {
public void execute(Runnable r);
}
Executor
ExecutorService
ThreadPoolExecutor
ExecutorServiceExecutor
Task submission:
executorService.submit(MyTask);executorService.invokeAll(Collection<Tasks>);executorService.invokeAny(Collection<Tasks>);
Lifecycle management:
executorService.shutdown();executorService.shutdownNow();
Lifecycle observation:
executorService.isShutdown();executorService.isTerminated();executorService.awaitTermination();
RunningShutting
DownTerminated
shutdown()
Task / Execution Environment
Executor
Task:Independent unit of work executed anywhere
Runnablerun()
Callablecall()
Execution Environment:Technique used to execute the task
Executorexecute(Runnable)
Future future = executorService.submit(Callable);
FutureisDone()
isCancelled()cancel()
Task manager/observer:
Thread Pools
• Executor managing a pool of threads and a work queue.
• Reduces overhead of thread creation
Executor
Thread PoolsExecutor
Fixed Thread Pool Executors.newFixedThreadPool(3)
Cached Thread Pool Executors.newCachedThreadPool()
Single Thread Pool Executors.newSingleThreadExecutor()
Custom Thread Pool new ThreadPoolExecutor(corePoolSize, maximumPoolSize, aliveTime, unit, workQueue)
Pitfalls
• Lost thread safety when switching from sequential to concurrent execution
Executor
Good Use Cases
• Execute tasks concurrently• Multiple Http requests• Concurrent image processing• Use cases gaining performance from
concurrent execution.
• Lifecycle management and observation of task execution.
• Maximum platform utilization
Executor
Thread Executor
Execution abstractionRepetitive tasksConcurrent executionSequential executionExecution managementTask management
One shot tasks
HandlerThread
• Inherits from Thread and encapsulates a Looper-object.
• Thread with a message queue and processing loop.
• Handles both Message and Runnable.
Running Deadt.quit()t = new HandlerThread().start();
How it worksHandlerThread
HandlerThread
Create and Start
Add Process
Message Queue
1
23
t = new HandlerThread("BgThread");t.start();
1Handler h = new Handler(t.getLooper()) {
@Overridepublic void handleMessage(Message
msg) {//Process message
}};
2
h.sendEmptyMessage(42);3
HandlerHandlerThread
Runnable/Message submission:
Lifecycle management:
Runnable/Message removal:
removeCallbacks(Runnable);removeMessages(Message)
post(Runnable);postDelayed(Runnable);postAtTime(Runnable)postAtFrontOfQueue(Runnable);sendMessage(Message);sendMessageDelayed(Message);sendMessageAtTime(Message);sendMessageAtFrontOfQueue(Message);
Good Use Cases
• Keep a thread alive
• Sequential execution of messages• Avoid concurrent execution on multiple
button clicks• State machine• Detailed control of message processing.
HandlerThread
Thread
One shot tasks
Executor
HandlerThread
Concurrent executionOne shot tasks
Execution abstractionRepetitive tasksConcurrent executionSequential executionExecution managementTask management
“newSingleThreadExecutor”-alikeExecute Message and RunnableBetter clean up
AsyncTask
• Wraps Handler/Looper thread communication.
• Utilizes the Executor framework.• Callbacks for UI operations and
Background operation.
onCancelled()4b
How it worksAsyncTask
UIThread
BGThread
new AsyncTask.execute()1
onPreExecute()2
3doInBackground()
onPostExecute()4a
AsyncTask.cancel()
+
How it worksAsyncTask
public class MyAsyncTask extends AsyncTask<String, Void, Integer> {
@Overrideprotected void onPreExecute() {}
@Overrideprotected Integer doInBackground(String... params) {
return null;}
@Overrideprotected void onCancelled(Integer result) {}
@Overrideprotected void onPostExecute(Integer result) {}
}
public class MyActivity extends Activity {
public void onButtonClicked(View v) {new MyAsyncTask().execute("SomeInputString");
}}
Pitfalls
• Application Global Behavior
• execute()
• Cancellation
• Creation and Start
AsyncTask
Application Global BehaviorAsyncTask > Pitfalls
execute()
Queue Thread Pool
Activity
execute()Activity
execute()Service
execute()Receiver
execute()*
execute()
Execution behavior has changed over time
AsyncTask > Pitfalls
execute()< Donut:
execute()< Honeycomb:
execute()
executeOnExecutor(Executor)
>= Honeycomb:
execute()AsyncTask > Pitfalls
<uses-sdk android:targetSdkVersion="12" />
<uses-sdk android:targetSdkVersion="13" />
“So, if I call AsyncTask.execute on Honeycomb and later my tasks will run
sequentially, right?”
“Right?!?”
“Eh, it depends…”
CancellationAsyncTask > Pitfalls
• Cancel AsyncTask when component finishes lifecycle.• Avoid UI updates on unavailable component.
• cancel(true) == cancel(false) + interrupt()
• Implement cancellation policy.
Creation and StartAsyncTask > Pitfalls
• at = new AsyncTask()• The first creation decides callback thread
• onPostExecute()• onPublishProgress()• onCancelled()
• at.execute()• Callback thread of onPreExecute()
Thread Executor
HandlerThread
“newSingleThreadExecutor”Execute Message and RunnableBetter clean up
One shot tasks
AsyncTask
Subsequent execution
AsyncTask<Void, Void, Void>AsyncTask.execute(Runnable)
Task control
One task with UI callback
Execution abstractionRepetitive tasksConcurrent executionSequential executionExecution managementTask management
Concurrent execution
Service
• Background execution on the UI thread
• Decouple background threads with other lifecycles, typically the Activity lifecycle.
Example: Lifecycle Decoupling
Time
ActivityComponent
onCreate() onDestroy() onCreate() onDestroy()
Service
ServiceComponent
onCreate() onDestroy()
BG
Good Use Cases
• Tasks executed independently of user interaction.
• Tasks executing over several Activity lifecycles or configuration changes.
Service
Pitfalls
• Hidden AsyncTask.execute() with serial execution.
Service
Thread Executor
HandlerThread
One shot tasks
AsyncTask
Subsequent execution
AsyncTask<Void, Void, Void>AsyncTask.execute(Runnable)
One task with UI callback
Service
Activity lifecycle independent tasks
“newSingleThreadExecutor”Execute Message and RunnableBetter clean up
Execution abstractionRepetitive tasksConcurrent executionSequential executionExecution managementTask management
Concurrent execution
Task control
IntentService
• Service with a worker thread.
• On demand intents.
public class MyIntentService extends IntentService {
@Overrideprotected void onHandleIntent(Intent intent) {}
}
Lifecycle
Time
IntentService
IntentServiceComponent
onCreate() onDestroy()
Intent 1BG Intent 2 Intent 3 Intent n
stopSelf()
Good Use Cases
• Serially executed tasks decoupled from other component lifecycles.
• Off-load UI thread from BroadcastReceiver.
• REST client (ResultReceiver as callback)
IntentService
Thread Executor
HandlerThread
One shot tasks
AsyncTask
Subsequent execution
AsyncTask<Void, Void, Void>AsyncTask.execute(Runnable)
One task with UI callback
Service
Activity lifecycle independent tasks
IntentService
“On demand”
“Continuous”
“newSingleThreadExecutor”Execute Message and RunnableBetter clean up
Execution abstractionRepetitive tasksConcurrent executionSequential executionExecution managementTask management
Concurrent execution
Task control
AsyncQueryHandler
• API Level 1• Asynchronous operations on a
ContentResolver• Query• Insert• Delete• Update
• Wraps a HandlerThread
How it worksAsyncQueryHandler
UIThread
BGThread
new AsyncQueryHandler();1
startQuery();startInsert();startUpdate();startDelete();
2
onQueryComplete();onInsertComplete();onUpdateComplete();onDeleteComplete();
3
DB operations
Cons
• No cursor management• No content observation• No data retention on configuration
changes• Background thread can’t be forced to quit
AsyncQueryHandler
Thread Executor
HandlerThread
One shot tasks
AsyncTask
Subsequent execution
AsyncTask<Void, Void, Void>AsyncTask.execute(Runnable)
One task with UI callback
Service
Activity lifecycle independent tasks
IntentService
“On demand”
“Continuous”
AsyncQuery
Handler
Asynchronous CRUD
“newSingleThreadExecutor”Execute Message and RunnableBetter clean up
Execution abstractionRepetitive tasksConcurrent executionSequential executionExecution managementTask management
Task control
Concurrent execution
Loader
• API added in Honeycomb• Available in compatibility package• Load data in a background thread• Observes data changes• Retained on configuration changes• Connected to the Activity and Fragment
lifecycles
BasicsLoader
Data Source
Loader
1 Load data in BG 2 Observe data
3 Lifecycle management 4 Retained on configuration change
Data SourcesLoader
Any Data Source
ContentProvider
CustomLoader
CursorLoader
Hard Easy
How It WorksLoader
public class AndroidLoaderActivity extends ListActivity implements LoaderCallbacks<Cursor>{
SimpleCursorAdapter mAdapter;
public void onCreate(Bundle savedInstanceState) { getLoaderManager().initLoader(0, null, this); }
@Overridepublic Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(..., CONTENT_URI, ...);}
@Overridepublic void onLoadFinished(Loader<Cursor> loader, Cursor c) {
mAdapter.swapCursor(c);}
@Overridepublic void onLoaderReset(Loader<Cursor> arg0) {
mAdapter.swapCursor(null);}
}
PitfallsLoader
• Data loading will stop when Activity/Fragment is destroyed• Http requests not finished
Good Use CasesLoader
• Loading data from Content Providers.
Thread Executor
HandlerThread
One shot tasks
AsyncTask
Subsequent execution
AsyncTask<Void, Void, Void>AsyncTask.execute(Runnable)
One task with UI callback
Service
Activity lifecycle independent tasks
IntentService
“On demand”
“Continuous”
AsyncQuery
Handler
Asynchronous CRUD
Loader
Load data from CPData observing
Full CRUD
“newSingleThreadExecutor”Execute Message and RunnableBetter clean up
Execution abstractionRepetitive tasksConcurrent executionSequential executionExecution managementTask management
Task control
Concurrent execution
CustomLoader
Thank you for listening!
Questions?