am f0f5efbe: Android Training: Run in a Background Service
* commit 'f0f5efbea206fd0fbac655519f3f535620ed74cc':
Android Training: Run in a Background Service
diff --git a/docs/downloads/training/ThreadSample.zip b/docs/downloads/training/ThreadSample.zip
new file mode 100644
index 0000000..bdc3ccf
--- /dev/null
+++ b/docs/downloads/training/ThreadSample.zip
Binary files differ
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 c1cb590..f1fde86 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>