diff options
author | Joe Malin <jmalin@google.com> | 2012-12-13 16:18:19 -0800 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2012-12-13 16:18:19 -0800 |
commit | 28cb615003b1f96f7e9e579a7859094f4598e580 (patch) | |
tree | 05986620b31d8ec9e971dc0a1e168e27d1c6e6a3 /docs | |
parent | 538c8d0a467187008b5e2249fdbea153d598f462 (diff) | |
parent | 7096a17e953d7e126e6ac8952b38920e0ea7e7e1 (diff) | |
download | frameworks_base-28cb615003b1f96f7e9e579a7859094f4598e580.zip frameworks_base-28cb615003b1f96f7e9e579a7859094f4598e580.tar.gz frameworks_base-28cb615003b1f96f7e9e579a7859094f4598e580.tar.bz2 |
am 7096a17e: am 718c7484: am f0f5efbe: Android Training: Run in a Background Service
* commit '7096a17e953d7e126e6ac8952b38920e0ea7e7e1':
Android Training: Run in a Background Service
Diffstat (limited to 'docs')
-rw-r--r-- | docs/downloads/training/ThreadSample.zip | bin | 0 -> 75204 bytes | |||
-rw-r--r-- | docs/html/training/load-data-background/define-launch-query.jd | 83 | ||||
-rw-r--r-- | docs/html/training/load-data-background/handle-results.jd | 104 | ||||
-rw-r--r-- | docs/html/training/load-data-background/index.jd | 117 | ||||
-rw-r--r-- | docs/html/training/load-data-background/setup-loader.jd | 90 | ||||
-rw-r--r-- | docs/html/training/run-background-service/create-service.jd | 131 | ||||
-rw-r--r-- | docs/html/training/run-background-service/index.jd | 68 | ||||
-rw-r--r-- | docs/html/training/run-background-service/report-status.jd | 199 | ||||
-rw-r--r-- | docs/html/training/run-background-service/send-request.jd | 82 | ||||
-rw-r--r-- | docs/html/training/training_toc.cs | 42 |
10 files changed, 512 insertions, 404 deletions
diff --git a/docs/downloads/training/ThreadSample.zip b/docs/downloads/training/ThreadSample.zip Binary files differnew file mode 100644 index 0000000..bdc3ccf --- /dev/null +++ b/docs/downloads/training/ThreadSample.zip diff --git a/docs/html/training/load-data-background/define-launch-query.jd b/docs/html/training/load-data-background/define-launch-query.jd deleted file mode 100644 index f7978f4..0000000 --- a/docs/html/training/load-data-background/define-launch-query.jd +++ /dev/null @@ -1,83 +0,0 @@ -page.title=Defining and Launching the Query -trainingnavtop=true -startpage=true - -@jd:body - -<!-- This is the training bar --> -<div id="tb-wrapper"> - <div id="tb"> -<h2>This lesson teaches you to</h2> -<ol> - <li> - <a href="#DefineLaunch">Define and Launch the Query</a> - </li> -</ol> - </div> -</div> - -<p> - To perform a query, create the {@link android.support.v4.content.CursorLoader}, set up its - query, and pass it to the loader framework. From then on, the framework manages everything. - It runs the query on a background thread, returns the results to the foreground, and - watches for changes to the data associated with the query. -</p> -<p> - Pass a {@link android.support.v4.content.CursorLoader} to the loader framework in - your implementation of - {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}. - The loader framework calls this method when you <i>create</i> a loader by calling - {@link android.support.v4.app.LoaderManager#initLoader initLoader()}. You can create - a {@link android.support.v4.content.CursorLoader} anywhere, - but the preferred way is to create it in - {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}, - because this defers creation until the object is actually needed. -</p> -<p> - Notice that {@link android.support.v4.app.LoaderManager#initLoader initLoader()} will only - {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} - if the {@link android.support.v4.content.CursorLoader} doesn't already exist; otherwise, it - re-uses the existing {@link android.support.v4.content.CursorLoader}. The loader framework - tracks {@link android.support.v4.content.CursorLoader} instance using the <code>id</code> - value passed to {@link android.support.v4.app.LoaderManager#initLoader initLoader()}. -</p> -<h2 id="DefineLaunch">Define and Launch the Query</h2> -<p> - To create a {@link android.support.v4.content.CursorLoader} and define its - query at the same time, call the constructor -{@link android.support.v4.content.CursorLoader#CursorLoader(Context, Uri, String[], String, String[], String) - CursorLoader(context, uri, projection, selection, selectionArgs, sortOrder)}. The - <code>context</code> and <code>uri</code> arguments are required, but the others are optional. - To use the default value for an optional argument, pass in <code>null</code>. The - {@link android.support.v4.content.CursorLoader} runs the query against the - {@link android.content.ContentProvider} identified by <code>uri</code>, just as if you had - called {@link android.content.ContentResolver#query ContentResolver.query()} with the same - arguments. -</p> -<p> - For example: -</p> -<pre> -public Loader<Cursor> onCreateLoader(int loaderID, Bundle bundle) -{ - /* - * Takes action based on the ID of the Loader that's being created - */ - switch (loaderID) { - case URL_LOADER: - /* - * Return a new CursorLoader - */ - return new CursorLoader( - this, // Context - DataProviderContract.IMAGE_URI, // Provider's content URI - PROJECTION, // Columns to return - null, // Return all rows - null, // No search arguments - null); // Default search order - default: - // An invalid id was passed in - return null; - } -} -</pre> diff --git a/docs/html/training/load-data-background/handle-results.jd b/docs/html/training/load-data-background/handle-results.jd deleted file mode 100644 index f8e003a..0000000 --- a/docs/html/training/load-data-background/handle-results.jd +++ /dev/null @@ -1,104 +0,0 @@ -page.title=Handling the Results -trainingnavtop=true -startpage=true - -@jd:body - -<!-- This is the training bar --> -<div id="tb-wrapper"> - <div id="tb"> -<h2>This lesson teaches you to</h2> -<ol> - <li> - <a href="#HandleResults">Handle Query Results</a> - </li> - <li> - <a href="#HandleReset">Clear Out Old Data</a></li> -</ol> - </div> -</div> - -<p> - {@link android.support.v4.content.CursorLoader} returns its query results to your - implementation of - {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished - LoaderCallbacks.onLoadFinished()}, in the form of a {@link android.database.Cursor}. In the - callback, you can update your data display, do further processing on the - {@link android.database.Cursor} data, and so forth. -</p> -<p> - When the loader framework detects changes to data associated with the query, - it resets the {@link android.support.v4.content.CursorLoader}, closes the current - {@link android.database.Cursor}, and then invokes your implementation of - {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()}. - Use this callback to delete references to the current {@link android.database.Cursor}; when the - loader framework destroys the {@link android.database.Cursor}, you won't have outstanding - references that cause memory leaks. -</p> -<h2 id="HandleFinished">Handle Query Results</h2> -<p> - The following two snippets are an example of displaying the results of a query, using a - {@link android.widget.ListView} backed by a - {@link android.support.v4.widget.SimpleCursorAdapter}. -</p> -<p> - The first snippet shows the {@link android.widget.ListView} and - {@link android.support.v4.widget.SimpleCursorAdapter}: -</p> -<pre> -// Gets a handle to the Android built-in ListView widget -mListView = ((ListView) findViewById(android.R.id.list)); -// Creates a CursorAdapter -mAdapter = - new SimpleCursorAdapter( - this, // Current context - R.layout.logitem, // View for each item in the list - null, // Don't provide the cursor yet - FROM_COLUMNS, // List of cursor columns to display - TO_FIELDS, // List of TextViews in each line - 0 // flags -); -// Links the adapter to the ListView -mListView.setAdapter(mAdapter); -</pre> -<p> - The next snippet shows an implementation of - {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()} - that moves the query results in the returned {@link android.database.Cursor} to the - {@link android.support.v4.widget.SimpleCursorAdapter}. Changing the - {@link android.database.Cursor} in the - {@link android.support.v4.widget.SimpleCursorAdapter} triggers a refresh of the - {@link android.widget.ListView} with the new data: -</p> -<pre> -public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) -{ - /* - * Move the results into the adapter. This - * triggers the ListView to re-display. - */ - mAdapter.swapCursor(cursor); -} -</pre> -<h2 id="HandleReset">Handle a Loader Reset</h2> -<p> - The loader framework resets the {@link android.support.v4.content.CursorLoader} whenever the - {@link android.database.Cursor} becomes invalid. This usually occurs because the data associated - with the {@link android.database.Cursor} has changed. Before re-running the query, - the framework calls your implementation of - {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()}. In - this callback, make sure to prevent memory leaks by deleting all references to the current - {@link android.database.Cursor}. Once you return from - {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()}, - the loader framework re-runs the query. -</p> -<p> - For example: -</p> -<pre> -public void onLoaderReset(Loader<Cursor> loader) -{ - // Remove the reference to the current Cursor - mAdapter.swapCursor(null); -} -</pre> diff --git a/docs/html/training/load-data-background/index.jd b/docs/html/training/load-data-background/index.jd deleted file mode 100644 index 574a32c..0000000 --- a/docs/html/training/load-data-background/index.jd +++ /dev/null @@ -1,117 +0,0 @@ -page.title=Loading Data in the Background -trainingnavtop=true -startpage=true - -@jd:body -<div id="tb-wrapper"> -<div id="tb"> - -<!-- Required platform, tools, add-ons, devices, knowledge, etc. --> -<h2>Dependencies and prerequisites</h2> -<h3>Dependencies</h3> -<ul> - <li> - Android 1.6 or later - </li> -</ul> -<h3>Prerequisites</h3> -<ul> - <li> - <a href="{@docRoot}training/basics/firstapp/index.html">Building Your First App</a> class - </li> - <li> - <a href="{@docRoot}training/basics/activity-lifecycle/index.html"> - Managing the Activity Lifecycle</a> class - </li> -</ul> - -<!-- related docs (NOT javadocs) --> -<h2>You should also read</h2> -<ul> - <li> - <a href="{@docRoot}guide/components/loaders.html">Loaders</a> - </li> - <li> - <a href="{@docRoot}guide/topics/data/data-storage.html#db">Using Databases</a> - </li> - <li> -<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">Content Provider Basics</a> - </li> -</ul> -</div> -</div> -<p> - A {@link android.support.v4.content.CursorLoader} runs a query against a - {@link android.content.ContentProvider} on a background thread and returns a - {@link android.database.Cursor} to the main thread. -</p> -<p> - {@link android.support.v4.content.CursorLoader} has these advantages over alternate ways of - running a query: -</p> -<dl> - <dt> - Query on a background thread - </dt> - <dd> - A {@link android.support.v4.content.CursorLoader} query runs asynchronously on a - background thread, so it doesn't cause "Application Not Responding" (ANR) errors on the UI - thread. {@link android.support.v4.content.CursorLoader} creates and starts the - background thread; all you have to do is initialize the loader framework and handle the - results of the query. - </dd> - <dt> - Automatic re-query - </dt> - <dd> - A {@link android.support.v4.content.CursorLoader} automatically runs a new query when - the loader framework detects that the data underlying the {@link android.database.Cursor} - has changed. - </dd> - <dt> - Simple API - </dt> - <dd> - The {@link android.support.v4.content.CursorLoader} API provides the - query framework and cursor monitoring that you would have to define yourself if you used - {@link android.os.AsyncTask}. - </dd> -</dl> -<p> - A {@link android.support.v4.content.CursorLoader} is limited in that the query must be - against a {@link android.net.Uri} and must return a {@link android.database.Cursor}. Because of - this, a {@link android.support.v4.content.CursorLoader} can only run a query against a - {@link android.content.ContentProvider}. -</p> -<p> - This class describes how to define and use a {@link android.support.v4.content.CursorLoader}. - Examples in this class use the {@link android.support.v4 v4 support library} versions of - classes, which support platforms starting with Android 1.6. -</p> -<h2>Lessons</h2> -<dl> - <dt> - <strong><a href="setup-loader.html">Setting Up the Loader</a></strong> - </dt> - <dd> - Learn how to set up an {@link android.app.Activity} that inherits the necessary classes - for running a {@link android.support.v4.content.CursorLoader} and returning results. - </dd> - <dt> - <strong><a href="define-launch-query.html">Defining and Launching the Query</a></strong> - </dt> - <dd> - Learn how to perform a query against a {@link android.content.ContentProvider} using - a {@link android.support.v4.content.CursorLoader}. - </dd> - <dt> - <strong> - <a href="handle-results.html">Handling the Results</a> - </strong> - </dt> - <dd> - Learn how to handle the {@link android.database.Cursor} returned from the query, and how - to remove references to the current {@link android.database.Cursor} when the loader - framework re-sets the {@link android.support.v4.content.CursorLoader}. - </dd> -</dl> diff --git a/docs/html/training/load-data-background/setup-loader.jd b/docs/html/training/load-data-background/setup-loader.jd deleted file mode 100644 index 4b40611..0000000 --- a/docs/html/training/load-data-background/setup-loader.jd +++ /dev/null @@ -1,90 +0,0 @@ -page.title=Setting Up the Loader -trainingnavtop=true -startpage=true - -@jd:body - -<!-- This is the training bar --> -<div id="tb-wrapper"> - <div id="tb"> -<h2>This lesson teaches you to</h2> -<ol> - <li> - <a href="#AddExtensions">Extend an Activity</a> - </li> - <li> - <a href="#GetLoader">Retrieve a LoaderManager</a> - </li> - <li> - <a href="#InitializeLoader">Initialize the Loader Framework</a> - </li> -</ol> - </div> -</div> -<p> - You create a {@link android.support.v4.content.CursorLoader} within a - <b>loader framework</b>. To set up the framework, you implement the - {@link android.support.v4.app.LoaderManager.LoaderCallbacks LoaderCallbacks<Cursor>} - as part of an {@link android.app.Activity}. In addition, to provide compatibility - compatible with platform versions starting with Android 1.6, you must extend the - {@link android.app.Activity} with the {@link android.support.v4.app.FragmentActivity} class. -</p> -<p class="note"> - <strong>Note:</strong> A {@link android.support.v4.app.Fragment} is not a prerequisite for - {@link android.support.v4.content.CursorLoader}. As a convenience, the support library class - {@link android.support.v4.app.FragmentActivity} contains the fragment and the loader frameworks, - but they are completely independent of each other. -</p> -<p> - Before you can use the loader framework, you need to initialize it. To do this, retrieve - a {@link android.support.v4.app.LoaderManager} object and call its - {@link android.support.v4.app.LoaderManager#initLoader initLoader()} method. -</p> -<p> - If you do use one or more {@link android.support.v4.app.Fragment} objects in an - {@link android.app.Activity}, the {@link android.support.v4.app.LoaderManager} you retrieve is - available to all of them. -</p> -<h2 id="AddExtensions">Extend an Activity</h2> -<p> - To set up an {@link android.app.Activity} subclass to contain a - {@link android.support.v4.content.CursorLoader}, extend the subclass with - must extend {@link android.support.v4.app.FragmentActivity}, which provides the loader - framework, and implement the {@link android.support.v4.app.LoaderManager.LoaderCallbacks - LoaderCallbacks<Cursor>} interface, which specifies method signatures that the loader - framework uses to interact with the {@link android.app.Activity}. -</p> -<p> - For example: -</p> -<pre> -public class DisplayActivity extends FragmentActivity - implements LoaderManager.LoaderCallbacks<Cursor> -</pre> -<h2 id="GetLoader">Retrieve a LoaderManager</h2> -<p> - To get an instance {@link android.support.v4.app.LoaderManager} for use in your - {@link android.app.Activity}, call - {@link android.support.v4.app.FragmentActivity#getSupportLoaderManager - FragmentActivity.getSupportLoaderManager()} at the beginning of the - {@link android.app.Activity#onCreate onCreate()} method. For example: -</p> -<pre> -private LoaderManager mLoaderManager; -public void onCreate() { -... -mLoaderManager = this.getSupportLoaderManager(); -</pre> -<h2 id="InitializeLoader">Initialize the Loader Framework</h2> -<p> - Once you have the {@link android.support.v4.app.LoaderManager} object, initialize - it by calling {@link android.support.v4.app.LoaderManager#initLoader initLoader()}. For - example: -</p> -<pre> -// CursorLoader instance identifier -public static final int URL_LOADER = 0; -... -// Initializes the CursorLoader -getSupportLoaderManager().initLoader(URL_LOADER, null, this); -</pre> diff --git a/docs/html/training/run-background-service/create-service.jd b/docs/html/training/run-background-service/create-service.jd new file mode 100644 index 0000000..5f4799c --- /dev/null +++ b/docs/html/training/run-background-service/create-service.jd @@ -0,0 +1,131 @@ +page.title=Creating a Background Service +trainingnavtop=true +@jd:body +<div id="tb-wrapper"> +<div id="tb"> +<h2>This lesson teaches you to</h2> +<ol> + <li> + <a href="#CreateClass">Create an IntentService</a> + </li> + <li> + <a href="#DefineManifest">Define the IntentService in the Manifest</a> + </li> +</ol> +<h2>You should also read</h2> +<ul> + <li> +<a href="{@docRoot}guide/components/services.html#ExtendingIntentService">Extending the IntentService Class</a> + </li> + <li> + <a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a> + </li> +</ul> +<h2>Try it out</h2> + +<div class="download-box"> + <a href="{@docRoot}shareables/training/ThreadSample.zip" class="button">Download the sample</a> + <p class="filename">ThreadSample.zip</p> +</div> + +</div> +</div> +<p> + The {@link android.app.IntentService} class provides a straightforward structure for running + an operation on a single background thread. This allows it to handle long-running operations + without affecting your user interface's responsiveness. Also, an + {@link android.app.IntentService} isn't affected by most user interface lifecycle events, so it + continues to run in circumstances that would shut down an {@link android.os.AsyncTask} +</p> +<p> + An {@link android.app.IntentService} has a few limitations: +</p> +<ul> + <li> + It can't interact directly with your user interface. To put its results in the UI, you + have to send them to an {@link android.app.Activity}. + </li> + <li> + Work requests run sequentially. If an operation is running in an + {@link android.app.IntentService}, and you send it another request, the request waits until + the first operation is finished. + </li> + <li> + An operation running on an {@link android.app.IntentService} can't be interrupted. + </li> +</ul> +<p> + However, in most cases an {@link android.app.IntentService} is the preferred way to simple + background operations. +</p> +<p> + This lesson shows you how to create your own subclass of {@link android.app.IntentService}. + The lesson also shows you how to create the required callback method + {@link android.app.IntentService#onHandleIntent onHandleIntent()}. Finally, the lesson describes + shows you how to define the {@link android.app.IntentService} in your manifest file. +</p> +<h2 id="CreateClass">Create an IntentService</h2> +<p> + To create an {@link android.app.IntentService} component for your app, define a class that + extends {@link android.app.IntentService}, and within it, define a method that + overrides {@link android.app.IntentService#onHandleIntent onHandleIntent()}. For example: +</p> +<pre> +public class RSSPullService extends IntentService { + @Override + protected void onHandleIntent(Intent workIntent) { + // Gets data from the incoming Intent + String dataString = workIntent.getDataString(); + ... + // Do work here, based on the contents of dataString + ... + } +} +</pre> +<p> + Notice that the other callbacks of a regular {@link android.app.Service} component, such as + {@link android.app.Service#onStartCommand onStartCommand()} are automatically invoked by + {@link android.app.IntentService}. In an {@link android.app.IntentService}, you should avoid + overriding these callbacks. +</p> +<h2 id="DefineManifest">Define the IntentService in the Manifest</h2> +<p> + An {@link android.app.IntentService} also needs an entry in your application manifest. + Provide this entry as a + <code><a href="{@docRoot}guide/topics/manifest/service-element.html"><service></a></code> + element that's a child of the + <code><a href="{@docRoot}guide/topics/manifest/application-element.html"> + <application></a></code> element: +</p> +<pre> + <application + android:icon="@drawable/icon" + android:label="@string/app_name"> + ... + <!-- + Because android:exported is set to "false", + the service is only available to this app. + --> + <service + android:name=".RSSPullService" + android:exported="false"/> + ... + <application/> +</pre> +<p> + The attribute <code>android:name</code> specifies the class name of the + {@link android.app.IntentService}. +</p> +<p> + Notice that the + <code><a href="{@docRoot}guide/topics/manifest/service-element.html"><service></a></code> + element doesn't contain an intent filter. The {@link android.app.Activity} that sends work + requests to the service uses an explicit {@link android.content.Intent}, so no filter is needed. + This also means that only components in the same app or other applications with the same user ID + can access the service. +</p> +<p> + Now that you have the basic {@link android.app.IntentService} class, you can send work requests + to it with {@link android.content.Intent} objects. The procedure for constructing these objects + and sending them to your {@link android.app.IntentService} is described in the next lesson. +</p> diff --git a/docs/html/training/run-background-service/index.jd b/docs/html/training/run-background-service/index.jd new file mode 100644 index 0000000..173b87a --- /dev/null +++ b/docs/html/training/run-background-service/index.jd @@ -0,0 +1,68 @@ +page.title=Running in a Background Service +trainingnavtop=true +startpage=true +@jd:body +<div id="tb-wrapper"> +<div id="tb"> +<h2>Dependencies and prerequisites</h2> +<ul> + <li>Android 1.6 (API Level 4) or higher</li> +</ul> +<h2>You should also read</h2> +<ul> + <li> +<a href="{@docRoot}guide/components/services.html#ExtendingIntentService">Extending the IntentService Class</a> + </li> + <li> + <a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a> + </li> +</ul> +<h2>Try it out</h2> + +<div class="download-box"> + <a href="{@docRoot}shareables/training/ThreadSample.zip" class="button">Download the sample</a> + <p class="filename">ThreadSample.zip</p> +</div> + +</div> +</div> +<!-- ------------------------------------------------------------------------------------------- --> +<!-- Introduction --> +<!-- ------------------------------------------------------------------------------------------- --> +<p> + Unless you specify otherwise, most of the operations you do in an app run in the foreground on + a special thread called the UI thread. This can cause problems, because long-running operations + will interfere with the responsiveness of your user interface. This annoys your users, and can + even cause system errors. To avoid this, the Android framework offers several classes that + help you off-load operations onto a separate thread running in the background. The most useful + of these is {@link android.app.IntentService}. +</p> +<p> + This class describes how to implement an {@link android.app.IntentService}, send it work + requests, and report its results to other components. +</p> +<h2>Lessons</h2> +<dl> + <dt> + <b><a href="create-service.html">Creating a Background Service</a></b> + </dt> + <dd> + Learn how to create an {@link android.app.IntentService}. + </dd> + <dt> + <b><a href="send-request.html">Sending Work Requests to the Background Service</a></b> + </dt> + <dd> + Learn how to send work requests to an {@link android.app.IntentService}. + </dd> + <dt> + <b><a href="report-status.html">Reporting Work Status</a></b> + </dt> + <dd> + Learn how to use an {@link android.content.Intent} and a + {@link android.support.v4.content.LocalBroadcastManager} to communicate the status of a + work request from an {@link android.app.IntentService} to the + {@link android.app.Activity} that sent the request. + </dd> +</dl> + diff --git a/docs/html/training/run-background-service/report-status.jd b/docs/html/training/run-background-service/report-status.jd new file mode 100644 index 0000000..41121c1 --- /dev/null +++ b/docs/html/training/run-background-service/report-status.jd @@ -0,0 +1,199 @@ +page.title=Reporting Work Status +trainingnavtop=true +@jd:body +<div id="tb-wrapper"> +<div id="tb"> +<h2>This lesson teaches you to</h2> +<ol> + <li> + <a href="#ReportStatus">Report Status From an IntentService</a> + </li> + <li> + <a href="#ReceiveStatus">Receive Status Broadcasts from an IntentService</a> + </li> +</ol> +<h2>You should also read</h2> +<ul> + <li> + <a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a> + </li> + <li> + The section <b>Broadcast receivers</b> in the + <a href="{@docRoot}guide/components/fundamentals.html#Components">Application Components</a> + API guide. + </li> +</ul> +<h2>Try it out</h2> + +<div class="download-box"> + <a href="{@docRoot}shareables/training/ThreadSample.zip" class="button">Download the sample</a> + <p class="filename">ThreadSample.zip</p> +</div> + +</div> +</div> +<p> + This lesson shows you how to report the status of a work request run in a background service + to the component that sent the request. This allows you, for example, to report the status of + the request in an {@link android.app.Activity} object's UI. The recommended way to send and + receive status is to use a {@link android.support.v4.content.LocalBroadcastManager}, which + limits broadcast {@link android.content.Intent} objects to components in your own app. +</p> +<h2 id="ReportStatus">Report Status From an IntentService</h2> + +<p> + To send the status of a work request in an {@link android.app.IntentService} to other + components, first create an {@link android.content.Intent} that contains the status in its + extended data. As an option, you can add an action and data URI to this + {@link android.content.Intent}. +</p> +<p> + Next, send the {@link android.content.Intent} by calling + {@link android.support.v4.content.LocalBroadcastManager#sendBroadcast + LocalBroadcastManager.sendBroadcast()}. This sends the {@link android.content.Intent} to any + component in your application that has registered to receive it. + To get an instance of {@link android.support.v4.content.LocalBroadcastManager}, call + {@link android.support.v4.content.LocalBroadcastManager#getInstance getInstance()}. +</p> +<p> + For example: +</p> +<pre> +public final class Constants { + ... + // Defines a custom Intent action + public static final String BROADCAST_ACTION = + "com.example.android.threadsample.BROADCAST"; + ... + // Defines the key for the status "extra" in an Intent + public static final String EXTENDED_DATA_STATUS = + "com.example.android.threadsample.STATUS"; + ... +} +public class RSSPullService extends IntentService { +... + /* + * Creates a new Intent containing a Uri object + * BROADCAST_ACTION is a custom Intent action + */ + Intent localIntent = + new Intent(Constants.BROADCAST_ACTION) + // Puts the status into the Intent + .putExtra(Constants.EXTENDED_DATA_STATUS, status); + // Broadcasts the Intent to receivers in this app. + LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent); +... +} +</pre> +<p> + The next step is to handle the incoming broadcast {@link android.content.Intent} objects in + the component that sent the original work request. +</p> +<h2 id="ReceiveStatus">Receive Status Broadcasts from an IntentService</h2> +<p> + + To receive broadcast {@link android.content.Intent} objects, use a subclass of + {@link android.content.BroadcastReceiver}. In the subclass, implement the + {@link android.content.BroadcastReceiver#onReceive BroadcastReceiver.onReceive()} callback + method, which {@link android.support.v4.content.LocalBroadcastManager} invokes when it receives + an {@link android.content.Intent}. {@link android.support.v4.content.LocalBroadcastManager} + passes the incoming {@link android.content.Intent} to + {@link android.content.BroadcastReceiver#onReceive BroadcastReceiver.onReceive()}. +</p> +<p> + For example: +</p> +<pre> +// Broadcast receiver for receiving status updates from the IntentService +private class ResponseReceiver extends BroadcastReceiver +{ + // Prevents instantiation + private DownloadStateReceiver() { + } + // Called when the BroadcastReceiver gets an Intent it's registered to receive + @ + public void onReceive(Context context, Intent intent) { +... + /* + * Handle Intents here. + */ +... + } +} +</pre> +<p> + Once you've defined the {@link android.content.BroadcastReceiver}, you can define filters + for it that match specific actions, categories, and data. To do this, create + an {@link android.content.IntentFilter}. This first snippet shows how to define the filter: +</p> +<pre> +// Class that displays photos +public class DisplayActivity extends FragmentActivity { + ... + public void onCreate(Bundle stateBundle) { + ... + super.onCreate(stateBundle); + ... + // The filter's action is BROADCAST_ACTION + IntentFilter mStatusIntentFilter = new IntentFilter( + Constants.BROADCAST_ACTION); + + // Adds a data filter for the HTTP scheme + mStatusIntentFilter.addDataScheme("http"); + ... +</pre> +<p> + To register the {@link android.content.BroadcastReceiver} and the + {@link android.content.IntentFilter} with the system, get an instance of + {@link android.support.v4.content.LocalBroadcastManager} and call its + {@link android.support.v4.content.LocalBroadcastManager#registerReceiver registerReceiver()} + method. This next snippet shows how to register the {@link android.content.BroadcastReceiver} + and its {@link android.content.IntentFilter}: +</p> +<pre> + // Instantiates a new DownloadStateReceiver + DownloadStateReceiver mDownloadStateReceiver = + new DownloadStateReceiver(); + // Registers the DownloadStateReceiver and its intent filters + LocalBroadcastManager.getInstance(this).registerReceiver( + mDownloadStateReceiver, + mStatusIntentFilter); + ... +</pre> +<p> + A single {@link android.content.BroadcastReceiver} can handle more than one type of broadcast + {@link android.content.Intent} object, each with its own action. This feature allows you to + run different code for each action, without having to define a separate + {@link android.content.BroadcastReceiver} for each action. To define another + {@link android.content.IntentFilter} for the same + {@link android.content.BroadcastReceiver}, create the {@link android.content.IntentFilter} and + repeat the call to + {@link android.support.v4.content.LocalBroadcastManager#registerReceiver registerReceiver()}. + For example: +</p> +<pre> + /* + * Instantiates a new action filter. + * No data filter is needed. + */ + statusIntentFilter = new IntentFilter(Constants.ACTION_ZOOM_IMAGE); + ... + // Registers the receiver with the new filter + LocalBroadcastManager.getInstance(getActivity()).registerReceiver( + mDownloadStateReceiver, + mIntentFilter); +</pre> +<p> + Sending an broadcast {@link android.content.Intent} doesn't start or resume an + {@link android.app.Activity}. The {@link android.content.BroadcastReceiver} for an + {@link android.app.Activity} receives and processes {@link android.content.Intent} objects even + when your app is in the background, but doesn't force your app to the foreground. If you + want to notify the user about an event that happened in the background while your app was not + visible, use a {@link android.app.Notification}. <i>Never</i> start an + {@link android.app.Activity} in response to an incoming broadcast + {@link android.content.Intent}. +</p> +<p> + +</p> + diff --git a/docs/html/training/run-background-service/send-request.jd b/docs/html/training/run-background-service/send-request.jd new file mode 100644 index 0000000..5b1114d --- /dev/null +++ b/docs/html/training/run-background-service/send-request.jd @@ -0,0 +1,82 @@ +page.title=Sending Work Requests to the Background Service +trainingnavtop=true +@jd:body +<div id="tb-wrapper"> +<div id="tb"> +<h2>This lesson teaches you to</h2> +<ol> + <li> +<a href="#CreateRequest">Create and Send a Work Request to an IntentService</a> + </li> +</ol> +<h2>You should also read</h2> +<ul> + <li> + <a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a> + </li> +</ul> +<h2>Try it out</h2> + +<div class="download-box"> + <a href="{@docRoot}shareables/training/ThreadSample.zip" class="button">Download the sample</a> + <p class="filename">ThreadSample.zip</p> +</div> + +</div> +</div> +<p> + The previous lesson showed you how to create an {@link android.app.IntentService} class. This + lesson shows you how to trigger the {@link android.app.IntentService} to run an operation by + sending it an {@link android.content.Intent}. This {@link android.content.Intent} can + contain optionally contain data for the {@link android.app.IntentService} to process. You can + send an {@link android.content.Intent} to an {@link android.app.IntentService} from any point + in an {@link android.app.Activity} or {@link android.app.Fragment} +</p> +<h2 id="CreateRequest">Create and Send a Work Request to an IntentService</h2> +<p> + To create a work request and send it to an {@link android.app.IntentService}, create an + explicit {@link android.content.Intent}, add work request data to it, and send it to + {@link android.app.IntentService} by calling + {@link android.content.Context#startService startService()}. +</p> +<p> + The next snippets demonstrate this: +</p> +<ol> + <li> + Create a new, explicit {@link android.content.Intent} for the + {@link android.app.IntentService} called <code>RSSPullService</code>. + <br> +<pre> +/* + * Creates a new Intent to start the RSSPullService + * IntentService. Passes a URI in the + * Intent's "data" field. + */ +mServiceIntent = new Intent(getActivity(), RSSPullService.class); +mServiceIntent.setData(Uri.parse(dataUrl)); +</pre> + </li> + <li> + Call {@link android.content.Context#startService startService()} + <br> +<pre> +// Starts the IntentService +getActivity().startService(mServiceIntent); +</pre> +</ol> +<p> + Notice that you can send the work request from anywhere in an Activity or Fragment. + For example, if you need to get user input first, you can send the request from a callback + that responds to a button click or similar gesture. +</p> +<p> + Once you call {@link android.content.Context#startService startService()}, + the {@link android.app.IntentService} does the work defined in its + {@link android.app.IntentService#onHandleIntent onHandleIntent()} method, and then stops itself. +</p> +<p> + The next step is to report the results of the work request back to the originating Activity + or Fragment. The next lesson shows you how to do this with a + {@link android.content.BroadcastReceiver}. +</p> diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index ba9bbcf..0f6994e 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -192,7 +192,7 @@ </ul> </li> </ul> - </li><!-- end getting started --> + </li><!-- end getting started --> <li class="nav-section"> @@ -605,7 +605,7 @@ <div class="nav-section-header"> <a href="<?cs var:toroot ?>training/notify-user/index.html" description= - "How to display messages called notifications outside of + "How to display messages called notifications outside of your application's UI." >Notifying the User</a> </div> @@ -679,19 +679,19 @@ zh-CN-lang="支持各种屏幕尺寸" ko-lang="다양한 화면 크기 지원" ja-lang="さまざまな画面サイズのサポート" - es-lang="Cómo admitir varios tamaños de pantalla" + es-lang="Cómo admitir varios tamaños de pantalla" >Supporting Different Screen Sizes</a> </li> <li><a href="/training/multiscreen/screendensities.html" zh-CN-lang="支持各种屏幕密度" ja-lang="さまざまな画面密度のサポート" - es-lang="Cómo admitir varias densidades de pantalla" + es-lang="Cómo admitir varias densidades de pantalla" >Supporting Different Screen Densities</a> </li> <li><a href="/training/multiscreen/adaptui.html" zh-CN-lang="实施自适应用户界面流程" ja-lang="順応性のある UI フローの実装" - es-lang="Cómo implementar interfaces de usuario adaptables" + es-lang="Cómo implementar interfaces de usuario adaptables" >Implementing Adaptive UI Flows</a> </li> </ul> @@ -845,7 +845,29 @@ </li> </ul> </li> - +<!-- Background Service --> + <li class="nav-section"> + <div class="nav-section-header"> + <a href="<?cs var:toroot ?>training/run-background-service/index.html" + description= + "How to improve UI performance and responsiveness by sending work to a + Service running in the background">Running in a Background Service</a> + </div> + <ul> + <li><a href="<?cs var:toroot ?>training/run-background-service/create-service.html"> + Creating a Background Service + </a> + </li> + <li><a href="<?cs var:toroot ?>training/run-background-service/send-request.html"> + Sending Work Requests to the Background Service + </a> + </li> + <li><a href="<?cs var:toroot ?>training/run-background-service/report-status.html"> + Reporting Work Status + </a> + </li> + </ul> + </li> <li class="nav-section"> <div class="nav-section-header"> @@ -862,25 +884,25 @@ <li><a href="/training/monitoring-device-state/battery-monitoring.html" zh-CN-lang="监控电池电量和充电状态" ja-lang="電池残量と充電状態の監視" - es-lang="Cómo controlar el nivel de batería y el estado de carga" + es-lang="Cómo controlar el nivel de batería y el estado de carga" >Monitoring the Battery Level and Charging State</a> </li> <li><a href="/training/monitoring-device-state/docking-monitoring.html" zh-CN-lang="确定和监控基座对接状态和类型" ja-lang="ホルダーの装着状態とタイプの特定と監視" - es-lang="Cómo determinar y controlar el tipo de conector y el estado de la conexión" + es-lang="Cómo determinar y controlar el tipo de conector y el estado de la conexión" >Determining and Monitoring the Docking State and Type</a> </li> <li><a href="/training/monitoring-device-state/connectivity-monitoring.html" zh-CN-lang="确定和监控网络连接状态" ja-lang="接続状態の特定と監視" - es-lang="Cómo determinar y controlar el estado de la conectividad" + es-lang="Cómo determinar y controlar el estado de la conectividad" >Determining and Monitoring the Connectivity Status</a> </li> <li><a href="/training/monitoring-device-state/manifest-receivers.html" zh-CN-lang="根据需要操作广播接收器" ja-lang="オンデマンドでのブロードキャスト レシーバ操作" - es-lang="Cómo manipular los receptores de emisión bajo demanda" + es-lang="Cómo manipular los receptores de emisión bajo demanda" >Manipulating Broadcast Receivers On Demand</a> </li> </ul> |