diff options
author | Joe Malin <jmalin@google.com> | 2012-11-05 17:22:24 -0800 |
---|---|---|
committer | Joe Malin <jmalin@google.com> | 2012-12-13 17:07:53 -0800 |
commit | ba34f097df278ce1861ebfecdaf634f519ba1f36 (patch) | |
tree | 43950be9af1ec1171dcb135836e9297a5021d072 /docs | |
parent | f0f5efbea206fd0fbac655519f3f535620ed74cc (diff) | |
download | frameworks_base-ba34f097df278ce1861ebfecdaf634f519ba1f36.zip frameworks_base-ba34f097df278ce1861ebfecdaf634f519ba1f36.tar.gz frameworks_base-ba34f097df278ce1861ebfecdaf634f519ba1f36.tar.bz2 |
Android Training: Loading Data in the Background
Change-Id: Ibb469cd068068b37ea95371afb7e4dca4535ba94
Diffstat (limited to 'docs')
-rw-r--r-- | docs/html/training/load-data-background/handle-results.jd | 137 | ||||
-rw-r--r-- | docs/html/training/load-data-background/index.jd | 77 | ||||
-rw-r--r-- | docs/html/training/load-data-background/setup-loader.jd | 142 | ||||
-rw-r--r-- | docs/html/training/training_toc.cs | 3 |
4 files changed, 356 insertions, 3 deletions
diff --git a/docs/html/training/load-data-background/handle-results.jd b/docs/html/training/load-data-background/handle-results.jd new file mode 100644 index 0000000..ce0024f --- /dev/null +++ b/docs/html/training/load-data-background/handle-results.jd @@ -0,0 +1,137 @@ +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">Delete Old Cursor References</a></li> +</ol> + +<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> + As shown in the previous lesson, you should begin loading your data with a + {@link android.support.v4.content.CursorLoader} in your implementation of + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader + onCreateLoader()}. The loader then provides the query results to your + {@link android.app.Activity} or {@link android.support.v4.app.FragmentActivity} in your + implementation of {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished + LoaderCallbacks.onLoadFinished()}. One of the incoming arguments to this method is a + {@link android.database.Cursor} containing the query results. You can use this object to + update your data display or do further processing. +</p> +<p> + Besides + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} and + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}, + you also have to implement + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()}. + This method is invoked when {@link android.support.v4.content.CursorLoader} detects + that data associated with the {@link android.database.Cursor} has changed. When the + data changes, the framework also re-runs the current query. +</p> +<h2 id="HandleResults">Handle Query Results</h2> +<p> + To display {@link android.database.Cursor} data returned by + {@link android.support.v4.content.CursorLoader}, use a + {@link android.view.View} class that implements {@link android.widget.AdapterView} and + provide the view with an adapter that implements + {@link android.support.v4.widget.CursorAdapter}. The system then automatically moves data from + the {@link android.database.Cursor} to the view. +</p> +<p> + You can set up the linkage between the view and adapter before you have any data to display, + and then move a {@link android.database.Cursor} into the adapter in the + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()} + method. As soon as you move the {@link android.database.Cursor} into the adapter, the + system automatically updates the view. This also happens if you change the contents of the + {@link android.database.Cursor}. +</p> +<p> + For example: +</p> +<pre> +public String[] mFromColumns = { + DataProviderContract.IMAGE_PICTURENAME_COLUMN +}; +public int[] mToFields = { + R.id.PictureName +}; +// Gets a handle to a List View +ListView mListView = (ListView) findViewById(R.id.dataList); +/* + * Defines a SimpleCursorAdapter for the ListView + * + */ +SimpleCursorAdapter mAdapter = + new SimpleCursorAdapter( + this, // Current context + R.layout.list_item, // Layout for a single row + null, // No Cursor yet + mFromColumns, // Cursor columns to use + mToFields, // Layout fields to use + 0 // No flags + ); +// Sets the adapter for the view +mListView.setAdapter(mAdapter); +... +/* + * Defines the callback that {@link android.support.v4.content.CursorLoader} calls + * when it's finished its query + */ +@Override +public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { + ... + /* + * Moves the query results into the adapter, causing the + * ListView fronting this adapter to re-display + */ + mAdapter.changeCursor(cursor); +} +</pre> +<h2 id="HandleReset">Delete Old Cursor References</h2> +<p> + The {@link android.support.v4.content.CursorLoader} is reset whenever its + {@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, you should delete all references to the current {@link android.database.Cursor} + in order to prevent memory leaks. Once + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()} + finishes, {@link android.support.v4.content.CursorLoader} re-runs its query. +</p> +<p> + For example: +</p> +<pre> +/* + * Invoked when the CursorLoader is being reset. For example, this is + * called if the data in the provider changes and the Cursor becomes stale. + */ +@Override +public void onLoaderReset(Loader<Cursor> loader) { + + /* + * Clears out the adapter's reference to the Cursor. + * This prevents memory leaks. + */ + mAdapter.changeCursor(null); +} +</pre> diff --git a/docs/html/training/load-data-background/index.jd b/docs/html/training/load-data-background/index.jd new file mode 100644 index 0000000..dc9d84a --- /dev/null +++ b/docs/html/training/load-data-background/index.jd @@ -0,0 +1,77 @@ +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> +<ul> + <li> + Android 1.6 or later + </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> + +<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> + Querying a {@link android.content.ContentProvider} for data you want to display takes time. + If you run the query directly from an {@link android.app.Activity}, it may get blocked and + cause the system to issue an "Application Not Responding" message. Even if it doesn't, users + will see an annoying delay in the UI. To avoid these problems, you should initiate a query on a + separate thread, wait for it to finish, and then display the results. +</p> +<p> + You can do this in a straightforward way by using an object that runs a query asynchronously in + the background and reconnects to your {@link android.app.Activity} when it's finished. This + object is a {@link android.support.v4.content.CursorLoader}. Besides doing the initial + background query, a {@link android.support.v4.content.CursorLoader} automatically re-runs the + query when data associated with the query changes. +</p> +<p> + This class describes how to use a {@link android.support.v4.content.CursorLoader} to run a + background query. 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">Running a Query with a CursorLoader</a></strong> + </dt> + <dd> + Learn how to run a query in the background, using a + {@link android.support.v4.content.CursorLoader}. + </dd> + <dt> + <strong> + <a href="handle-results.html">Handling the Results</a> + </strong> + </dt> + <dd> + Learn how to handle the {@link android.database.Cursor} returned from the query, and how + to remove references to the current {@link android.database.Cursor} when the loader + framework re-sets the {@link android.support.v4.content.CursorLoader}. + </dd> +</dl> diff --git a/docs/html/training/load-data-background/setup-loader.jd b/docs/html/training/load-data-background/setup-loader.jd new file mode 100644 index 0000000..17fe7b0 --- /dev/null +++ b/docs/html/training/load-data-background/setup-loader.jd @@ -0,0 +1,142 @@ +page.title=Running a Query with a CursorLoader +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="#Extend">Define an Activity That Uses CursorLoader</a> + </li> + <li> + <a href="#InitializeLoader">Initialize the Query</a> + </li> + <li> + <a href="#DefineLaunch">Start the Query</a> + </li> +</ol> + +<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> + A {@link android.support.v4.content.CursorLoader} runs an asynchronous query in the background + against a {@link android.content.ContentProvider}, and returns the results to the + {@link android.app.Activity} or {@link android.support.v4.app.FragmentActivity} from which it + was called. This allows the {@link android.app.Activity} or + {@link android.support.v4.app.FragmentActivity} to continue to interact with the user while the + query is ongoing. +</p> +<h2 id="Extend">Define an Activity That Uses CursorLoader</h2> +<p> + To use a {@link android.support.v4.content.CursorLoader} with an + {@link android.app.Activity} or {@link android.support.v4.app.FragmentActivity}, use the + {@link android.support.v4.app.LoaderManager.LoaderCallbacks LoaderCallbacks<Cursor>} + interface. A {@link android.support.v4.content.CursorLoader} invokes callbacks defined + in this interface to communicate with the class; this lesson and the next one + describe each callback in detail. +</p> +<p> + For example, this is how you should define a {@link android.support.v4.app.FragmentActivity} + that uses the support library version of {@link android.support.v4.content.CursorLoader}. By + extending {@link android.support.v4.app.FragmentActivity}, you get support for + {@link android.support.v4.content.CursorLoader} as well as + {@link android.support.v4.app.Fragment}: +</p> +<pre> +public class PhotoThumbnailFragment extends FragmentActivity implements + LoaderManager.LoaderCallbacks<Cursor> { +... +} +</pre> +<h2 id="InitializeLoader">Initialize the Query</h2> +<p> + To initialize a query, call + {@link android.support.v4.app.LoaderManager#initLoader LoaderManager.initLoader()}. This + initializes the background framework. You can do this after the user has entered data that's + used in the query, or, if you don't need any user data, you can do it in + {@link android.support.v4.app.FragmentActivity#onCreate onCreate()} or + {@link android.support.v4.app.Fragment#onCreateView onCreateView()}. For example: +</p> +<pre> + // Identifies a particular Loader being used in this component + private static final int URL_LOADER = 0; + ... + /* When the system is ready for the Fragment to appear, this displays + * the Fragment's View + */ + public View onCreateView( + LayoutInflater inflater, + ViewGroup viewGroup, + Bundle bundle) { + ... + /* + * Initializes the CursorLoader. The URL_LOADER value is eventually passed + * to onCreateLoader(). + */ + getLoaderManager().initLoader(URL_LOADER, null, this); + ... + } +</pre> +<p class="note"> + <strong>Note:</strong> The method {@link android.support.v4.app.Fragment#getLoaderManager + getLoaderManager()} is only available in the {@link android.support.v4.app.Fragment} class. To + get a {@link android.support.v4.app.LoaderManager} in a + {@link android.support.v4.app.FragmentActivity}, call + {@link android.support.v4.app.FragmentActivity#getSupportLoaderManager + getSupportLoaderManager()}. +</p> +<h2 id="DefineLaunch">Start the Query</h2> +<p> + As soon as the background framework is initialized, it calls your implementation of + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}. + To start the query, return a {@link android.support.v4.content.CursorLoader} from this method. + You can instantiate an empty {@link android.support.v4.content.CursorLoader} and then use its + methods to define your query, or you can instantiate the object and define the query at the + same time: +</p> +<pre> +/* +* Callback that's invoked when the system has initialized the Loader and +* is ready to start the query. This usually happens when initLoader() is +* called. The loaderID argument contains the ID value passed to the +* initLoader() call. +*/ +@Override +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: + // Returns a new CursorLoader + return new CursorLoader( + getActivity(), // Parent activity context + mDataUrl, // Table to query + mProjection, // Projection to return + null, // No selection clause + null, // No selection arguments + null // Default sort order + ); + default: + // An invalid id was passed in + return null; + } +} +</pre> +<p> + Once the background framework has the object, it starts the query in the background. When the + query is done, the background framework calls + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}, + which is described in the next lesson. +</p> diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index f1fde86..e07e669 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -998,8 +998,6 @@ </li> </ul> </li> - - <li class="nav-section"> <div class="nav-section-header"> <a href="<?cs var:toroot ?>training/monetization/index.html" @@ -1020,7 +1018,6 @@ <!-- End best Publishing --> </ul><!-- nav --> - <script type="text/javascript"> <!-- buildToggleLists(); |