diff options
Diffstat (limited to 'docs/html')
20 files changed, 1094 insertions, 128 deletions
diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd index c61a94b..32b9c9e 100644 --- a/docs/html/about/dashboards/index.jd +++ b/docs/html/about/dashboards/index.jd @@ -64,7 +64,7 @@ Platform Versions</a>.</p> </div> -<p style="clear:both"><em>Data collected during a 7-day period ending on May 1, 2014. +<p style="clear:both"><em>Data collected during a 7-day period ending on June 4, 2014. <br/>Any versions with less than 0.1% distribution are not shown.</em> </p> @@ -95,7 +95,7 @@ Screens</a>.</p> </div> -<p style="clear:both"><em>Data collected during a 7-day period ending on May 1, 2014. +<p style="clear:both"><em>Data collected during a 7-day period ending on June 4, 2014. <br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p> @@ -114,7 +114,7 @@ support for any lower version (for example, support for version 2.0 also implies <img alt="" style="float:right" -src="//chart.googleapis.com/chart?chs=400x250&cht=p&chd=t%3A0.1%2C87.0%2C12.9&chf=bg%2Cs%2C00000000&chl=GL%201.1%20only%7CGL%202.0%7CGL%203.0&chco=c4df9b%2C6fad0c" /> +src="//chart.googleapis.com/chart?chs=400x250&cht=p&chd=t%3A0.1%2C83.6%2C16.3&chf=bg%2Cs%2C00000000&chl=GL%201.1%20only%7CGL%202.0%7CGL%203.0&chco=c4df9b%2C6fad0c" /> <p>To declare which version of OpenGL ES your application requires, you should use the {@code android:glEsVersion} attribute of the <a @@ -136,17 +136,17 @@ uses.</p> </tr> <tr> <td>2.0</th> -<td>87.0%</td> +<td>83.6%</td> </tr> <tr> <td>3.0</th> -<td>12.9%</td> +<td>16.3%</td> </tr> </table> -<p style="clear:both"><em>Data collected during a 7-day period ending on May 1, 2014</em></p> +<p style="clear:both"><em>Data collected during a 7-day period ending on June 4, 2014</em></p> @@ -164,47 +164,42 @@ uses.</p> var VERSION_DATA = [ { - "chart": "//chart.googleapis.com/chart?chs=500x250&cht=p&chd=t%3A1.0%2C16.2%2C0.1%2C13.4%2C60.8%2C8.5&chf=bg%2Cs%2C00000000&chl=Froyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat&chco=c4df9b%2C6fad0c", + "chart": "//chart.googleapis.com/chart?chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat&chf=bg%2Cs%2C00000000&chd=t%3A0.8%2C14.9%2C12.3%2C58.4%2C13.6&chco=c4df9b%2C6fad0c&cht=p&chs=500x250", "data": [ { "api": 8, "name": "Froyo", - "perc": "1.0" + "perc": "0.8" }, { "api": 10, "name": "Gingerbread", - "perc": "16.2" - }, - { - "api": 13, - "name": "Honeycomb", - "perc": "0.1" + "perc": "14.9" }, { "api": 15, "name": "Ice Cream Sandwich", - "perc": "13.4" + "perc": "12.3" }, { "api": 16, "name": "Jelly Bean", - "perc": "33.5" + "perc": "29.0" }, { "api": 17, "name": "Jelly Bean", - "perc": "18.8" + "perc": "19.1" }, { "api": 18, "name": "Jelly Bean", - "perc": "8.5" + "perc": "10.3" }, { "api": 19, "name": "KitKat", - "perc": "8.5" + "perc": "13.6" } ] } @@ -226,23 +221,22 @@ var SCREEN_DATA = "xhdpi": "0.6" }, "Normal": { - "hdpi": "33.9", - "mdpi": "12.5", - "xhdpi": "19.9", - "xxhdpi": "13.5" + "hdpi": "34.2", + "mdpi": "12.0", + "xhdpi": "19.6", + "xxhdpi": "14.6" }, "Small": { - "ldpi": "7.5" + "ldpi": "7.2" }, "Xlarge": { "hdpi": "0.3", - "ldpi": "0.1", - "mdpi": "4.2", + "mdpi": "4.0", "xhdpi": "0.3" } }, - "densitychart": "//chart.googleapis.com/chart?chs=400x250&cht=p&chd=t%3A8.2%2C21.1%2C1.6%2C34.8%2C20.8%2C13.5&chf=bg%2Cs%2C00000000&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chco=c4df9b%2C6fad0c", - "layoutchart": "//chart.googleapis.com/chart?chs=400x250&cht=p&chd=t%3A4.9%2C7.8%2C80.0%2C7.5&chf=bg%2Cs%2C00000000&chl=Xlarge%7CLarge%7CNormal%7CSmall&chco=c4df9b%2C6fad0c" + "densitychart": "//chart.googleapis.com/chart?chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chf=bg%2Cs%2C00000000&chd=t%3A7.8%2C20.4%2C1.6%2C35.1%2C20.5%2C14.6&chco=c4df9b%2C6fad0c&cht=p&chs=400x250", + "layoutchart": "//chart.googleapis.com/chart?chl=Xlarge%7CLarge%7CNormal%7CSmall&chf=bg%2Cs%2C00000000&chd=t%3A4.6%2C7.8%2C80.4%2C7.2&chco=c4df9b%2C6fad0c&cht=p&chs=400x250" } ]; diff --git a/docs/html/distribute/engage/deep-linking.jd b/docs/html/distribute/engage/deep-linking.jd index 50728c5..0417ba1 100644 --- a/docs/html/distribute/engage/deep-linking.jd +++ b/docs/html/distribute/engage/deep-linking.jd @@ -68,8 +68,6 @@ page.image=/images/gp-listing-4.jpg <h2 id="related-resources"> Related Resources </h2> - - </div> <div class="resource-widget resource-flow-layout col-13" data-query= diff --git a/docs/html/distribute/essentials/quality/core.jd b/docs/html/distribute/essentials/quality/core.jd index c301f8c..cfe1a2a 100644 --- a/docs/html/distribute/essentials/quality/core.jd +++ b/docs/html/distribute/essentials/quality/core.jd @@ -234,9 +234,7 @@ page.image=/distribute/images/core-quality-guidelines.jpg </tr> </table> -<h3> - Related Resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/essentials/corequalityguidelines/visualdesign" @@ -509,9 +507,7 @@ data-maxresults="6"> </tr> </table> -<h3> - Related Resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/essentials/corequalityguidelines/functionality" @@ -670,9 +666,7 @@ data-sortorder="-timestamp" data-cardsizes="6x3" data-maxresults="6"> </tr> </table> -<h3> - Related Resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/essentials/core/performance" data-sortorder="-timestamp" @@ -819,9 +813,7 @@ data-cardsizes="6x3" data-maxresults="6"> </tr> </table> -<h3> - Related Resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/essentials/core/play" data-sortorder="-timestamp" diff --git a/docs/html/distribute/essentials/quality/tablets.jd b/docs/html/distribute/essentials/quality/tablets.jd index 966c462..2b2a5ae 100644 --- a/docs/html/distribute/essentials/quality/tablets.jd +++ b/docs/html/distribute/essentials/quality/tablets.jd @@ -158,7 +158,7 @@ across the screen:</p> multi-pane UI for tablets (see next section).</li> </ul> -<h3>Related resources</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query="collection:distribute/essentials/tabletguidelines/optimize" @@ -219,7 +219,7 @@ different layouts in the appropriate screen size buckets (such as <code>sw600dp</code>/<code>sw720</code>).</li> </ul> -<h3>Related resources</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query="collection:distribute/essentials/tabletguidelines/extrascreen" @@ -308,7 +308,7 @@ icon at the highest density possible. For example, if a tablet has an {@code xhd it will request the {@code xxhdpi} version of the launcher icon.</li> </ul> -<h3>Related resources</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query="collection:distribute/essentials/tabletguidelines/assets" @@ -345,7 +345,7 @@ larger touch targets. </li> or just centering the icon within the transparent button.</li> </ul> -<h3>Related resources</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query="collection:distribute/essentials/tabletguidelines/fonts" @@ -371,7 +371,7 @@ horizontal or square widget). </li> possible.</li> </ul> -<h3>Related resources</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query="collection:distribute/essentials/tabletguidelines/widgets" @@ -458,7 +458,7 @@ some recommendations:</p> </li> </ol> -<h3>Related resources</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query="collection:distribute/essentials/tabletguidelines/versions" @@ -528,7 +528,7 @@ permissions, make sure to explicitly declare a corresponding as needed. </p> -<h3>Related resources</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query="collection:distribute/essentials/tabletguidelines/hardware" @@ -560,7 +560,7 @@ app supports. Note that, if possible, you should avoid using the <a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html"><code><compatible-screens></code></a> element in your app.</p> -<h3>Related resources</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query="collection:distribute/essentials/tabletguidelines/tabletscreens" @@ -689,7 +689,7 @@ element in your app.</p> </li> </ul> -<h3>Related resources</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query="collection:distribute/essentials/tabletguidelines/showcase" @@ -799,7 +799,7 @@ appropriate.</p> recommended. </p> -<h3 class="clearfloat">Related resources</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query="collection:distribute/essentials/tabletguidelines/googleplay" data-sortOrder="-timestamp" diff --git a/docs/html/distribute/googleplay/edu/about.jd b/docs/html/distribute/googleplay/edu/about.jd index 1c003cf..e73356e 100644 --- a/docs/html/distribute/googleplay/edu/about.jd +++ b/docs/html/distribute/googleplay/edu/about.jd @@ -109,7 +109,7 @@ Xnonavpage=true <p style="clear:both"> </p> <div class="headerLine"> -<h2>Related Resources</h2> +<h2 id="related-resources">Related Resources</h2> </div> <div class="dynamic-grid"> diff --git a/docs/html/distribute/tools/launch-checklist.jd b/docs/html/distribute/tools/launch-checklist.jd index 3f6b1a6..f310800 100644 --- a/docs/html/distribute/tools/launch-checklist.jd +++ b/docs/html/distribute/tools/launch-checklist.jd @@ -85,9 +85,7 @@ src="{@docRoot}distribute/images/launch-checklist.jpg"></div> Play. </p> -<h3> - Related resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/toolsreference/launchchecklist/understanding" @@ -110,9 +108,7 @@ data-maxresults="6"> repeated violations, termination of your developer account. </p> -<h3> - Related resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/toolsreference/launchchecklist/policies" data-sortorder= @@ -154,9 +150,7 @@ data-maxresults="6"> should exhibit. </p> -<h3> - Related resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/toolsreference/launchchecklist/quality" data-sortorder= @@ -212,9 +206,7 @@ data-maxresults="6"> no changes are required in your app binary. </p> -<h3> - Related resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/toolsreference/launchchecklist/rating" data-sortorder= @@ -280,9 +272,7 @@ data-maxresults="6"> Checklist</a> for key steps and considerations in the localization process. </p> -<h3> - Related resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/toolsreference/launchchecklist/country" data-sortorder= @@ -335,9 +325,7 @@ data-maxresults="6"> on your code when building your release-ready APK. </p> -<h3> - Related resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/toolsreference/launchchecklist/size" data-sortorder= @@ -387,9 +375,7 @@ data-maxresults="6"> <a href="{@docRoot}about/dashboards/index.html">Device Dashboard</a> charts. </p> -<h3> - Related resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/toolsreference/launchchecklist/platform" data-sortorder= @@ -450,9 +436,7 @@ data-maxresults="6"> set up a Google Wallet Merchant Account</a> before you can publish. </p> -<h3> - Related resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/toolsreference/launchchecklist/price" data-sortorder= @@ -485,9 +469,7 @@ data-maxresults="6"> complete and test your implementation before creating your release-ready APK. </p> -<h3> - Related resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/toolsreference/launchchecklist/purchasemethod" @@ -517,9 +499,7 @@ data-maxresults="6"> available currencies through the Developer Console. </p> -<h3> - Related resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/toolsreference/launchchecklist/setprice" data-sortorder= @@ -599,9 +579,7 @@ data-maxresults="6"> listing. </p> -<h3> - Related resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/toolsreference/launchchecklist/localization" @@ -659,9 +637,7 @@ data-maxresults="6"> publishing date. </p> -<h3> - Related resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/toolsreference/launchchecklist/graphics" data-sortorder= @@ -701,7 +677,7 @@ data-maxresults="6"> Developer Console. If necessary, you can replace an APK with a more recent version before publishing. </p> -<!--<h3>Related resources</h3> +<!--<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query="collection:distribute/toolsreference/launchchecklist/build" @@ -815,9 +791,7 @@ See how you can facilitate testing with Google Play.</td> elsewhere. </p> -<h3> - Related resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/toolsreference/launchchecklist/productdetails" @@ -853,9 +827,7 @@ data-maxresults="6"> available. </p> -<h3> - Related resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/toolsreference/launchchecklist/badges" data-sortorder= @@ -959,9 +931,7 @@ data-maxresults="6"> linking from your promotional campaigns. </p> -<h3> - Related resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/toolsreference/launchchecklist/finalchecks" @@ -1063,7 +1033,7 @@ data-maxresults="6"> </ul> </ul> -<h3>Related resources</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query="collection:distribute/toolsreference/launchchecklist/afterlaunch" diff --git a/docs/html/distribute/tools/localization-checklist.jd b/docs/html/distribute/tools/localization-checklist.jd index 569ed02..08a8143 100644 --- a/docs/html/distribute/tools/localization-checklist.jd +++ b/docs/html/distribute/tools/localization-checklist.jd @@ -84,9 +84,7 @@ page.image=/distribute/images/localization-checklist.jpg development, translation, testing, and marketing efforts to these markets. </p> -<h3 id="related-resources"> - Related Resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/toolsreference/localizationchecklist/identifylocales" @@ -224,9 +222,7 @@ data-sortorder="-timestamp" data-cardsizes="9x3," data-maxresults="6"> directories, without language or locale qualifiers. </p> -<h3> - Related resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/tools/loc/designforloc" data-sortorder="-timestamp" @@ -399,9 +395,7 @@ data-cardsizes="9x3" data-maxresults="6"> </resources> </pre> -<h3 class="clearfloat"> - Related resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/toolsreference/localizationchecklist/managestrings" @@ -570,9 +564,7 @@ data-sortorder="-timestamp" data-cardsizes="9x3" data-maxresults="6"> <img src="{@docRoot}images/gp-localization-trans-0.png" class="border-img"> </div> -<h3> - Related resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/toolsreference/localizationchecklist/translatestrings" @@ -690,7 +682,7 @@ data-sortorder="-timestamp" data-cardsizes="9x3" data-maxresults="6"> your localized apps. One way to do that is through beta testing with regional users — Google Play can help you do this. <!-- </p> -<h3 class="clearfloat">Related resources</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query="collection:distribute/toolsreference/localizationchecklist/test" @@ -887,9 +879,7 @@ data-sortorder="-timestamp" data-cardsizes="9x3" data-maxresults="6"> helpful reminders for a successful localized launch. </p> -<h3> - Related resources -</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query= "collection:distribute/toolsreference/localizationchecklist/preplaunch" @@ -968,7 +958,7 @@ data-maxresults="6"> "{@docRoot}distribute/tools/launch-checklist.html">Launch Checklist</a> to learn more about how to plan, build, and launch your app on Google Play. </p> -<h3 class="clearfloat">Related resources</h3> +<h3 class="rel-resources clearfloat">Related resources</h3> <div class="resource-widget resource-flow-layout col-13" data-query="collection:distribute/toolsreference/localizationchecklist/supportlaunch" diff --git a/docs/html/distribute/tools/promote/badge-files.jd b/docs/html/distribute/tools/promote/badge-files.jd index b481802..e65e698 100644 --- a/docs/html/distribute/tools/promote/badge-files.jd +++ b/docs/html/distribute/tools/promote/badge-files.jd @@ -21,9 +21,10 @@ two Google Play badges.</p> <a href="{@docRoot}downloads/brand/v2/english_get.ai">English (English)</a><br/> + <a href="{@docRoot}downloads/brand/af_generic_rgb_wo.ai">Afrikaans (Afrikaans)</a><br/> + <a href="{@docRoot}downloads/brand/v2/amharic_get.ai">ኣማርኛ (Amharic)</a><br/> - <a href="{@docRoot}downloads/brand/af_generic_rgb_wo.ai">Afrikaans (Afrikaans)</a><br/> <!-- <a href="{@docRoot}downloads/brand/ar_generic_rgb_wo.ai">العربية (Arabic)</a><br/> --> @@ -286,6 +287,3 @@ Guidelines</a>. <p>To quickly create a badge that links to your apps on Google Play, use the <a href="{@docRoot}distribute/tools/promote/badges.html">Googe Play badge generator</a>.</p> - - -
\ No newline at end of file diff --git a/docs/html/guide/components/fundamentals.jd b/docs/html/guide/components/fundamentals.jd index 9ac063e..fd1a7a8 100644 --- a/docs/html/guide/components/fundamentals.jd +++ b/docs/html/guide/components/fundamentals.jd @@ -335,8 +335,8 @@ documentation. </p> {@link android.content.Intent} to start activities, services, and broadcast receivers. You can do so by explicitly naming the target component (using the component class name) in the intent. However, the real power of intents lies in the concept of <em>implicit intents</em>. An implicit intent -simply describe the type of action to perform (and optionally, the data upon which you’d like to -perform the action) and allow the system to find a component on the device that can perform the +simply describes the type of action to perform (and, optionally, the data upon which you’d like to +perform the action) and allows the system to find a component on the device that can perform the action and start it. If there are multiple components that can perform the action described by the intent, then the user selects which one to use.</p> diff --git a/docs/html/images/training/volley-request.png b/docs/html/images/training/volley-request.png Binary files differnew file mode 100644 index 0000000..85f0681 --- /dev/null +++ b/docs/html/images/training/volley-request.png diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd index 9b06a9d..f490053 100644 --- a/docs/html/tools/sdk/tools-notes.jd +++ b/docs/html/tools/sdk/tools-notes.jd @@ -28,6 +28,39 @@ href="http://tools.android.com/knownissues">http://tools.android.com/knownissues <div class="toggle-content opened"> <p><a href="#" onclick="return toggleContent(this)"> <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img" + alt=""/>SDK Tools, Revision 22.6.4</a> <em>(June 2014)</em> + </p> + + <div class="toggle-content-toggleme"> + + <dl> + <dt>Dependencies:</dt> + + <dd> + <ul> + <li>Android SDK Platform-tools revision 18 or later.</li> + <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is + designed for use with ADT 22.6.3 and later. If you haven't already, update your + <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 22.6.3.</li> + <li>If you are developing outside Eclipse, you must have + <a href="http://ant.apache.org/">Apache Ant</a> 1.8 or later.</li> + </ul> + </dd> + + <dt>General Notes:</dt> + <dd> + <ul> + <li>Fixed an issue with the x86 emulator that caused Google Maps to crash. + (<a href="http://b.android.com/69385">Issue 69385</a>)</li> + <li>Fixed minor OpenGL issues.</li> + </ul> + </dd> + </div> +</div> + +<div class="toggle-content closed"> + <p><a href="#" onclick="return toggleContent(this)"> + <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""/>SDK Tools, Revision 22.6.3</a> <em>(April 2014)</em> </p> 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 89ab539..1f6493f 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/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/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> |