Part II CONCURRENCY IN ANDROID WorkerBackground Threads Async

Part II CONCURRENCY IN ANDROID

Worker/Background Threads Async. Task Loader Async. Task. Loader Cursor. Loader

Async. Tasks What is Async. Task It executes tasks in a background thread It can publish results on the UI thread It should be used for short operations Threading Rules Instances of Async. Task must be created in UI thread Async. Task#execute() must be invoked on UI thread. A task can only be executed once. Do not call on. Pre. Execute, do. In. Background, on. Progress. Update, on. Post. Execute manually

How To Create Async. Tasks Subclass Async. Task My. Async. Task extends Async. Task<Params, Progress, Result> {. . . } Three Generic Types Params: the type of the parameters sent to the task upon execution. Use Void if none Progress: the type of the progress units published during background execution. Use Void if none Result: the type of the result of the background computation. Use Void if none.

How To Create Async. Tasks Four Steps 1. on. Pre. Execute(): void executed on UI thread Used for task set up 2. do. In. Background(Params … params): Result Executed on the background thread The result must be returned from this Params are passed in from execute() �Access params as an array params[0], params[i] It may call publish. Update(Progress … progs) �e. g. , publish. Update(11, 32, 24) if Progress is Integer

How To Create Async. Tasks 3. on. Progress. Update(Progress … progs): void executed on UI thread progs are passed in from publish. Update() Access progs as an array, progs[0], progs[i] The timing of the execution this callback is undefined after publish. Update() was called. 4. on. Post. Execute(Result): void Executed on UI thread The result is the return from do. In. Background()

How To Start/Stop Async. Task To start Call Async. Task#execute(Params…) �E. g. , a. My. Async. Task. execute(“photo 1. jpg”, “photo 2. jpg”) if Params is String To cancel Call Async. Task#cancel(boolean my. Interrupt. If. Running) �E. g. , a. My. Async. Task. cancel(true) It returns true if successful If do. In. Background() has not started, the task is cancelled and do. In. Background() would not run else if may. Interrupt. If. Running interrupt the thread (raise the flag) else let do. In. Background() finish call on. Cancelled(Result) on UI thread (Result may be null) Returns false if task has completed, or already cancelled, or could not be cancelled. To really stop the task, In do. In. Background() Call is. Cancelled() on a regular basis to see if it is cancelled.

Order of Execution Async. Tasks may be executed concurrently or sequentially Before DONUT, tasks were executed serially on a single thread With DONUT, tasks were executed to a pool of threads With HONEYCOMB, tasks are executed on a thread � You may request for multiple threads using execute. On. Executor()

Simple. Async. Task Example 1 class Background. Task extends Async. Task<String, Integer> { private Weak. Reference<Context> m. Weak. Ref. Activity; private Weak. Reference<Progress. Bar> m. Weak. Ref. Progress. Bar; int total. Urls = 0; public Background. Task(Context context, Progress. Bar progress. Bar) { this. m. Weak. Ref. Activity = new Weak. Reference<Context>(context); this. m. Weak. Ref. Progress. Bar = new Weak. Reference<Progress. Bar>(progress. Bar); } // invoked in the UI thread @Override protected void on. Pre. Execute() { super. on. Pre. Execute(); display. Progress(); } // executed in its own thread @Override protected Integer do. In. Background(String. . . urls) { int success. Count = 0; total. Urls = urls. length; // Dummy code int i = 0; while ( !is. Cancelled() && i < total. Urls) { try { Thread. sleep(5000); // sleep 5 s - mimicking download } catch (Interrupted. Exception e) { e. print. Stack. Trace(); } Log. i("ASYNCTASK: ", urls[i]); // Log. Cat will display each URL success. Count++; publish. Progress(i); } // the following toast would cause an exception since it is NOT in UI thread //Toast. make. Text(main. Activity. Context, "Never Displayed", Toast. LENGTH_LONG). show(); return success. Count; }

Simple. Async. Task Example 2 class Background. Task extends Async. Task<String, Integer> {. . . // continued from previous slide // invoked in the UI thread @Override protected void on. Progress. Update(Integer. . . values) { super. on. Progress. Update(values); m. Weak. Ref. Progress. Bar. get(). set. Progress((values[0] + 1) * 10); update. Progress(values[0]+1); } // invoked in the UI thread @Override protected void on. Post. Execute(Integer result) { super. on. Post. Execute(result); dismiss. Progress. Bar(result); } private void display. Progress() { Context context = m. Weak. Ref. Activity. get(); if (context != null) { Toast. make. Text(context, "Started. . . ", Toast. LENGTH_LONG). show(); } } private void dismiss. Progress. Bar(Integer success. Count) { Context context = m. Weak. Ref. Activity. get(); if (context != null) { Toast. make. Text(context, "Done. . . ", Toast. LENGTH_LONG). show(); } } } private void update. Progress(int value) { float percentage = (float)value / total. Urls * 100; String text = "Downloading. . . "+percentage+"%"; Context context = m. Weak. Ref. Activity. get(); if (context != null) { Toast. make. Text(context, Toast. LENGTH_LONG). show(); } }

Simple. Async. Task Example 3 public class Simple. Async. Task extends Activity { Progress. Bar m. Progress. Bar; Background. Task m. Background. Task; @Override protected void on. Create(Bundle saved. Instance. State) { super. on. Create(saved. Instance. State); set. Content. View(R. layout. activity_simple_async_task); } @Override public boolean on. Create. Options. Menu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. get. Menu. Inflater(). inflate(R. menu. simple_async_task, menu); return true; } @Override public void on. Destroy() { super. on. Destroy(); m. Background. Task. cancel(true); } public void start. Downloading(View v) { m. Progress. Bar = (Progress. Bar)find. View. By. Id(R. id. progress_bar); // start the Async. Task with 10 URLs m. Background. Task = new Background. Task(get. Application. Context(), m. Progress. Bar); m. Background. Task. execute("url 0", "url 1", "url 2", "url 3", "url 4", "url 5", "url 6", "url 7", "url 8", "url 9"); } }

Simple. Async. Task Example 4 Layout file <Linear. Layout xmlns: android="http: //schemas. android. com/apk/res/android" xmlns: tools="http: //schemas. android. com/tools" android: layout_width="match_parent" android: layout_height="match_parent" android: orientation="vertical" tools: context=". Simple. Async. Task" > <Text. View android: layout_width="wrap_content" android: layout_height="wrap_content" android: text="@string/app_title" /> <Progress. Bar android: id="@+id/progress_bar" android: layout_width="fill_parent" android: layout_height="wrap_content" style="@android: style/Widget. Progress. Bar. Horizontal" android: layout_margin. Right="5 dp" /> <Button android: layout_width="fill_parent" android: layout_height="wrap_content" android: layout_margin. Right="5 dp" android: text="Download the file" android: on. Click="start. Downloading"/> </Linear. Layout>

Loaders Introduced in Android 3. 0 They are available to every Activity and Fragment They provide asynchronous loading of data They monitor data source and update automatically They automatically reconnect to the last loader’s cursor when being re-created after configuration changes

Loader API Summary Loader. Manager Each Activit/Fragment has one Loader. Manager It Manages one or more loader instances Loader. Manager. Loader. Callbacks A callback interface for a client to interact with Loader. Manager �Oncreate. Loader(), on. Load. Finished(), on. Loader. Reset() Loader A abstract class that performs asynchronous loading of data Async. Task. Loader An abstract loader that provide an Async. Task to the work Cursor. Loader A subclass of Async. Task. Loader that queries the Content. Resolver and returns a Cursor. Best for loading data from Content. Providers

Using loaders in an App Components used with Loaders An activity or Fragment An instance of Loader. Manager An Async. Task. Loader or Cursor. Loader to load data from custom source or Content. Provider An implementation of Loader. Manager. Loader. Callbacks A way of display the loader’s data, such as Simple. Cursor. Adapter A data source, such as a Content. Provider when using Cursor. Loader

Start a Loader get. Loader. Manager(). init. Loader(Loader_id, Bundle, Callbacks) �Loader_id: each id may have a unique id (0, 1, 2 …) �bundle: data to be passed on to the Loader �Callbacks: object that implements Loader. Manager. Loader. Callbacks. init. Loader() ensures a loader is created and active �If the loader by the id exists, the last one is reused �If the loaded data is available, on. Load. Finished() will be called right away. � Implies that the Loader. Callbacks instance must be created before you call init. Loader() �If the loader by the id does not exist, it triggers Loader. Manager. Loader. Callbacks#on. Create. Loader() init. Loader() does return the Loader just initialized. �Normally you don’t use this returned loader directly �Use the Loader. Manager and its callbacks to interact with the loader. Call init. Loader() in Activity#on. Create() or Fragment#on. Activity. Created()

Restart a Loader init. Loader() does not create a new loader if there is one with the same id Loaders, in particular Cursor. Loaders, are expected to retain their data after being stopped. This allows the apps to keep their data across the activity or fragments on. Stop() and on. Start() Sometimes you want to discard the old data and start over get. Loader. Manager. restart. Loader(loader_id, bundle, callbacks)

Loader. Manager: The 3 callbacks on. Create. Loader(loader_id, bundle): Loader Called when a new loader with loader_id needs to be created It returns a Loader to the Loader. Manager on. Load. Finished(Loader<D> loader, D data) Called when the loader has the requested data available loader. get. Id() can get the loader’s Id Data is the data loaded. D may be Cursor. When it is cursor, do not close it manually in your code, the Loader. Manager manages it. Here you may use the data � E. g. , m. Simple. Cursor. Adapter. swap(data); Don’t commit fragment transactions in this call since it may be called after the activity’s state has been saved. � A fragment transaction can only be created/committed prior to the activity saving its state. on. Loader. Reset() Called when the loader being reset, the data no longer available. You can release the reference to the data � E. g. , m. Simple. Cursor. Adapter. swap(null);

An Example - 1 Public class Cursor. Loader. List. Fragment extends List. Fragment implement Loader. Manager. Loader. Callbacks<Cursor> { Simple. Cursor. Adapter m. Adapter; void On. Activity. Created(Bundle data) { super. on. Activity. Created(data); m. Adapter = new Simple. Cursor. Adapter(get. Activity(), R. layout. my_layout, null, // we don’t have data yet, use null new String[] {Contacts. DISPLAY_NAME}, new int[] {R. id. name}, 0}; // since Loader monitors data changes, use 0 // so the adapter would not monitor the data set. List. Adapter(m. Adapter); // prepare the loader get. Loader. Manager(). init. Loader(3, null, this); } // return a Cursor. Loader<Cursor> on. Create. Loader(int id, Bundle args) { Uri base. Uri = Contacts. CONTENT_URI; String[] projections = new String[] {Contacts. DISPLAY_NAME}; String select = Contacts. DISPLAY_NAME + “ IS NOT NULL ”; String[] select. Args = null; String sort. Order = null; return new Cursor. Loader(get. Activity(), base. Uri, projections, select. Args, sort. Order); }

An Example - 2 Public class Cursor. Loader. List. Fragment extends List. Fragmen implement Loader. Manager. Loader. Callbacks<Cursor> {. . . void on. Load. Finished(Loader<Cursor> loader, Cursor data) { // now we have data, put it into the list view // do not try to close the old cursor, android takes care of it m. Adapter. swap. Cursor(data); } // if the cursor is about to be closed void on. Loader. Reset(Loader<Cursor> loader) { // called when the cursor is to be closed. // release the reference to the cursor m. Adapter. swap. Cursor(null); } }
- Slides: 20