diff --git a/docs/downloads/training/ThreadSample.zip b/docs/downloads/training/ThreadSample.zip new file mode 100644 index 0000000000000..bdc3ccfd7040a Binary files /dev/null and b/docs/downloads/training/ThreadSample.zip 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 f7978f4a89840..0000000000000 --- 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 - - -
- 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. -
-- 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 create 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. -
-
- 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 id
- value passed to {@link android.support.v4.app.LoaderManager#initLoader initLoader()}.
-
- 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
- context and uri arguments are required, but the others are optional.
- To use the default value for an optional argument, pass in null. The
- {@link android.support.v4.content.CursorLoader} runs the query against the
- {@link android.content.ContentProvider} identified by uri, just as if you had
- called {@link android.content.ContentResolver#query ContentResolver.query()} with the same
- arguments.
-
- For example: -
-
-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;
- }
-}
-
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 f8e003a3401fc..0000000000000
--- 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
-
-
-- {@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. -
-- 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. -
-- 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}. -
-- The first snippet shows the {@link android.widget.ListView} and - {@link android.support.v4.widget.SimpleCursorAdapter}: -
--// 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); --
- 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: -
-
-public void onLoadFinished(Loader<Cursor> loader, Cursor cursor)
-{
- /*
- * Move the results into the adapter. This
- * triggers the ListView to re-display.
- */
- mAdapter.swapCursor(cursor);
-}
-
-- 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. -
-- For example: -
-
-public void onLoaderReset(Loader<Cursor> loader)
-{
- // Remove the reference to the current Cursor
- mAdapter.swapCursor(null);
-}
-
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 574a32cc0e40d..0000000000000
--- 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
-- 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. -
-- {@link android.support.v4.content.CursorLoader} has these advantages over alternate ways of - running a query: -
-- 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}. -
-- 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. -
-- You create a {@link android.support.v4.content.CursorLoader} within a - loader framework. 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. -
-- Note: 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. -
-- 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. -
-- 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. -
-- 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}. -
-- For example: -
--public class DisplayActivity extends FragmentActivity - implements LoaderManager.LoaderCallbacks<Cursor> --
- 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: -
-
-private LoaderManager mLoaderManager;
-public void onCreate() {
-...
-mLoaderManager = this.getSupportLoaderManager();
-
-- 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: -
--// CursorLoader instance identifier -public static final int URL_LOADER = 0; -... -// Initializes the CursorLoader -getSupportLoaderManager().initLoader(URL_LOADER, null, this); -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 0000000000000..5f4799c75eb04 --- /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 +
ThreadSample.zip
++ 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} +
++ An {@link android.app.IntentService} has a few limitations: +
++ However, in most cases an {@link android.app.IntentService} is the preferred way to simple + background operations. +
++ 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. +
++ 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: +
+
+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
+ ...
+ }
+}
+
++ 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. +
+
+ An {@link android.app.IntentService} also needs an entry in your application manifest.
+ Provide this entry as a
+ <service>
+ element that's a child of the
+
+ <application> element:
+
+ <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/> ++
+ The attribute android:name specifies the class name of the
+ {@link android.app.IntentService}.
+
+ Notice that the
+ <service>
+ 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.
+
+ 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. +
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 0000000000000..173b87a27b4ce --- /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 +ThreadSample.zip
++ 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}. +
++ This class describes how to implement an {@link android.app.IntentService}, send it work + requests, and report its results to other components. +
+ThreadSample.zip
++ 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. +
++ 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}. +
++ 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()}. +
++ For example: +
+
+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);
+...
+}
+
++ The next step is to handle the incoming broadcast {@link android.content.Intent} objects in + the component that sent the original work request. +
++ + 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()}. +
++ For example: +
+
+// 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.
+ */
+...
+ }
+}
+
++ 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: +
+
+// 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");
+ ...
+
++ 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}: +
++ // Instantiates a new DownloadStateReceiver + DownloadStateReceiver mDownloadStateReceiver = + new DownloadStateReceiver(); + // Registers the DownloadStateReceiver and its intent filters + LocalBroadcastManager.getInstance(this).registerReceiver( + mDownloadStateReceiver, + mStatusIntentFilter); + ... ++
+ 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: +
++ /* + * 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); ++
+ 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}. Never start an + {@link android.app.Activity} in response to an incoming broadcast + {@link android.content.Intent}. +
++ +
+ 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 0000000000000..5b1114d47cf1d --- /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 +ThreadSample.zip
++ 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} +
++ 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()}. +
++ The next snippets demonstrate this: +
+RSSPullService.
+ +/* + * 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)); ++
+// Starts the IntentService +getActivity().startService(mServiceIntent); ++
+ 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. +
++ 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. +
++ 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}. +
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index ba9bbcfe023eb..0f6994ebcc922 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -192,7 +192,7 @@ - +