am f0f5efbe: Android Training: Run in a Background Service

* commit 'f0f5efbea206fd0fbac655519f3f535620ed74cc':
  Android Training: Run in a Background Service
This commit is contained in:
Joe Malin
2012-12-13 16:15:36 -08:00
committed by Android Git Automerger
10 changed files with 512 additions and 404 deletions

Binary file not shown.

View File

@@ -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&lt;Cursor&gt; 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>

View File

@@ -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&lt;Cursor&gt; 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&lt;Cursor&gt; loader)
{
// Remove the reference to the current Cursor
mAdapter.swapCursor(null);
}
</pre>

View File

@@ -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>

View File

@@ -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&lt;Cursor&gt;}
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&lt;Cursor&gt;} 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&lt;Cursor&gt;
</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>

View File

@@ -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 {
&#64;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">&lt;service&gt;</a></code>
element that's a child of the
<code><a href="{@docRoot}guide/topics/manifest/application-element.html">
&lt;application&gt;</a></code> element:
</p>
<pre>
&lt;application
android:icon="&#64;drawable/icon"
android:label="&#64;string/app_name"&gt;
...
&lt;!--
Because android:exported is set to "false",
the service is only available to this app.
--&gt;
&lt;service
android:name=".RSSPullService"
android:exported="false"/&gt;
...
&lt;application/&gt;
</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">&lt;service&gt;</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>

View File

@@ -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>

View File

@@ -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
&#64;
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>

View File

@@ -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>

View File

@@ -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>