* commit '718c7484cf008d45f8501ae7d0cd57b31f935934': Android Training: Run in a Background Service
This commit is contained in:
BIN
docs/downloads/training/ThreadSample.zip
Normal file
BIN
docs/downloads/training/ThreadSample.zip
Normal file
Binary file not shown.
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
131
docs/html/training/run-background-service/create-service.jd
Normal file
131
docs/html/training/run-background-service/create-service.jd
Normal 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 {
|
||||
@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>
|
||||
68
docs/html/training/run-background-service/index.jd
Normal file
68
docs/html/training/run-background-service/index.jd
Normal 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>
|
||||
|
||||
199
docs/html/training/run-background-service/report-status.jd
Normal file
199
docs/html/training/run-background-service/report-status.jd
Normal 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
|
||||
@
|
||||
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>
|
||||
|
||||
82
docs/html/training/run-background-service/send-request.jd
Normal file
82
docs/html/training/run-background-service/send-request.jd
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user