diff options
Diffstat (limited to 'docs/html/training')
-rw-r--r-- | docs/html/training/articles/keystore.jd | 107 | ||||
-rw-r--r-- | docs/html/training/basics/network-ops/connecting.jd | 1 | ||||
-rw-r--r-- | docs/html/training/basics/network-ops/index.jd | 9 | ||||
-rw-r--r-- | docs/html/training/cloudsync/backupapi.jd | 2 | ||||
-rw-r--r-- | docs/html/training/cloudsync/index.jd | 10 | ||||
-rw-r--r-- | docs/html/training/contacts-provider/retrieve-names.jd | 12 | ||||
-rw-r--r-- | docs/html/training/training_toc.cs | 29 | ||||
-rw-r--r-- | docs/html/training/tv/index.jd | 59 | ||||
-rw-r--r-- | docs/html/training/tv/optimizing-layouts-tv.jd | 246 | ||||
-rw-r--r-- | docs/html/training/tv/optimizing-navigation-tv.jd | 206 | ||||
-rw-r--r-- | docs/html/training/tv/unsupported-features-tv.jd | 157 | ||||
-rw-r--r-- | docs/html/training/volley/index.jd | 133 | ||||
-rw-r--r-- | docs/html/training/volley/request-custom.jd | 163 | ||||
-rw-r--r-- | docs/html/training/volley/request.jd | 281 | ||||
-rw-r--r-- | docs/html/training/volley/requestqueue.jd | 204 | ||||
-rw-r--r-- | docs/html/training/volley/simple.jd | 169 |
16 files changed, 1114 insertions, 674 deletions
diff --git a/docs/html/training/articles/keystore.jd b/docs/html/training/articles/keystore.jd new file mode 100644 index 0000000..bbbda67 --- /dev/null +++ b/docs/html/training/articles/keystore.jd @@ -0,0 +1,107 @@ +page.title=Android Keystore System +@jd:body + +<div id="qv-wrapper"> + <div id="qv"> + <h2>In this document</h2> + <ol> + <li><a href="#WhichShouldIUse">Choosing Between a Keychain or the Android Keystore Provider</a></li> + <li><a href="#UsingAndroidKeyStore">Using Android Keystore Provider + </a></li> + <ol> + <li><a href="#GeneratingANewPrivateKey">Generating a New Private Key</a></li> + <li><a href="#WorkingWithKeyStoreEntries">Working with Keystore Entries</a></li> + <li><a href="#ListingEntries">Listing Entries</a></li> + <li><a href="#SigningAndVerifyingData">Signing and Verifying Data</a></li> + </ol> + </ol> + + <h2>Blog articles</h2> + <ol> + <li><a + href="http://android-developers.blogspot.com/2012/03/unifying-key-store-access-in-ics.html"> + <h4>Unifying Key Store Access in ICS</h4> + </a></li> + </ol> + </div> +</div> + +<p>The Android Keystore system lets you store private keys + in a container to make it more difficult to extract from the + device. Once keys are in the keystore, they can be used for + cryptographic operations with the private key material remaining + non-exportable.</p> + +<p>The Keystore system is used by the {@link + android.security.KeyChain} API as well as the Android + Keystore provider feature that was introduced in Android 4.3 + (API level 18). This document goes over when and how to use the + Android Keystore provider.</p> + +<h2 id="WhichShouldIUse">Choosing Between a Keychain or the +Android Keystore Provider</h2> + +<p>Use the {@link android.security.KeyChain} API when you want + system-wide credentials. When an app requests the use of any credential + through the {@link android.security.KeyChain} API, users get to + choose, through a system-provided UI, which of the installed credentials + an app can access. This allows several apps to use the + same set of credentials with user consent.</p> + +<p>Use the Android Keystore provider to let an individual app store its own + credentials that only the app itself can access. + This provides a way for apps to manage credentials that are usable + only by itself while providing the same security benefits that the + {@link android.security.KeyChain} API provides for system-wide + credentials. This method requires no user interaction to select the credentials.</p> + +<h2 id="UsingAndroidKeyStore">Using Android Keystore Provider</h2> + +<p> +To use this feature, you use the standard {@link java.security.KeyStore} +and {@link java.security.KeyPairGenerator} classes along with the +{@code AndroidKeyStore} provider introduced in Android 4.3 (API level 18).</p> + +<p>{@code AndroidKeyStore} is registered as a {@link + java.security.KeyStore} type for use with the {@link + java.security.KeyStore#getInstance(String) KeyStore.getInstance(type)} + method and as a provider for use with the {@link + java.security.KeyPairGenerator#getInstance(String, String) + KeyPairGenerator.getInstance(algorithm, provider)} method.</p> + +<h3 id="GeneratingANewPrivateKey">Generating a New Private Key</h3> + +<p>Generating a new {@link java.security.PrivateKey} requires that + you also specify the initial X.509 attributes that the self-signed + certificate will have. You can replace the certificate at a later + time with a certificate signed by a Certificate Authority.</p> + +<p>To generate the key, use a {@link java.security.KeyPairGenerator} + with {@link android.security.KeyPairGeneratorSpec}:</p> + +{@sample development/samples/ApiDemos/src/com/example/android/apis/security/KeyStoreUsage.java generate} + +<h3 id="WorkingWithKeyStoreEntries">Working with Keystore Entries</h3> + +<p>Using the {@code AndroidKeyStore} provider takes place through + all the standard {@link java.security.KeyStore} APIs.</p> + +<h4 id="ListingEntries">Listing Entries</h4> + +<p>List entries in the keystore by calling the {@link + java.security.KeyStore#aliases()} method:</p> + +{@sample development/samples/ApiDemos/src/com/example/android/apis/security/KeyStoreUsage.java list} + +<h4 id="SigningAndVerifyingData">Signing and Verifying Data</h4> + +<p>Sign data by fetching the {@link + java.security.KeyStore.Entry} from the keystore and using the + {@link java.security.Signature} APIs, such as {@link + java.security.Signature#sign()}:</p> + +{@sample development/samples/ApiDemos/src/com/example/android/apis/security/KeyStoreUsage.java sign} + +<p>Similarly, verify data with the {@link java.security.Signature#verify(byte[])} method:</p> + +{@sample development/samples/ApiDemos/src/com/example/android/apis/security/KeyStoreUsage.java verify} diff --git a/docs/html/training/basics/network-ops/connecting.jd b/docs/html/training/basics/network-ops/connecting.jd index 50a9e1b..1452ded 100644 --- a/docs/html/training/basics/network-ops/connecting.jd +++ b/docs/html/training/basics/network-ops/connecting.jd @@ -25,6 +25,7 @@ next.link=managing.html <h2>You should also read</h2> <ul> + <li><a href="{@docRoot}training/volley/index.html">Transmitting Network Data Using Volley</a></li> <li><a href="{@docRoot}training/monitoring-device-state/index.html">Optimizing Battery Life</a></li> <li><a href="{@docRoot}training/efficient-downloads/index.html">Transferring Data Without Draining the Battery</a></li> <li><a href="{@docRoot}guide/webapps/index.html">Web Apps Overview</a></li> diff --git a/docs/html/training/basics/network-ops/index.jd b/docs/html/training/basics/network-ops/index.jd index cb3a390..db64fe9 100644 --- a/docs/html/training/basics/network-ops/index.jd +++ b/docs/html/training/basics/network-ops/index.jd @@ -24,6 +24,7 @@ next.link=connecting.html <li><a href="{@docRoot}training/monitoring-device-state/index.html">Optimizing Battery Life</a></li> <li><a href="{@docRoot}training/efficient-downloads/index.html">Transferring Data Without Draining the Battery</a></li> <li><a href="{@docRoot}guide/webapps/index.html">Web Apps Overview</a></li> + <li><a href="{@docRoot}training/volley/index.html">Transmitting Network Data Using Volley</a></li> </ul> @@ -51,6 +52,14 @@ as a source of reusable code for your own application.</p> fundamental building blocks for creating Android applications that download content and parse data efficiently, while minimizing network traffic.</p> +<p class="note"><strong>Note:</strong> See the class <a href="{@docRoot} +training/volley/index.html">Transmitting Network Data Using Volley</a> +for information on Volley, an HTTP library that makes networking for Android apps +easier and faster. Volley is available through the open +<a href="https://android.googlesource.com/platform/frameworks/volley">AOSP</a> +repository. Volley may be able to help you streamline and improve the performance +of your app's network operations.</p> + <h2>Lessons</h2> diff --git a/docs/html/training/cloudsync/backupapi.jd b/docs/html/training/cloudsync/backupapi.jd index a5436c6..fd35ada 100644 --- a/docs/html/training/cloudsync/backupapi.jd +++ b/docs/html/training/cloudsync/backupapi.jd @@ -41,7 +41,7 @@ new devices using the Backup API.</p> <h2 id="register">Register for the Android Backup Service</h2> <p>This lesson requires the use of the <a - href="http://code.google.com/android/backup/index.html">Android Backup + href="{@docRoot}google/backup/index.html">Android Backup Service</a>, which requires registration. Go ahead and <a href="http://code.google.com/android/backup/signup.html">register here</a>. Once that's done, the service pre-populates an XML tag for insertion in your Android diff --git a/docs/html/training/cloudsync/index.jd b/docs/html/training/cloudsync/index.jd index 55b275b..8679009 100644 --- a/docs/html/training/cloudsync/index.jd +++ b/docs/html/training/cloudsync/index.jd @@ -6,6 +6,16 @@ startpage=true @jd:body +<div id="tb-wrapper"> +<div id="tb"> + +<h2>Dependencies and prerequisites</h2> +<ul> + <li>Android 2.2 (API level 8) and higher</li> +</ul> +</div> +</div> + <p>By providing powerful APIs for internet connectivity, the Android framework helps you build rich cloud-enabled apps that sync their data to a remote web service, making sure all your devices always stay in sync, and your valuable diff --git a/docs/html/training/contacts-provider/retrieve-names.jd b/docs/html/training/contacts-provider/retrieve-names.jd index b034a6a..7106889 100644 --- a/docs/html/training/contacts-provider/retrieve-names.jd +++ b/docs/html/training/contacts-provider/retrieve-names.jd @@ -102,9 +102,9 @@ trainingnavtop=true <p> To display the search results in a {@link android.widget.ListView}, you need a main layout file that defines the entire UI including the {@link android.widget.ListView}, and an item layout - file that defines one line of the {@link android.widget.ListView}. For example, you can define - the main layout file <code>res/layout/contacts_list_view.xml</code> that contains the - following XML: + file that defines one line of the {@link android.widget.ListView}. For example, you could create + the main layout file <code>res/layout/contacts_list_view.xml</code> with + the following XML: </p> <pre> <?xml version="1.0" encoding="utf-8"?> @@ -250,7 +250,8 @@ public class ContactsFragment extends Fragment implements public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the fragment layout - return inflater.inflate(R.layout.contacts_list_layout, container, false); + return inflater.inflate(R.layout.contact_list_fragment, + container, false); } </pre> <h3 id="DefineAdapter">Set up the CursorAdapter for the ListView</h3> @@ -268,7 +269,8 @@ public class ContactsFragment extends Fragment implements super.onActivityCreated(savedInstanceState); ... // Gets the ListView from the View list of the parent activity - mContactsList = (ListView) getActivity().findViewById(R.layout.contact_list_view); + mContactsList = + (ListView) getActivity().findViewById(R.layout.contact_list_view); // Gets a CursorAdapter mCursorAdapter = new SimpleCursorAdapter( getActivity(), diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index 0616b62..c5dc3c5 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -609,6 +609,35 @@ include the action bar on devices running Android 2.1 or higher." </li> </ul> </li> + <li class="nav-section"> + <div class="nav-section-header"> + <a href="<?cs var:toroot ?>training/volley/index.html" + description="How to perform fast, scalable UI operations over the network using Volley" + >Transmitting Network Data Using Volley</a> + </div> + <ul> + <li> + <a href="<?cs var:toroot ?>training/volley/simple.html"> + Sending a Simple Request + </a> + </li> + <li> + <a href="<?cs var:toroot ?>training/volley/requestqueue.html"> + Setting Up a RequestQueue + </a> + </li> + <li> + <a href="<?cs var:toroot ?>training/volley/request.html"> + Making a Standard Request + </a> + </li> + <li> + <a href="<?cs var:toroot ?>training/volley/request-custom.html"> + Implementing a Custom Request + </a> + </li> + </ul> + </li> </ul> </li> diff --git a/docs/html/training/tv/index.jd b/docs/html/training/tv/index.jd deleted file mode 100644 index 54f7016..0000000 --- a/docs/html/training/tv/index.jd +++ /dev/null @@ -1,59 +0,0 @@ -page.title=Designing for TV -page.tags="input","screens" - -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 2.0 (API Level 5) or higher</li> -</ul> - -</div> -</div> - -<a class="notice-developers-video wide" href="http://www.youtube.com/watch?v=zsRnRLh-O34"> -<div> - <h3>Video</h3> - <p>DevBytes: Design for Large Displays - Part 1</p> -</div> -</a> - -<p> - Smart TVs powered by Android bring your favorite Android apps to the best screen in your house. - Thousands of apps in the Google Play Store are already optimized for TVs. This class shows how - you can optimize your Android app for TVs, including how to build a layout that - works great when the user is ten feet away and navigating with a remote control. -</p> - -<h2>Lessons</h2> - -<dl> - <dt><b><a href="optimizing-layouts-tv.html">Optimizing Layouts for TV</a></b></dt> - <dd>Shows you how to optimize app layouts for TV screens, which have some unique characteristics such as: - <ul> - <li>permanent "landscape" mode</li> - <li>high-resolution displays</li> - <li>"10 foot UI" environment.</li> - </ul> - </dd> - - <dt><b><a href="optimizing-navigation-tv.html">Optimizing Navigation for TV</a></b></dt> - <dd>Shows you how to design navigation for TVs, including: - <ul> - <li>handling D-pad navigation</li> - <li>providing navigational feedback</li> - <li>providing easily-accessible controls on the screen.</li> - </ul> - </dd> - - <dt><b><a href="unsupported-features-tv.html">Handling features not supported on TV</a></b></dt> - <dd>Lists the hardware features that are usually not available on TVs. This lesson also shows you how to - provide alternatives for missing features or check for missing features and disable code at run time.</dd> -</dl> diff --git a/docs/html/training/tv/optimizing-layouts-tv.jd b/docs/html/training/tv/optimizing-layouts-tv.jd deleted file mode 100644 index a6db052..0000000 --- a/docs/html/training/tv/optimizing-layouts-tv.jd +++ /dev/null @@ -1,246 +0,0 @@ -page.title=Optimizing Layouts for TV -parent.title=Designing for TV -parent.link=index.html - -trainingnavtop=true -next.title=Optimizing Navigation for TV -next.link=optimizing-navigation-tv.html - -@jd:body - -<div id="tb-wrapper"> -<div id="tb"> - -<h2>This lesson teaches you to</h2> -<ol> - <li><a href="#DesignLandscapeLayouts">Design Landscape Layouts</a></li> - <li><a href="#MakeTextControlsEasyToSee">Make Text and Controls Easy to See</a></li> - <li><a href="#DesignForLargeScreens">Design for High-Density Large Screens</a></li> - <li><a href="#HandleLargeBitmaps">Design to Handle Large Bitmaps</a></li> -</ol> - -<h2>You should also read</h2> -<ul> - <li><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></li> -</ul> - -</div> -</div> - -<p> -When your application is running on a television set, you should assume that the user is sitting about -ten feet away from the screen. This user environment is referred to as the -<a href="http://en.wikipedia.org/wiki/10-foot_user_interface">10-foot UI</a>. To provide your -users with a usable and enjoyable experience, you should style and lay out your UI accordingly.. -</p> -<p> -This lesson shows you how to optimize layouts for TV by: -</p> -<ul> - <li>Providing appropriate layout resources for landscape mode.</li> - <li>Ensuring that text and controls are large enough to be visible from a distance.</li> - <li>Providing high resolution bitmaps and icons for HD TV screens.</li> -</ul> - -<h2 id="DesignLandscapeLayouts">Design Landscape Layouts</h2> - -<p> -TV screens are always in landscape orientation. Follow these tips to build landscape layouts optimized for TV screens: -</p> -<ul> - <li>Put on-screen navigational controls on the left or right side of the screen and save the - vertical space for content.</li> - <li>Create UIs that are divided into sections, by using <a href="{@docRoot}guide/components/fragments.html">Fragments</a> - and use view groups like {@link android.widget.GridView} instead - of {@link android.widget.ListView} to make better use of the - horizontal screen space.</li> - <li>Use view groups such as {@link android.widget.RelativeLayout} - or {@link android.widget.LinearLayout} to arrange views. - This allows the Android system to adjust the position of the views to the size, alignment, - aspect ratio, and pixel density of the TV screen.</li> - <li>Add sufficient margins between layout controls to avoid a cluttered UI.</li> -</ul> - -<p> -For example, the following layout is optimized for TV: -</p> - -<img src="{@docRoot}images/training/panoramio-grid.png" /> - -<p> -In this layout, the controls are on the lefthand side. The UI is displayed within a -{@link android.widget.GridView}, which is well-suited to landscape orientation. -In this layout both GridView and Fragment have the width and height set -dynamically, so they can adjust to the screen resolution. Controls are added to the left side Fragment programatically at runtime. -The layout file for this UI is {@code res/layout-land-large/photogrid_tv.xml}. -(This layout file is placed in {@code layout-land-large} because TVs have large screens with landscape orientation. For details refer to -<a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a>.)</p> - -res/layout-land-large/photogrid_tv.xml -<pre> -<RelativeLayout - android:layout_width="fill_parent" - android:layout_height="fill_parent" > - - <fragment - android:id="@+id/leftsidecontrols" - android:layout_width="0dip" - android:layout_marginLeft="5dip" - android:layout_height="match_parent" /> - - <GridView - android:id="@+id/gridview" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> - -</RelativeLayout> -</pre> - -<p> -To set up action bar items on the left side of the screen, you can also include the <a -href="http://code.google.com/p/googletv-android-samples/source/browse/#git%2FLeftNavBarLibrary"> -Left navigation bar library</a> in your application to set up action items on the left side -of the screen, instead of creating a custom Fragment to add controls: -</p> - -<pre> -LeftNavBar bar = (LeftNavBarService.instance()).getLeftNavBar(this); -</pre> - -<p> -When you have an activity in which the content scrolls vertically, always use a left navigation bar; -otherwise, your users have to scroll to the top of the content to switch between the content view and -the ActionBar. Look at the -<a href="http://code.google.com/p/googletv-android-samples/source/browse/#git%2FLeftNavBarDemo"> -Left navigation bar sample app</a> to see how to simple it is to include the left navigation bar in your app. -</p> - -<h2 id="MakeTextControlsEasyToSee">Make Text and Controls Easy to See</h2> -<p> -The text and controls in a TV application's UI should be easily visible and navigable from a distance. -Follow these tips to make them easier to see from a distance : -</p> - -<ul> - <li>Break text into small chunks that users can quickly scan.</li> - <li>Use light text on a dark background. This style is easier to read on a TV.</li> - <li>Avoid lightweight fonts or fonts that have both very narrow and very broad strokes. Use simple sans-serif - fonts and use anti-aliasing to increase readability.</li> - <li>Use Android's standard font sizes: - <pre> - <TextView - android:id="@+id/atext" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="center_vertical" - android:singleLine="true" - android:textAppearance="?android:attr/textAppearanceMedium"/> - </pre></li> - <li>Ensure that all your view widgets are large enough to be clearly visible to someone sitting 10 feet away - from the screen (this distance is greater for very large screens). The best way to do this is to use - layout-relative sizing rather than absolute sizing, and density-independent pixel units instead of absolute - pixel units. For example, to set the width of a widget, use wrap_content instead of a pixel measurement, - and to set the margin for a widget, use dip instead of px values. - </li> -</ul> -<p> - -</p> - -<h2 id="DesignForLargeScreens">Design for High-Density Large Screens</h2> - -<p> -The common HDTV display resolutions are 720p, 1080i, and 1080p. Design your UI for 1080p, and then -allow the Android system to downscale your UI to 720p if necessary. In general, downscaling (removing pixels) -does not degrade the UI (Notice that the converse is not true; you should avoid upscaling because it degrades -UI quality). -</p> - -<p> -To get the best scaling results for images, provide them as <a href="{@docRoot}tools/help/draw9patch.html"> -9-patch image</a> elements if possible. -If you provide low quality or small images in your layouts, they will appear pixelated, fuzzy, or grainy. This -is not a good experience for the user. Instead, use high-quality images. -</p> - -<p> -For more information on optimizing apps for large screens see <a href="{@docRoot}training/multiscreen/index.html"> -Designing for multiple screens</a>. -</p> - -<h2 id="HandleLargeBitmaps">Design to Handle Large Bitmaps</h2> - -<p> -The Android system has a limited amount of memory, so downloading and storing high-resolution images can often -cause out-of-memory errors in your app. To avoid this, follow these tips: -</p> - -<ul> - <li>Load images only when they're displayed on the screen. For example, when displaying multiple images in - a {@link android.widget.GridView} or - {@link android.widget.Gallery}, only load an image when - {@link android.widget.Adapter#getView(int, View, ViewGroup) getView()} - is called on the View's {@link android.widget.Adapter}. - </li> - <li>Call {@link android.graphics.Bitmap#recycle()} on - {@link android.graphics.Bitmap} views that are no longer needed. - </li> - <li>Use {@link java.lang.ref.WeakReference} for storing references - to {@link android.graphics.Bitmap} objects in an in-memory - {@link java.util.Collection}.</li> - <li>If you fetch images from the network, use {@link android.os.AsyncTask} - to fetch them and store them on the SD card for faster access. - Never do network transactions on the application's UI thread. - </li> - <li>Scale down really large images to a more appropriate size as you download them; otherwise, downloading the image - itself may cause an "Out of Memory" exception. Here is sample code that scales down images while downloading: - - <pre> - // Get the source image's dimensions - BitmapFactory.Options options = new BitmapFactory.Options(); - // This does not download the actual image, just downloads headers. - options.inJustDecodeBounds = true; - BitmapFactory.decodeFile(IMAGE_FILE_URL, options); - // The actual width of the image. - int srcWidth = options.outWidth; - // The actual height of the image. - int srcHeight = options.outHeight; - - // Only scale if the source is bigger than the width of the destination view. - if(desiredWidth > srcWidth) - desiredWidth = srcWidth; - - // Calculate the correct inSampleSize/scale value. This helps reduce memory use. It should be a power of 2. - int inSampleSize = 1; - while(srcWidth / 2 > desiredWidth){ - srcWidth /= 2; - srcHeight /= 2; - inSampleSize *= 2; - } - - float desiredScale = (float) desiredWidth / srcWidth; - - // Decode with inSampleSize - options.inJustDecodeBounds = false; - options.inDither = false; - options.inSampleSize = inSampleSize; - options.inScaled = false; - // Ensures the image stays as a 32-bit ARGB_8888 image. - // This preserves image quality. - options.inPreferredConfig = Bitmap.Config.ARGB_8888; - - Bitmap sampledSrcBitmap = BitmapFactory.decodeFile(IMAGE_FILE_URL, options); - - // Resize - Matrix matrix = new Matrix(); - matrix.postScale(desiredScale, desiredScale); - Bitmap scaledBitmap = Bitmap.createBitmap(sampledSrcBitmap, 0, 0, - sampledSrcBitmap.getWidth(), sampledSrcBitmap.getHeight(), matrix, true); - sampledSrcBitmap = null; - - // Save - FileOutputStream out = new FileOutputStream(LOCAL_PATH_TO_STORE_IMAGE); - scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out); - scaledBitmap = null; - </pre> - </li> </ul>
\ No newline at end of file diff --git a/docs/html/training/tv/optimizing-navigation-tv.jd b/docs/html/training/tv/optimizing-navigation-tv.jd deleted file mode 100644 index bb78258..0000000 --- a/docs/html/training/tv/optimizing-navigation-tv.jd +++ /dev/null @@ -1,206 +0,0 @@ -page.title=Optimizing Navigation for TV -parent.title=Designing for TV -parent.link=index.html - -trainingnavtop=true -previous.title=Optimizing Layouts for TV -previous.link=optimizing-layouts-tv.html -next.title=Handling Features Not Supported on TV -next.link=unsupported-features-tv.html - -@jd:body - -<div id="tb-wrapper"> -<div id="tb"> - -<h2>This lesson teaches you to</h2> -<ol> - <li><a href="#HandleDpadNavigation">Handle D-pad Navigation</a></li> - <li><a href="#HandleFocusSelection">Provide Clear Visual Indication for Focus and Selection</a></li> - <li><a href="#DesignForEasyNavigation">Design for Easy Navigation</a></li> -</ol> - -<h2>You should also read</h2> -<ul> - <li><a href="{@docRoot}training/design-navigation/index.html">Designing Effective Navigation</a></li> -</ul> - -</div> -</div> - -<p> -An important aspect of the user experience when operating a TV is the direct human interface: a remote control. -As you optimize your Android application for TVs, you should pay special attention to how the user actually navigates -around your application when using a remote control instead of a touchscreen. -</p> -<p> -This lesson shows you how to optimize navigation for TV by: -</p> - -<ul> - <li>Ensuring all layout controls are D-pad navigable.</li> - <li>Providing highly obvious feedback for UI navigation.</li> - <li>Placing layout controls for easy access.</li> -</ul> - -<h2 id="HandleDpadNavigation">Handle D-pad Navigation</h2> - -<p> -On a TV, users navigate with controls on a TV remote, using either a D-pad or arrow keys. -This limits movement to up, down, left, and right. -To build a great TV-optimized app, you must provide a navigation scheme in which the user can -quickly learn how to navigate your app using the remote. -</p> - -<p> -When you design navigation for D-pad, follow these guidelines: -</p> - -<ul> - <li>Ensure that the D-pad can navigate to all the visible controls on the screen.</li> - <li>For scrolling lists with focus, D-pad up/down keys scroll the list and Enter key selects an item in the list. Ensure that users can - select an element in the list and that the list still scrolls when an element is selected.</li> - <li>Ensure that movement between controls is straightforward and predictable.</li> -</ul> - -<p> -Android usually handles navigation order between layout elements automatically, so you don't need to do anything extra. If the screen layout -makes navigation difficult, or if you want users to move through the layout in a specific way, you can set up explicit navigation for your -controls. -For example, for an {@code android.widget.EditText}, to define the next control to receive focus, use: -<pre> -<EditText android:id="@+id/LastNameField" android:nextFocusDown="@+id/FirstNameField"\> -</pre> -The following table lists all of the available navigation attributes: -</p> - -<table> -<tr> -<th>Attribute</th> -<th>Function</th> -</tr> -<tr> -<td>{@link android.R.attr#nextFocusDown}</td> -<td>Defines the next view to receive focus when the user navigates down.</td> -</tr> -<tr> -<td>{@link android.R.attr#nextFocusLeft}</td> -<td>Defines the next view to receive focus when the user navigates left.</td> -</tr> -<tr> -<td>{@link android.R.attr#nextFocusRight}</td> -<td>Defines the next view to receive focus when the user navigates right.</td> -</tr> -<tr> -<td>{@link android.R.attr#nextFocusUp}</td> -<td>Defines the next view to receive focus when the user navigates up.</td> -</tr> -</table> - -<p> -To use one of these explicit navigation attributes, set the value to the ID (android:id value) of another widget in the layout. You should set -up the navigation order as a loop, so that the last control directs focus back to the first one. -</p> - -<p> -Note: You should only use these attributes to modify the navigation order if the default order that the system applies does not work well. -</p> - -<h2 id="HandleFocusSelection">Provide Clear Visual Indication for Focus and Selection</h2> - -<p> -Use appropriate color highlights for all navigable and selectable elements in the UI. This makes it easy for users to know whether the control -is currently focused or selected when they navigate with a D-pad. Also, use uniform highlight scheme across your application. -</p> - -<p> -Android provides <a href="{@docRoot}guide/topics/resources/drawable-resource.html#StateList">Drawable State List Resources</a> to implement highlights -for selected and focused controls. For example: -</p> - -res/drawable/button.xml: -<pre> -<?xml version="1.0" encoding="utf-8"?> -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="true" - android:drawable="@drawable/button_pressed" /> <!-- pressed --> - <item android:state_focused="true" - android:drawable="@drawable/button_focused" /> <!-- focused --> - <item android:state_hovered="true" - android:drawable="@drawable/button_focused" /> <!-- hovered --> - <item android:drawable="@drawable/button_normal" /> <!-- default --> -</selector> -</pre> - -<p> -This layout XML applies the above state list drawable to a {@link android.widget.Button}: -</p> -<pre> -<Button - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:background="@drawable/button" /> -</pre> - -<p> -Provide sufficient padding within the focusable and selectable controls so that the highlights around them are clearly visible. -</p> - -<h2 id="DesignForEasyNavigation">Design for Easy Navigation</h2> - -<p> -Users should be able to navigate to any UI control with a couple of D-pad clicks. Navigation should be easy and intuitive to -understand. For any non-intuitive actions, provide users with written help, using a dialog triggered by a help button or action bar icon. -</p> - -<p> -Predict the next screen that the user will want to navigate to and provide one click navigation to it. If the current screen UI is very sparse, -consider making it a multi pane screen. Use fragments for making multi-pane screens. For example, consider the multi-pane UI below with continent names -on the left and list of cool places in each continent on the right. -</p> - -<img src="{@docRoot}images/training/cool-places.png" alt="" /> - -<p> -The above UI consists of three Fragments - <code>left_side_action_controls</code>, <code>continents</code> and -<code>places</code> - as shown in its layout -xml file below. Such multi-pane UIs make D-pad navigation easier and make good use of the horizontal screen space for -TVs. -</p> -res/layout/cool_places.xml -<pre> -<LinearLayout - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="horizontal" - > - <fragment - android:id="@+id/left_side_action_controls" - android:layout_width="0px" - android:layout_height="match_parent" - android:layout_marginLeft="10dip" - android:layout_weight="0.2"/> - <fragment - android:id="@+id/continents" - android:layout_width="0px" - android:layout_height="match_parent" - android:layout_marginLeft="10dip" - android:layout_weight="0.2"/> - - <fragment - android:id="@+id/places" - android:layout_width="0px" - android:layout_height="match_parent" - android:layout_marginLeft="10dip" - android:layout_weight="0.6"/> - -</LinearLayout> -</pre> - -<p> -Also, notice in the UI layout above action controls are on the left hand side of a vertically scrolling list to make -them easily accessible using D-pad. -In general, for layouts with horizontally scrolling components, place action controls on left or right hand side and -vice versa for vertically scrolling components. -</p> - diff --git a/docs/html/training/tv/unsupported-features-tv.jd b/docs/html/training/tv/unsupported-features-tv.jd deleted file mode 100644 index a9f090b..0000000 --- a/docs/html/training/tv/unsupported-features-tv.jd +++ /dev/null @@ -1,157 +0,0 @@ -page.title=Handling Features Not Supported on TV -parent.title=Designing for TV -parent.link=index.html - -trainingnavtop=true -previous.title=Optimizing Navigation for TV -previous.link=optimizing-navigation-tv.html - -@jd:body - -<div id="tb-wrapper"> -<div id="tb"> - -<h2>This lesson teaches you to</h2> -<ol> - <li><a href="#WorkaroundUnsupportedFeatures">Work Around Features Not Supported on TV</a></li> - <li><a href="#CheckAvailableFeatures">Check for Available Features at Runtime</a></li> -</ol> - -</div> -</div> - -<p> -TVs are much different from other Android-powered devices: -</p> -<ul> - <li>They're not mobile.</li> - <li>Out of habit, people use them for watching media with little or no interaction.</li> - <li>People interact with them from a distance.</li> -</ul> - -<p> -Because TVs have a different purpose from other devices, they usually don't have hardware features -that other Android-powered devices often have. For this reason, the Android system does not -support the following features for a TV device: -<table> -<tr> -<th>Hardware</th> -<th>Android feature descriptor</th> -</tr> -<tr> -<td>Camera</td> -<td>android.hardware.camera</td> -</tr> -<tr> -<td>GPS</td> -<td>android.hardware.location.gps</td> -</tr> -<tr> -<td>Microphone</td> -<td>android.hardware.microphone</td> -</tr> -<tr> -<td>Near Field Communications (NFC)</td> -<td>android.hardware.nfc</td> -</tr> -<tr> -<td>Telephony</td> -<td>android.hardware.telephony</td> -</tr> -<tr> -<td>Touchscreen</td> -<td>android.hardware.touchscreen</td> -</tr> -</table> -</p> - -<p> -This lesson shows you how to work around features that are not available on TV by: -<ul> - <li>Providing work arounds for some non-supported features.</li> - <li>Checking for available features at runtime and conditionally activating/deactivating certain code - paths based on availability of those features.</li> -</ul> -</p> - - -<h2 id="WorkaroundUnsupportedFeatures">Work Around Features Not Supported on TV</h2> - -<p> -Android doesn't support touchscreen interaction for TV devices, most TVs don't have touch screens, -and interacting with a TV using a touchscreen is not consistent with the 10 foot environment. For -these reasons, users interact with Android-powered TVs using a remote. In consideration of this, -ensure that every control in your app can be accessed with the D-pad. Refer back to the previous two lessons -<a href="{@docRoot}training/tv/optimizing-layouts-tv.html">Optimizing Layouts for TV</a> and -<a href="{@docRoot}training/tv/optimizing-navigation-tv.html">Optimize Navigation for TV</a> for -more details -on this topic. The Android system assumes that a device has a touchscreen, so if you want your application -to run on a TV, you must <strong>explicitly</strong> disable the touchscreen requirement in your manifest file: -<pre> -<uses-feature android:name="android.hardware.touchscreen" android:required="false"/> -</pre> -</p> - -<p> -Although a TV doesn't have a camera, you can still provide a photography-related application on a TV. -For example, if you have an app that takes, views and edits photos, you can disable its picture-taking -functionality for TVs and still allow users to view and even edit photos. The next section talks about how to -deactivate or activate specific functions in the application based on runtime device type detection. -</p> - -<p> -Because TVs are stationary, indoor devices, they don't have built-in GPS. If your application uses location -information, allow users to search for a location or use a "static" location provider to get -a location from the zip code configured during the TV setup. -<pre> -LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); -Location location = locationManager.getLastKnownLocation("static"); -Geocoder geocoder = new Geocoder(this); -Address address = null; - -try { - address = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1).get(0); - Log.d("Zip code", address.getPostalCode()); - -} catch (IOException e) { - Log.e(TAG, "Geocoder error", e); -} -</pre> -</p> - -<p> -TVs usually don't support microphones, but if you have an application that uses voice control, -you can create a mobile device app that takes voice input and then acts as a remote control for a TV. -</p> - -<h2 id="CheckAvailableFeatures">Check for Available Features at Runtime</h2> - -<p> -To check if a feature is available at runtime, call -{@link android.content.pm.PackageManager#hasSystemFeature(String)}. - This method takes a single argument : a string corresponding to the -feature you want to check. For example, to check for touchscreen, use -{@link android.content.pm.PackageManager#hasSystemFeature(String)} with the argument -{@link android.content.pm.PackageManager#FEATURE_TOUCHSCREEN}. -</p> - -<p> -The following code snippet demonstrates how to detect device type at runtime based on supported features: - -<pre> -// Check if android.hardware.telephony feature is available. -if (getPackageManager().hasSystemFeature("android.hardware.telephony")) { - Log.d("Mobile Test", "Running on phone"); -// Check if android.hardware.touchscreen feature is available. -} else if (getPackageManager().hasSystemFeature("android.hardware.touchscreen")) { - Log.d("Tablet Test", "Running on devices that don't support telphony but have a touchscreen."); -} else { - Log.d("TV Test", "Running on a TV!"); -} -</pre> -</p> - -<p> -This is just one example of using runtime checks to deactivate app functionality that depends on features -that aren't available on TVs. -</p>
\ No newline at end of file diff --git a/docs/html/training/volley/index.jd b/docs/html/training/volley/index.jd new file mode 100644 index 0000000..ba5b09f --- /dev/null +++ b/docs/html/training/volley/index.jd @@ -0,0 +1,133 @@ +page.title=Transmitting Network Data Using Volley +page.tags="" + +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 (API Level 4) or higher</li> +</ul> + +<h2>You should also see</h2> +<ul> + <li>For a production quality app that uses Volley, see the 2013 Google I/O + <a href="https://github.com/google/iosched">schedule app</a>. In particular, see: + <ul> + <li><a + href="https://github.com/google/iosched/blob/master/android/src/main/java/com/google/android/apps/iosched/util/ImageLoader.java"> + ImageLoader</a></li> + <li><a + href="https://github.com/google/iosched/blob/master/android/src/main/java/com/google/android/apps/iosched/util/BitmapCache.java"> + BitmapCache</a></li> + </ul> + </li> +</ul> + +</div> +</div> + +<a class="notice-developers-video wide" href="https://developers.google.com/events/io/sessions/325304728"> +<div> + <h3>Video</h3> + <p>Volley: Easy, Fast Networking for Android</p> +</div> +</a> + + +<p>Volley is an HTTP library that makes networking for Android apps easier and most importantly, +faster. Volley is available through the open +<a href="https://android.googlesource.com/platform/frameworks/volley">AOSP</a> repository.</p> + +<p>Volley offers the following benefits:</p> + +<ul> + +<li>Automatic scheduling of network requests.</li> +<li>Multiple concurrent network connections.</li> +<li>Transparent disk and memory response caching with standard HTTP +<a href=http://en.wikipedia.org/wiki/Cache_coherence">cache coherence</a>.</li> +<li>Support for request prioritization.</li> +<li>Cancellation request API. You can cancel a single request, or you can set blocks or +scopes of requests to cancel.</li> +<li>Ease of customization, for example, for retry and backoff.</li> +<li>Strong ordering that makes it easy to correctly populate your UI with data fetched +asynchronously from the network.</li> +<li>Debugging and tracing tools.</li> + +</ul> + +<p>Volley excels at RPC-type operations used to populate a UI, such as fetching a page of +search results as structured data. It integrates easily with any protocol and comes out of +the box with support for raw strings, images, and JSON. By providing built-in support for +the features you need, Volley frees you from writing boilerplate code and allows you to +concentrate on the logic that is specific to your app.</p> +<p>Volley is not suitable for large download or streaming operations, since Volley holds +all responses in memory during parsing. For large download operations, consider using an +alternative like {@link android.app.DownloadManager}.</p> + +<p>The core Volley library is developed in the open +<a href="https://android.googlesource.com/platform/frameworks/volley">AOSP</a> +repository at {@code frameworks/volley} and contains the main request dispatch pipeline +as well as a set of commonly applicable utilities, available in the Volley "toolbox." The +easiest way to add Volley to your project is to clone the Volley repository and set it as +a library project:</p> + +<ol> +<li>Git clone the repository by typing the following at the command line: + +<pre> +git clone https://android.googlesource.com/platform/frameworks/volley +</pre> +</li> + +<li>Import the downloaded source into your app project as an Android library project +(as described in <a href="{@docRoot}tools/projects/projects-eclipse.html"> +Managing Projects from Eclipse with ADT</a>, if you're using Eclipse) or make a +<a href="{@docRoot}guide/faq/commontasks.html#addexternallibrary"><code>.jar</code> file</a>.</li> +</ol> + +<h2>Lessons</h2> + +<dl> + <dt> + <strong><a href="simple.html">Sending a Simple Request</a></strong> + </dt> + <dd> + Learn how to send a simple request using the default behaviors of Volley, and how + to cancel a request. + + </dd> + <dt> + <strong><a href="requestqueue.html">Setting Up a RequestQueue</a></strong> + </dt> + <dd> + Learn how to set up a {@code RequestQueue}, and how to implement a singleton + pattern to create a {@code RequestQueue} that lasts the lifetime of your app. + </dd> + <dt> + <strong><a href="request.html">Making a Standard Request</a></strong> + </dt> + <dd> + Learn how to send a request using one of Volley's out-of-the-box request types + (raw strings, images, and JSON). + </dd> + <dt> + <strong><a href="request-custom.html">Implementing a Custom Request</a></strong> + </dt> + <dd> + Learn how to implement a custom request. + </dd> + +</dl> diff --git a/docs/html/training/volley/request-custom.jd b/docs/html/training/volley/request-custom.jd new file mode 100644 index 0000000..7b669b9 --- /dev/null +++ b/docs/html/training/volley/request-custom.jd @@ -0,0 +1,163 @@ +page.title=Implementing a Custom Request + +trainingnavtop=true + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<!-- table of contents --> +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#custom-request">Write a Custom Request</a></li> +</ol> + +</div> +</div> + +<a class="notice-developers-video wide" href="https://developers.google.com/events/io/sessions/325304728"> +<div> + <h3>Video</h3> + <p>Volley: Easy, Fast Networking for Android</p> +</div> +</a> + +<p>This lesson describes how to implement your own custom request types, for types that +don't have out-of-the-box Volley support.</p> + +<h2 id="custom-request">Write a Custom Request</h2> + +Most requests have ready-to-use implementations in the toolbox; if your response is a string, +image, or JSON, you probably won't need to implement a custom {@code Request}.</p> + +<p>For cases where you do need to implement a custom request, this is all you need +to do:</p> + +<ul> + +<li>Extend the {@code Request<T>} class, where +{@code <T>} represents the type of parsed response +the request expects. So if your parsed response is a string, for example, +create your custom request by extending {@code Request<String>}. See the Volley +toolbox classes {@code StringRequest} and {@code ImageRequest} for examples of +extending {@code Request<T>}.</li> + +<li>Implement the abstract methods {@code parseNetworkResponse()} +and {@code deliverResponse()}, described in more detail below.</li> + +</ul> + +<h3>parseNetworkResponse</h3> + +<p>A {@code Response} encapsulates a parsed response for delivery, for a given type +(such as string, image, or JSON). Here is a sample implementation of +{@code parseNetworkResponse()}:</p> + +<pre> +@Override +protected Response<T> parseNetworkResponse( + NetworkResponse response) { + try { + String json = new String(response.data, + HttpHeaderParser.parseCharset(response.headers)); + return Response.success(gson.fromJson(json, clazz), + HttpHeaderParser.parseCacheHeaders(response)); + } + // handle errors +... +} +</pre> + +<p>Note the following:</p> + +<ul> +<li>{@code parseNetworkResponse()} takes as its parameter a {@code NetworkResponse}, which +contains the response payload as a byte[], HTTP status code, and response headers.</li> +<li>Your implementation must return a {@code Response<T>}, which contains your typed +response object and cache metadata or an error, such as in the case of a parse failure.</li> +</ul> + +<p>If your protocol has non-standard cache semantics, you can build a {@code Cache.Entry} +yourself, but most requests are fine with something like this: +</p> +<pre>return Response.success(myDecodedObject, + HttpHeaderParser.parseCacheHeaders(response));</pre> +<p> +Volley calls {@code parseNetworkResponse()} from a worker thread. This ensures that +expensive parsing operations, such as decoding a JPEG into a Bitmap, don't block the UI +thread.</p> + +<h3>deliverResponse</h3> + +<p>Volley calls you back on the main thread with the object you returned in +{@code parseNetworkResponse()}. Most requests invoke a callback interface here, +for example: +</p> + +<pre> +protected void deliverResponse(T response) { + listener.onResponse(response); +</pre> + +<h3>Example: GsonRequest</h3> + +<p><a href="http://code.google.com/p/google-gson/">Gson</a> is a library for converting +Java objects to and from JSON using reflection. You can define Java objects that have the +same names as their corresponding JSON keys, pass Gson the class object, and Gson will fill +in the fields for you. Here's a complete implementation of a Volley request that uses +Gson for parsing:</p> + +<pre> +public class GsonRequest<T> extends Request<T> { + private final Gson gson = new Gson(); + private final Class<T> clazz; + private final Map<String, String> headers; + private final Listener<T> listener; + + /** + * Make a GET request and return a parsed object from JSON. + * + * @param url URL of the request to make + * @param clazz Relevant class object, for Gson's reflection + * @param headers Map of request headers + */ + public GsonRequest(String url, Class<T> clazz, Map<String, String> headers, + Listener<T> listener, ErrorListener errorListener) { + super(Method.GET, url, errorListener); + this.clazz = clazz; + this.headers = headers; + this.listener = listener; + } + + @Override + public Map<String, String> getHeaders() throws AuthFailureError { + return headers != null ? headers : super.getHeaders(); + } + + @Override + protected void deliverResponse(T response) { + listener.onResponse(response); + } + + @Override + protected Response<T> parseNetworkResponse(NetworkResponse response) { + try { + String json = new String( + response.data, + HttpHeaderParser.parseCharset(response.headers)); + return Response.success( + gson.fromJson(json, clazz), + HttpHeaderParser.parseCacheHeaders(response)); + } catch (UnsupportedEncodingException e) { + return Response.error(new ParseError(e)); + } catch (JsonSyntaxException e) { + return Response.error(new ParseError(e)); + } + } +} +</pre> + +<p>Volley provides ready-to-use {@code JsonArrayRequest} and {@code JsonArrayObject} classes +if you prefer to take that approach. See <a href="request.html"> +Using Standard Request Types</a> for more information.</p> diff --git a/docs/html/training/volley/request.jd b/docs/html/training/volley/request.jd new file mode 100644 index 0000000..d8ccab2 --- /dev/null +++ b/docs/html/training/volley/request.jd @@ -0,0 +1,281 @@ +page.title=Making a Standard Request + +trainingnavtop=true + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<!-- table of contents --> +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#request-image">Request an Image</a></li> + <li><a href="#request-json">Request JSON</a></li> +</ol> + +</div> +</div> + +<a class="notice-developers-video wide" href="https://developers.google.com/events/io/sessions/325304728"> +<div> + <h3>Video</h3> + <p>Volley: Easy, Fast Networking for Android</p> +</div> +</a> + +<p> +This lesson describes how to use the common request types that Volley supports:</p> + +<ul> + <li>{@code StringRequest}. Specify a URL and receive a raw string in response. See + <a href="requestqueue.html">Setting Up a Request Queue</a> for an example.</li> + <li>{@code ImageRequest}. Specify a URL and receive an image in response.</li> + <li>{@code JsonObjectRequest} and {@code JsonArrayRequest} (both subclasses of + {@code JsonRequest}). Specify a URL and get a JSON object or array (respectively) in + response.</li> +</ul> + +<p>If your expected response is one of these types, you probably won't have to implement a +custom request. This lesson describes how to use these standard request types. For +information on how to implement your own custom request, see <a href="requests-custom.html"> +Implementing a Custom Request</a>.</p> + + +<h2 id="request-image">Request an Image</h2> + +<p>Volley offers the following classes for requesting images. These classes layer on top +of each other to offer different levels of support for processing images:</p> + +<ul> + <li>{@code ImageRequest}—a canned request for getting an image at a given URL and + calling back with a decoded bitmap. It also provides convenience features like specifying + a size to resize to. Its main benefit is that Volley's thread scheduling ensures that + expensive image operations (decoding, resizing) automatically happen on a worker thread.</li> + + <li>{@code ImageLoader}—a helper class that handles loading and caching images from + remote URLs. {@code ImageLoader} is a an orchestrator for large numbers of {@code ImageRequest}s, + for example when putting multiple thumbnails in a {@link android.widget.ListView}. + {@code ImageLoader} provides an in-memory cache to sit in front of the normal Volley + cache, which is important to prevent flickering. This makes it possible to achieve a + cache hit without blocking or deferring off the main thread, which is impossible when + using disk I/O. {@code ImageLoader} also does response coalescing, without which almost + every response handler would set a bitmap on a view and cause a layout pass per image. + Coalescing makes it possible to deliver multiple responses simultaneously, which improves + performance.</li> + <li>{@code NetworkImageView}—builds on {@code ImageLoader} and effectively replaces + {@link android.widget.ImageView} for situations where your image is being fetched over + the network via URL. {@code NetworkImageView} also manages canceling pending requests if + the view is detached from the hierarchy.</li> +</ul> + +<h3>Use ImageRequest</h3> + +<p>Here is an example of using {@code ImageRequest}. It retrieves the image specified by +the URL and displays it in the app. Note that this snippet interacts with the +{@code RequestQueue} through a singleton class (see <a href="{@docRoot} +training/volley/requestqueue.html#singleton">Setting Up a RequestQueue</a> for more discussion of +this topic):</p> + +<pre> +ImageView mImageView; +String url = "http://i.imgur.com/7spzG.png"; +mImageView = (ImageView) findViewById(R.id.myImage); +... + +// Retrieves an image specified by the URL, displays it in the UI. +ImageRequest request = new ImageRequest(url, + new Response.Listener<Bitmap>() { + @Override + public void onResponse(Bitmap bitmap) { + mImageView.setImageBitmap(bitmap); + } + }, 0, 0, null, + new Response.ErrorListener() { + public void onErrorResponse(VolleyError error) { + mImageView.setImageResource(R.drawable.image_load_error); + } + }); +// Access the RequestQueue through your singleton class. +MySingleton.getInstance(this).addToRequestQueue(request);</pre> + + +<h3>Use ImageLoader and NetworkImageView</h3> + +<p>You can use {@code ImageLoader} and {@code NetworkImageView} in concert to efficiently +manage the display of multiple images, such as in a {@link android.widget.ListView}. In your +layout XML file, you use {@code NetworkImageView} in much the same way you would use +{@link android.widget.ImageView}, for example:</p> + +<pre><com.android.volley.toolbox.NetworkImageView + android:id="@+id/networkImageView" + android:layout_width="150dp" + android:layout_height="170dp" + android:layout_centerHorizontal="true" /></pre> + +<p>You can use {@code ImageLoader} by itself to display an image, for example:</p> + +<pre> +ImageLoader mImageLoader; +ImageView mImageView; +// The URL for the image that is being loaded. +private static final String IMAGE_URL = + "http://developer.android.com/images/training/system-ui.png"; +... +mImageView = (ImageView) findViewById(R.id.regularImageView); + +// Get the ImageLoader through your singleton class. +mImageLoader = MySingleton.getInstance(this).getImageLoader(); +mImageLoader.get(IMAGE_URL, ImageLoader.getImageListener(mImageView, + R.drawable.def_image, R.drawable.err_image)); +</pre> + +<p>However, {@code NetworkImageView} can do this for you if all you're doing is populating +an {@link android.widget.ImageView}. For example:</p> + +<pre> +ImageLoader mImageLoader; +NetworkImageView mNetworkImageView; +private static final String IMAGE_URL = + "http://developer.android.com/images/training/system-ui.png"; +... + +// Get the NetworkImageView that will display the image. +mNetworkImageView = (NetworkImageView) findViewById(R.id.networkImageView); + +// Get the ImageLoader through your singleton class. +mImageLoader = MySingleton.getInstance(this).getImageLoader(); + +// Set the URL of the image that should be loaded into this view, and +// specify the ImageLoader that will be used to make the request. +mNetworkImageView.setImageUrl(IMAGE_URL, mImageLoader); +</pre> + +<p>The above snippets access the {@code RequestQueue} and the {@code ImageLoader} +through a singleton class, as described in <a href="{@docRoot}training/volley/requestqueue.html#singleton"> +Setting Up a RequestQueue</a>. This approach ensures that your app creates single instances of +these classes that last the lifetime of your app. The reason that this is important for +{@code ImageLoader} (the helper class that handles loading and caching images) is that +the main function of the in-memory cache is to allow for flickerless rotation. Using a +singleton pattern allows the bitmap cache to outlive the activity. If instead you create the +{@code ImageLoader} in an activity, the {@code ImageLoader} would be recreated along with +the activity every time the user rotates the device. This would cause flickering.</p> + +<h4 id="lru-cache">Example LRU cache</h4> + +<p>The Volley toolbox provides a standard cache implementation via the +{@code DiskBasedCache} class. This class caches files directly onto the hard disk in the +specified directory. But to use {@code ImageLoader}, you should provide a custom +in-memory LRU bitmap cache that implements the {@code ImageLoader.ImageCache} interface. +You may want to set up your cache as a singleton; for more discussion of this topic, see +<a href="{@docRoot}training/volley/requestqueue.html#singleton"> +Setting Up a RequestQueue</a>.</p> + +<p>Here is a sample implementation for an in-memory {@code LruBitmapCache} class. +It extends the {@link android.support.v4.util.LruCache} class and implements the +{@code ImageLoader.ImageCache} interface:</p> + +<pre> +import android.graphics.Bitmap; +import android.support.v4.util.LruCache; +import android.util.DisplayMetrics; +import com.android.volley.toolbox.ImageLoader.ImageCache; + +public class LruBitmapCache extends LruCache<String, Bitmap> + implements ImageCache { + + public LruBitmapCache(int maxSize) { + super(maxSize); + } + + public LruBitmapCache(Context ctx) { + this(getCacheSize(ctx)); + } + + @Override + protected int sizeOf(String key, Bitmap value) { + return value.getRowBytes() * value.getHeight(); + } + + @Override + public Bitmap getBitmap(String url) { + return get(url); + } + + @Override + public void putBitmap(String url, Bitmap bitmap) { + put(url, bitmap); + } + + // Returns a cache size equal to approximately three screens worth of images. + public static int getCacheSize(Context ctx) { + final DisplayMetrics displayMetrics = ctx.getResources(). + getDisplayMetrics(); + final int screenWidth = displayMetrics.widthPixels; + final int screenHeight = displayMetrics.heightPixels; + // 4 bytes per pixel + final int screenBytes = screenWidth * screenHeight * 4; + + return screenBytes * 3; + } +} +</pre> + +<p>Here is an example of how to instantiate an {@code ImageLoader} to use this +cache:</p> + +<pre> +RequestQueue mRequestQueue; // assume this exists. +ImageLoader mImageLoader = new ImageLoader(mRequestQueue, new LruBitmapCache( + LruBitmapCache.getCacheSize())); +</pre> + + +<h2 id="request-json">Request JSON</h2> + +<p>Volley provides the following classes for JSON requests:</p> + +<ul> + <li>{@code JsonArrayRequest}—A request for retrieving a + {@link org.json.JSONArray} + response body at a given URL.</li> + <li>{@code JsonObjectRequest}—A request for retrieving a + {@link org.json.JSONObject} + response body at a given URL, allowing for an optional + {@link org.json.JSONObject} + to be passed in as part of the request body.</li> +</ul> + +<p>Both classes are based on the common base class {@code JsonRequest}. You use them +following the same basic pattern you use for other types of requests. For example, this +snippet fetches a JSON feed and displays it as text in the UI:</p> + +<pre> +TextView mTxtDisplay; +ImageView mImageView; +mTxtDisplay = (TextView) findViewById(R.id.txtDisplay); +String url = "http://my-json-feed"; + +JsonObjectRequest jsObjRequest = new JsonObjectRequest + (Request.Method.GET, url, null, new Response.Listener<JSONObject>() { + + @Override + public void onResponse(JSONObject response) { + mTxtDisplay.setText("Response: " + response.toString()); + } +}, new Response.ErrorListener() { + + @Override + public void onErrorResponse(VolleyError error) { + // TODO Auto-generated method stub + + } +}); + +// Access the RequestQueue through your singleton class. +MySingleton.getInstance(this).addToRequestQueue(jsObjRequest); +</pre> + +For an example of implementing a custom JSON request based on +<a href="http://code.google.com/p/google-gson/">Gson</a>, see the next lesson, +<a href="request-custom.html">Implementing a Custom Request</a>. diff --git a/docs/html/training/volley/requestqueue.jd b/docs/html/training/volley/requestqueue.jd new file mode 100644 index 0000000..6858d91 --- /dev/null +++ b/docs/html/training/volley/requestqueue.jd @@ -0,0 +1,204 @@ +page.title=Setting Up a RequestQueue + +trainingnavtop=true + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<!-- table of contents --> +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#network">Set Up a Network and Cache</a></li> + <li><a href="#singleton">Use a Singleton Pattern</a></li> +</ol> + +</div> +</div> + +<a class="notice-developers-video wide" href="https://developers.google.com/events/io/sessions/325304728"> +<div> + <h3>Video</h3> + <p>Volley: Easy, Fast Networking for Android</p> +</div> +</a> + + +<p>The previous lesson showed you how to use the convenience method +<code>Volley.newRequestQueue</code> to set up a {@code RequestQueue}, taking advantage of +Volley's default behaviors. This lesson walks you through the explicit steps of creating a +{@code RequestQueue}, to allow you to supply your own custom behavior.</p> + +<p>This lesson also describes the recommended practice of creating a {@code RequestQueue} +as a singleton, which makes the {@code RequestQueue} last the lifetime of your app.</p> + +<h2 id="network">Set Up a Network and Cache</h2> + +<p>A {@code RequestQueue} needs two things to do its job: a network to perform transport +of the requests, and a cache to handle caching. There are standard implementations of these +available in the Volley toolbox: {@code DiskBasedCache} provides a one-file-per-response +cache with an in-memory index, and {@code BasicNetwork} provides a network transport based +on your choice of {@link android.net.http.AndroidHttpClient} or {@link java.net.HttpURLConnection}.</p> + +<p>{@code BasicNetwork} is Volley's default network implementation. A {@code BasicNetwork} +must be initialized with the HTTP client your app is using to connect to the network. +Typically this is {@link android.net.http.AndroidHttpClient} or +{@link java.net.HttpURLConnection}:</p> +<ul> +<li>Use {@link android.net.http.AndroidHttpClient} for apps targeting Android API levels +lower than API Level 9 (Gingerbread). Prior to Gingerbread, {@link java.net.HttpURLConnection} +was unreliable. For more discussion of this topic, see +<a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html"> +Android's HTTP Clients</a>. </li> + +<li>Use {@link java.net.HttpURLConnection} for apps targeting Android API Level 9 +(Gingerbread) and higher.</li> +</ul> +<p>To create an app that runs on all versions of Android, you can check the version of +Android the device is running and choose the appropriate HTTP client, for example:</p> + +<pre> +HttpStack stack; +... +// If the device is running a version >= Gingerbread... +if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { + // ...use HttpURLConnection for stack. +} else { + // ...use AndroidHttpClient for stack. +} +Network network = new BasicNetwork(stack); +</pre> + +<p>This snippet shows you the steps involved in setting up a +{@code RequestQueue}:</p> + +<pre> +RequestQueue mRequestQueue; + +// Instantiate the cache +Cache cache = new DiskBasedCache(getCacheDir(), 1024 * 1024); // 1MB cap + +// Set up the network to use HttpURLConnection as the HTTP client. +Network network = new BasicNetwork(new HurlStack()); + +// Instantiate the RequestQueue with the cache and network. +mRequestQueue = new RequestQueue(cache, network); + +// Start the queue +mRequestQueue.start(); + +String url ="http://www.myurl.com"; + +// Formulate the request and handle the response. +StringRequest stringRequest = new StringRequest(Request.Method.GET, url, + new Response.Listener<String>() { + @Override + public void onResponse(String response) { + // Do something with the response + } +}, + new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + // Handle error + } +}); + +// Add the request to the RequestQueue. +mRequestQueue.add(stringRequest); +... +</pre> + +<p>If you just need to make a one-time request and don't want to leave the thread pool +around, you can create the {@code RequestQueue} wherever you need it and call {@code stop()} on the +{@code RequestQueue} once your response or error has come back, using the +{@code Volley.newRequestQueue()} method described in <a href="simple.html">Sending a Simple +Request</a>. But the more common use case is to create the {@code RequestQueue} as a +singleton to keep it running for the lifetime of your app, as described in the next section.</p> + + +<h2 id="singleton">Use a Singleton Pattern</h2> + +<p>If your application makes constant use of the network, it's probably most efficient to +set up a single instance of {@code RequestQueue} that will last the lifetime of your app. +You can achieve this in various ways. The recommended approach is to implement a singleton +class that encapsulates {@code RequestQueue} and other Volley +functionality. Another approach is to subclass {@link android.app.Application} and set up the +{@code RequestQueue} in {@link android.app.Application#onCreate Application.onCreate()}. +But this approach is <a href="{@docRoot}reference/android/app/Application.html"> +discouraged</a>; a static singleton can provide the same functionality in a more modular +way. </p> + +<p>A key concept is that the {@code RequestQueue} must be instantiated with the +{@link android.app.Application} context, not an {@link android.app.Activity} context. This +ensures that the {@code RequestQueue} will last for the lifetime of your app, instead of +being recreated every time the activity is recreated (for example, when the user +rotates the device). + +<p>Here is an example of a singleton class that provides {@code RequestQueue} and +{@code ImageLoader} functionality:</p> + +<pre>private static MySingleton mInstance; + private RequestQueue mRequestQueue; + private ImageLoader mImageLoader; + private static Context mCtx; + + private MySingleton(Context context) { + mCtx = context; + mRequestQueue = getRequestQueue(); + + mImageLoader = new ImageLoader(mRequestQueue, + new ImageLoader.ImageCache() { + private final LruCache<String, Bitmap> + cache = new LruCache<String, Bitmap>(20); + + @Override + public Bitmap getBitmap(String url) { + return cache.get(url); + } + + @Override + public void putBitmap(String url, Bitmap bitmap) { + cache.put(url, bitmap); + } + }); + } + + public static synchronized MySingleton getInstance(Context context) { + if (mInstance == null) { + mInstance = new MySingleton(context); + } + return mInstance; + } + + public RequestQueue getRequestQueue() { + if (mRequestQueue == null) { + // getApplicationContext() is key, it keeps you from leaking the + // Activity or BroadcastReceiver if someone passes one in. + mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext()); + } + return mRequestQueue; + } + + public <T> void addToRequestQueue(Request<T> req) { + getRequestQueue().add(req); + } + + public ImageLoader getImageLoader() { + return mImageLoader; + } +}</pre> + +<p>Here are some examples of performing {@code RequestQueue} operations using the singleton +class:</p> + +<pre> +// Get a RequestQueue +RequestQueue queue = MySingleton.getInstance(this.getApplicationContext()). + getRequestQueue(); +... + +// Add a request (in this example, called stringRequest) to your RequestQueue. +MySingleton.getInstance(this).addToRequestQueue(stringRequest); +</pre> diff --git a/docs/html/training/volley/simple.jd b/docs/html/training/volley/simple.jd new file mode 100644 index 0000000..942c57f --- /dev/null +++ b/docs/html/training/volley/simple.jd @@ -0,0 +1,169 @@ +page.title=Sending a Simple Request + +trainingnavtop=true + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<!-- table of contents --> +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#manifest">Add the INTERNET Permission</a></li> + <li><a href="#simple">Use newRequestQueue</a></li> + <li><a href="#send">Send a Request</a></li> + <li><a href="#cancel">Cancel a Request</a></li> +</ol> + +</div> +</div> + +<a class="notice-developers-video wide" href="https://developers.google.com/events/io/sessions/325304728"> +<div> + <h3>Video</h3> + <p>Volley: Easy, Fast Networking for Android</p> +</div> +</a> + +<p>At a high level, you use Volley by creating a {@code RequestQueue} and passing it +{@code Request} objects. The {@code RequestQueue} manages worker threads for running the +network operations, reading from and writing to the cache, and parsing responses. Requests +do the parsing of raw responses and Volley takes care of dispatching the parsed response +back to the main thread for delivery.</p> + +<p> This lesson describes how to send a request using the <code>Volley.newRequestQueue</code> +convenience method, which sets up a {@code RequestQueue} for you. +See the next lesson, +<a href="requestqueue.html">Setting Up a RequestQueue</a>, for information on how to set +up a {@code RequestQueue} yourself.</p> + +<p>This lesson also describes how to add a request to a {@code RequestQueue} and cancel a +request.</p> + +<h2 id="manifest">Add the INTERNET Permission</h2> + +<p>To use Volley, you must add the +{@link android.Manifest.permission#INTERNET android.permission.INTERNET} permission +to your app's manifest. Without this, your app won't be able to connect to the network.</p> + + +<h2 id="simple">Use newRequestQueue</h2> + +<p>Volley provides a convenience method <code>Volley.newRequestQueue</code> that sets up a +{@code RequestQueue} for you, using default values, and starts the queue. For example:</p> + +<pre> +final TextView mTextView = (TextView) findViewById(R.id.text); +... + +// Instantiate the RequestQueue. +RequestQueue queue = Volley.newRequestQueue(this); +String url ="http://www.google.com"; + +// Request a string response from the provided URL. +StringRequest stringRequest = new StringRequest(Request.Method.GET, url, + new Response.Listener<String>() { + @Override + public void onResponse(String response) { + // Display the first 500 characters of the response string. + mTextView.setText("Response is: "+ response.substring(0,500)); + } +}, new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + mTextView.setText("That didn't work!"); + } +}); +// Add the request to the RequestQueue. +queue.add(stringRequest); +</pre> + +<p>Volley always delivers parsed responses on the main thread. Running on the main thread +is convenient for populating UI controls with received data, as you can freely modify UI +controls directly from your response handler, but it's especially critical to many of the +important semantics provided by the library, particularly related to canceling requests. +</p> + +<p>See <a href="requestqueue.html">Setting Up a RequestQueue</a> for a +description of how to set up a {@code RequestQueue} yourself, instead of using the +<code>Volley.newRequestQueue</code> convenience method.</p> + +<h2 id="send">Send a Request</h2> + +<p>To send a request, you simply construct one and add it to the {@code RequestQueue} with +{@code add()}, as shown above. Once you add the request it moves through the pipeline, +gets serviced, and has its raw response parsed and delivered.</p> + +<p>When you call {@code add()}, Volley runs one cache processing thread and a pool of +network dispatch threads. When you add a request to the queue, it is picked up by the cache +thread and triaged: if the request can be serviced from cache, the cached response is +parsed on the cache thread and the parsed response is delivered on the main thread. If the +request cannot be serviced from cache, it is placed on the network queue. The first +available network thread takes the request from the queue, performs the HTTP transaction, +parsse the response on the worker thread, writes the response to cache, and posts the parsed +response back to the main thread for delivery.</p> + +<p>Note that expensive operations like blocking I/O and parsing/decoding are done on worker +threads. You can add a request from any thread, but responses are always delivered on the +main thread.</p> + +<p>Figure 1 illustrates the life of a request:</p> + + <img src="{@docRoot}images/training/volley-request.png" + alt="system bars"> +<p class="img-caption"><strong>Figure 1.</strong> Life of a request.</p> + + +<h2 id="cancel">Cancel a Request</h2> + +<p>To cancel a request, call {@code cancel()} on your {@code Request} object. Once cancelled, +Volley guarantees that your response handler will never be called. What this means in +practice is that you can cancel all of your pending requests in your activity's +{@link android.app.Activity#onStop onStop()} method and you don't have to litter your +response handlers with checks for {@code getActivity() == null}, +whether {@code onSaveInstanceState()} has been called already, or other defensive +boilerplate.</p> + +<p>To take advantage of this behavior, you would typically have to +track all in-flight requests in order to be able to cancel them at the +appropriate time. There is an easier way: you can associate a tag object with each +request. You can then use this tag to provide a scope of requests to cancel. For +example, you can tag all of your requests with the {@link android.app.Activity} they +are being made on behalf of, and call {@code requestQueue.cancelAll(this)} from +{@link android.app.Activity#onStop onStop()}. +Similarly, you could tag all thumbnail image requests in a +{@link android.support.v4.view.ViewPager} tab with their respective tabs and cancel on swipe +to make sure that the new tab isn't being held up by requests from another one.</p> + +<p>Here is an example that uses a string value for the tag:</p> + +<ol> +<li>Define your tag and add it to your requests. +<pre> +public static final String TAG = "MyTag"; +StringRequest stringRequest; // Assume this exists. +RequestQueue mRequestQueue; // Assume this exists. + +// Set the tag on the request. +stringRequest.setTag(TAG); + +// Add the request to the RequestQueue. +mRequestQueue.add(stringRequest);</pre> +</li> + +<li>In your activity's {@link android.app.Activity#onStop onStop()} method, cancel all requests that have this tag. +<pre> +@Override +protected void onStop () { + super.onStop(); + if (mRequestQueue != null) { + mRequestQueue.cancelAll(TAG); + } +} +</pre></li></ol> + +<p>Take care when canceling requests. If you are depending on your response handler to +advance a state or kick off another process, you need to account for this. Again, the +response handler will not be called. +</p> |