tag:blogger.com,1999:blog-48379742116596920602024-03-05T18:11:29.310-08:00Android - The Technical Blog"Programming is usually taught by examples" (Niklaus Wirth)iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.comBlogger34125tag:blogger.com,1999:blog-4837974211659692060.post-85406113561521216342019-04-29T05:14:00.000-07:002019-04-29T05:14:41.129-07:00Economics Festival app - privacy policy<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 18pt; margin-top: 18pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 34pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">Privacy Policy</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">Claudio Agostini built the Economics Festival app as a Free app. This SERVICE is provided by Claudio Agostini at no cost and is intended for use as is.</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">This page is used to inform visitors regarding my policies with the collection, use, and disclosure of Personal Information if anyone decided to use my Service.</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">If you choose to use my Service, then you agree to the collection and use of information in relation to this policy. The Personal Information that I collect is used for providing and improving the Service. I will not use or share your information with anyone except as described in this Privacy Policy.</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">The terms used in this Privacy Policy have the same meanings as in our Terms and Conditions, which is accessible at Economics Festival unless otherwise defined in this Privacy Policy.</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">Information Collection and Use</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">For a better experience, while using our Service, I may require you to provide us with certain personally identifiable information, including but not limited to account id, event's favorite sessions. The information that I request will be retained on your device and is not collected by me in any way.</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">The app does use third party services that may collect information used to identify you.</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">Link to privacy policy of third party service providers used by the app</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: #616161; font-family: 'Noto Sans Symbols',sans-serif; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline; white-space: pre;"><div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 14pt; margin-top: 14pt;">
<a href="https://www.google.com/policies/privacy/" style="text-decoration: none;"><span style="-webkit-text-decoration-skip: none; background-color: transparent; color: #448aff; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">Google Play Services</span></a></div>
</li>
</ul>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">Log Data</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">I want to inform you that whenever you use my Service, in a case of an error in the app I collect data and information (through third party products) on your phone called Log Data. This Log Data may include information such as your device Internet Protocol (“IP”) address, device name, operating system version, the configuration of the app when utilizing my Service, the time and date of your use of the Service, and other statistics.</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">Cookies</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">Cookies are files with a small amount of data that are commonly used as anonymous unique identifiers. These are sent to your browser from the websites that you visit and are stored on your device's internal memory.</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">This Service does not use these “cookies” explicitly. However, the app may use third party code and libraries that use “cookies” to collect information and improve their services. You have the option to either accept or refuse these cookies and know when a cookie is being sent to your device. If you choose to refuse our cookies, you may not be able to use some portions of this Service.</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">Service Providers</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">I may employ third-party companies and individuals due to the following reasons:</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: #616161; font-family: 'Noto Sans Symbols',sans-serif; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline; white-space: pre;"><div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 0pt; margin-top: 14pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">To facilitate our Service;</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: #616161; font-family: 'Noto Sans Symbols',sans-serif; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline; white-space: pre;"><div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">To provide the Service on our behalf;</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: #616161; font-family: 'Noto Sans Symbols',sans-serif; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline; white-space: pre;"><div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">To perform Service-related services; or</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: #616161; font-family: 'Noto Sans Symbols',sans-serif; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline; white-space: pre;"><div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 14pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">To assist us in analyzing how our Service is used.</span></div>
</li>
</ul>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">I want to inform users of this Service that these third parties have access to your Personal Information. The reason is to perform the tasks assigned to them on our behalf. However, they are obligated not to disclose or use the information for any other purpose.</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">Security</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">I value your trust in providing us your Personal Information, thus we are striving to use commercially acceptable means of protecting it. But remember that no method of transmission over the internet, or method of electronic storage is 100% secure and reliable, and I cannot guarantee its absolute security.</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">Links to Other Sites</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">This Service may contain links to other sites. If you click on a third-party link, you will be directed to that site. Note that these external sites are not operated by me. Therefore, I strongly advise you to review the Privacy Policy of these websites. I have no control over and assume no responsibility for the content, privacy policies, or practices of any third-party sites or services.</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">Children’s Privacy</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">These Services do not address anyone under the age of 13. I do not knowingly collect personally identifiable information from children under 13. In the case I discover that a child under 13 has provided me with personal information, I immediately delete this from our servers. If you are a parent or guardian and you are aware that your child has provided us with personal information, please contact me so that I will be able to do necessary actions.</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">Changes to This Privacy Policy</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">I may update our Privacy Policy from time to time. Thus, you are advised to review this page periodically for any changes. I will notify you of any changes by posting the new Privacy Policy on this page. These changes are effective immediately after they are posted on this page.</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">Contact Us</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">If you have any questions or suggestions about my Privacy Policy, do not hesitate to contact me.</span></div>
<div dir="ltr" style="background-color: white; line-height: 1.295; margin-bottom: 12pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">This privacy policy page was created at </span><a href="https://privacypolicytemplate.net/" style="text-decoration: none;"><span style="-webkit-text-decoration-skip: none; background-color: transparent; color: #448aff; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">privacypolicytemplate.net</span></a><span style="background-color: transparent; color: #616161; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; white-space: pre;"> and modified/generated by </span><a href="https://app-privacy-policy-generator.firebaseapp.com/" style="text-decoration: none;"><span style="-webkit-text-decoration-skip: none; background-color: transparent; color: #448aff; font-family: Roboto,sans-serif; font-size: 10.5pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration-skip-ink: none; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; white-space: pre;">App Privacy Policy Generator</span></a></div>
<span id="docs-internal-guid-5c3851d5-7fff-a724-6ba3-c166b2c2596b"><br /></span>iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com6tag:blogger.com,1999:blog-4837974211659692060.post-6128253088745347622018-03-07T12:46:00.002-08:002018-03-07T12:46:11.724-08:00Animations with ConstraintLayout and the transition frameworkIn this post I'd like to share an interesting tutorial published on <b>AndroidPub </b>by <span style="font-size: large;"><b>Leonardo Pirro</b></span>:<br />
<a href="https://android.jlelse.eu/build-awesome-animations-with-7-lines-of-code-using-constraintlayout-854e8fd3ad93" target="_blank">Build awesome animations with 7 lines of code using ConstraintLayout</a><br />
<br />
You can find a sample app on GitHub here:<br />
<a href="https://github.com/LPirro/ConstraintLayoutAnimations" target="_blank">sample app in GitHub</a><br />
<br />
The tutorial is about animating layout changes using the android's <b>transition framework</b> with constraints in a <b>ConstraintLayout</b>.<br />
To begin with, let's see a preview of the animation:<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7zVSNcOFjIQCTqidp8shilJ_SpIVw4zOdMQAEr0IhGMk-s7F4fUgdlpx24aiARnxcdwsBEPlk4SOCNerahz0zM9ZLfM3fdX-wOP5kmkWfGqGIHl6nAkp-E6YGgVScFpaIoRynx8X3PSs/s1600/constraintlayout.gif" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="480" data-original-width="240" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7zVSNcOFjIQCTqidp8shilJ_SpIVw4zOdMQAEr0IhGMk-s7F4fUgdlpx24aiARnxcdwsBEPlk4SOCNerahz0zM9ZLfM3fdX-wOP5kmkWfGqGIHl6nAkp-E6YGgVScFpaIoRynx8X3PSs/s320/constraintlayout.gif" width="160" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">preview of the animation</td></tr>
</tbody></table>
<br />There are some things I would like to point out about this animation...<div>
<br /></div>
<h3>
Layout files</h3>
As you can see from the sample app, there are basically 2 layouts: the starting layout (at the beginning of the animation) and the ending layout (at the end of the animation).<br />The two layouts are almost identical (they have the same widgets), <b><u>but with different constraints</u></b>.<br />
For example in the first layout the title and subtitle have the right constraint set on the left of the ImageView, so they are just outside the screen and therefore not visible. This is their <b>starting position at the beginning of the animation</b>.<br />The same applies to the TextView containing the description. In the first layout it has its top constraint set to the bottom of the ImageView, so it's just outside the screen and therefore not visible.<br />In the second layout the same widgets are visible because they use different constraints: that's <b>the final position in the animation</b>.<br />
<div>
<br /></div>
<div>
<h3>
ConstraintSet</h3>
<span style="background-color: white;"><span style="font-family: inherit;">This class allows you to define programmatically a <b>set of constraints</b> to be used with ConstraintLayout. It lets you create and save constraints, and apply them to an existing ConstraintLayout.</span></span><br />
<span style="background-color: white;"><span style="font-family: inherit;">In the example, using the method clone() we can assign to the ConstraintSet the constraints <b>of the second layout</b>.</span></span><br />
<span style="background-color: white;"><span style="font-family: inherit;"><br /></span></span>
<h3>
<span style="background-color: white;"><span style="font-family: inherit;">Transition framework</span></span></h3>
<span style="background-color: white;"><span style="font-family: inherit;">The animation makes use of the <b>Android's transition framework</b>. To be more specific, it uses a transition without scenes using the method "<b><u>beginDelayedTransition</u></b>" as described here:</span></span><br />
<span style="background-color: white;"><span style="font-family: inherit;"><a href="https://developer.android.com/training/transitions/index.html#NoScenes" target="_blank">Apply a transition without scenes</a></span></span><br />
<span style="background-color: white;"><br /></span>
<span style="background-color: white;">The sample uses the ChangeBounds transition (move and resize views).</span><br />
<span style="background-color: white;"><br /></span>
<h3>
<span style="background-color: white;">Animation</span></h3>
<span style="background-color: white;">The animation works as follows:</span><br />
<br />
<ol>
<li>we retrieve the constraints from the second layout and store them in a ConstraintSet</li>
<li>we define a Transition (ChangeBounds) with an interpolator and execution time</li>
<li>we invoke the method "beginDelayedTransition" to mark the beginning of the animation</li>
<li>we make the changes that must be animated: these simply consist of applying the constraints of the second layout to the first layout</li>
</ol>
<div>
One thing to notice is that the two layouts are identical except for the constraints, which define the position of the widgets. <b><u>By animating the constraints we can animate the position of the widgets</u></b>.</div>
<div>
Another thing to notice is that the transition is always applied to<b> the first layout</b> (named "constraint"): the first time we apply the constraints of the second layout, the secont time we apply the constraints of the first layout, and so on...</div>
<br />
<span style="background-color: white;"><br /></span></div>
iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com9tag:blogger.com,1999:blog-4837974211659692060.post-15451326689994943532017-11-10T10:17:00.000-08:002017-11-10T10:17:15.497-08:00AsyncTasks done right<div class="MsoNormal">
<span lang="EN-GB">As an
Android developer you’ve probably already used <b>AsyncTasks</b> to perform
long-running tasks in a <b>separate thread</b> and deliver the results back to the
main Activity.<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-GB">AsyncTask
are particularly well suited for Activities, because they have <b>coordinated callback
methods</b> that run:</span><br />
<br />
<ul>
<li>in
a separate thread (doInBackground), to perform long-running operations;</li>
<li>in
the main thread (onPostExecute, onProgressUpdate, etc.) to display the results
in the UI.</li>
</ul>
</div>
<div class="MsoNormal">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_DJ4h0-bBo2CuJRgPImn9pex_HHuedqfFj8YuAiotDv9AzHyJzRnx0eaMGMxvS0-1V-3rZ4ENGhpphYyRxpHCVpqCKDOxKwUYmXADBSAFrhHvhMxSBblzzT1K9i68w3gdar-8x0gWV_A/s1600/AsyncTask01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="911" data-original-width="1224" height="297" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_DJ4h0-bBo2CuJRgPImn9pex_HHuedqfFj8YuAiotDv9AzHyJzRnx0eaMGMxvS0-1V-3rZ4ENGhpphYyRxpHCVpqCKDOxKwUYmXADBSAFrhHvhMxSBblzzT1K9i68w3gdar-8x0gWV_A/s400/AsyncTask01.png" width="400" /></a></div>
<span lang="EN-GB"><br /></span>
<span lang="EN-GB">To be more
precise, AsyncTasks are generally used for tasks <b>that don’t last too much</b> and
are related to the content of an Activity (for example, saving the data provided
by the user in a local database).</span><br />
<span lang="EN-GB"><br /></span>
<span lang="EN-GB">For long-running operations <b><u>it is always
better to use a Service</u></b>, because the lifecycle of a Service is not so much
affected by the lifecycle of the Activity (what happens if the user closes the
app while a background thread is ongoing?).<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-GB">Anyway,
you’ve probably used AsyncTasks in a way like this:</span></div>
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>public class MyActivity extends AppCompatActivity {
// ...
new MyAsincTask().execute(...);
private class MyAsincTask extends AsyncTask<integer integer=""> {
@Override
protected Integer doInBackground(Integer... integers) {
// long running task
}
@Override
protected void onPostExecute(Integer integer) {
// display results in MyActivity
}
}
}
</integer></code></pre>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<span lang="EN-GB">Within
Android Studio Lint gives you a warning, saying that <b>non-static inner and
anonymous classes could cause memory leaks.</b><o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-GB">What’s the
problem exactly? Well, in Java non-static inner and anonymous classes hold an
<b>implicit reference</b> to the outer class. In our example, the AsyncTask holds an
implicit reference to the containing Activity. If we launch an AsyncTask to do
some work in the background and, while the operation is ongoing, the user
closes the app, the AsyncTask keeps an implicit reference to the Activity: <b>this
reference can’t be garbage collected</b>, thus creating a memory leak.<o:p></o:p></span><br />
<span lang="EN-GB"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-GB">To solve
this problem <b>we have to convert our AsyncTask in a static class</b>. Static classes
in Java are <b>top-level classes</b> and they don’t hold any implicit reference to the
containing Activity.<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-GB">This technique,
however, raises another problem. When the AsyncTask has completed the
background task and the method onPostExecute is invoked, the results must be
delivered back to the Activity and displayed to the user: <b><u>our AsyncTask needs a
reference to the Activity</u></b> (maybe we need a Context to start another Activity,
or some widgets to display the results). If we use a regular (strong)
reference, memory leaks may occur. Moreover, what happes if the Activity no
longer exists because the user has closed the app?<o:p></o:p></span><br />
<span lang="EN-GB"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-GB"><b>The
solution is using <span style="font-size: large;">weak references</span></b>. JVM ignores weak references. That means
objects which have only week references are eligible for garbage collection.
They are likely to be garbage collected when JVM runs the garbage collector
thread. JVM doesn’t show any regard for weak references.<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-GB"><b>Using weak
references doesn’t prevent the garbage collector from deleting unnecessary
objects in memory</b>. In the method onPostExecute, by invoking get() on the weak
references, we check if the objects are still in memory or have already been
garbage collected. Only in the first case we can display the results to the
connected Activity.<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-GB">Have a look
at the following example (the parts of interest are highlighted):</span></div>
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>public static class GetScheduledRecordingsTask extends AsyncTask<void cheduledrecordingitem="" list="" void="">> {
@Inject
DBHelper dbHelper;
<b>private final WeakReference</b><scheduledrecordingsfragment><b> weakFragment;
private final WeakReference</b><compactcalendarview><b> weakCalendarView;
private final WeakReference</b><compactcalendarview .compactcalendarviewlistener=""><b> weakCompactCalendarViewListener;</b>
private final Date selectedDate;
public GetScheduledRecordingsTask(ScheduledRecordingsFragment scheduledRecordingsFragment, CompactCalendarView compactCalendarView, CompactCalendarView.CompactCalendarViewListener compactCalendarViewListener, Date selectedDate) {
App.getComponent().inject(this);
<b>weakFragment = new WeakReference<>(scheduledRecordingsFragment);
weakCalendarView = new WeakReference<>(compactCalendarView);
weakCompactCalendarViewListener = new WeakReference<>(compactCalendarViewListener);</b>
this.selectedDate = selectedDate;
}
protected List<scheduledrecordingitem> doInBackground(Void... params) {
return dbHelper.getAllScheduledRecordings();
}
protected void onPostExecute(List<scheduledrecordingitem> scheduledRecordings) {
<b>ScheduledRecordingsFragment scheduledRecordingsFragment = weakFragment.get();
CompactCalendarView calendarView = weakCalendarView.get();
CompactCalendarView.CompactCalendarViewListener compactCalendarViewListener = weakCompactCalendarViewListener.get();
if (scheduledRecordingsFragment == null || calendarView == null || compactCalendarViewListener == null)
return;</b>
calendarView.removeAllEvents();
for (ScheduledRecordingItem item : scheduledRecordings) {
Event event = new Event(ContextCompat.getColor(scheduledRecordingsFragment.getActivity(), R.color.accent), item.getStart(), item);
calendarView.addEvent(event, false);
}
calendarView.invalidate(); // refresh the calendar view
compactCalendarViewListener.onDayClick(selectedDate); // click to show current day
}
}
// ...
<b>new GetScheduledRecordingsTask(scheduledRecordingsFragment, calendarView, compactCalendarViewListener, selectedDate).execute();</b>
</scheduledrecordingitem></scheduledrecordingitem></compactcalendarview></compactcalendarview></scheduledrecordingsfragment></void></code></pre>
iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com3tag:blogger.com,1999:blog-4837974211659692060.post-43187266165643289032017-10-26T09:49:00.000-07:002017-10-26T09:52:30.481-07:00Testing Service lifecycle method calls<div style="text-align: left;">
Let's suppose you have created a local Service (implementing the <b>Local Binder Pattern</b>) to perform some tasks for your app, delivering the results back to a connected Activity. </div>
<div style="text-align: left;">
It is important to properly <b>test the Service </b>to make sure it behaves as you expect.
The first thing to do, as the Android documentation suggests, is <b>testing the Service's lifecycle methods</b>.<br />
<br />
To be more precise:</div>
<ul>
<li style="text-align: left;">e<span lang="DE" style="text-indent: -18pt;">nsure that the onCreate() is
called in response to Context.startService() or Context.bindService().
Similarly, you should ensure that onDestroy() is called in response to
Context.stopService(), Context.unbindService(), stopSelf(), or
stopSelfResult(). Test that your Service correctly handles multiple calls from
Context.startService(). Only the first call triggers Service.onCreate(), but
all calls trigger a call to Service.onStartCommand()</span></li>
</ul>
If you are not familiar with testing Services you can first check the official Android documentation here:<br />
<a href="https://developer.android.com/training/testing/integration-testing/service-testing.html" target="_blank">Testing Your Service</a><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpn_UAh32-r5zLL30jZr01kkAMKfDCgapcHNCMMTAUsswH2-HbCp5L3ozLnKVTq-7YxgiUYhEcNlS34q9e2gAxlg92WOL4Jr_YMvs0TnLYiqotj8YtacSRNgbCeuoV83EDMEpKA-jqGvc/s1600/android_app_testing.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="330" data-original-width="700" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpn_UAh32-r5zLL30jZr01kkAMKfDCgapcHNCMMTAUsswH2-HbCp5L3ozLnKVTq-7YxgiUYhEcNlS34q9e2gAxlg92WOL4Jr_YMvs0TnLYiqotj8YtacSRNgbCeuoV83EDMEpKA-jqGvc/s320/android_app_testing.png" width="320" /></a></div>
<br />
But how do you do that without mixing the code of your Service, implementing you <b>business logic</b>, with the code needed <b>to keep track of the method calls</b>?<br />
<br />
<h2>
@VisibleForTesting</h2>
The @VisibleForTesting annotation indicates that an annotated method (<b>or variable</b>) is more visible than normally necessary to make the method testable. This annotation has an <b>optional otherwise argument</b> that lets you designate what the visibility of the method should have been if not for the need to make it visible for testing. Lint uses the otherwise argument to enforce the intended visibility.<br />
<br />
You can also specify <b>@VisibleForTesting(otherwise = VisibleForTesting.NONE)</b> to indicate that a method exists only for testing. This form is the same as using <b>@RestrictTo(TESTS)</b>. They both perform the same lint check.<br />
<div>
For our purpose we can define some <b>static variables</b>, inside our Service, used to keep track of the lifecycle method calls. These variables are <b>annotated with @VisibleForTesting</b>, meaning that they are only used for testing purposes.<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>// Just for testing.
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
public static int onCreateCalls = 0;
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
public static int onDestroyCalls = 0;
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
public static int onStartCommandCalls = 0;</code></pre>
In the relevant Service lifecycle methods <b>we increment our counters</b>:</div>
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>@Override
public void onCreate() {
Log.d(TAG, "RecordingService - onCreate");
onCreateCalls++;
// ...
}
@Override
public void onDestroy() {
Log.d(TAG, "RecordingService - onDestroy");
onDestroyCalls++;
// ...
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStartCommandCalls++;
// ...
}</code></pre>
<br />
You can see the whole class on GitHub (it's a <b>hybrid Service</b>, both bound and started, used to record audio with a MediaRecorder):<br />
<a href="https://github.com/iClaude/SoundRecorder/blob/scheduled-recorder/app/src/main/java/com/danielkim/soundrecorder/RecordingService.java" target="_blank">RecordingService.java</a><br />
<br />
<h2>
Testing the Service</h2>
Testing our Service is now very easy. We first define the <b>ServiceTestRule</b> as follows:
<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>@Rule
public final ServiceTestRule mServiceRule = new ServiceTestRule() {
@Override
protected void afterService() {
super.afterService();
RecordingService.onCreateCalls = 0;
RecordingService.onStartCommandCalls = 0;
RecordingService.onDestroyCalls = 0;
}
};</code></pre>
Note that in the overriden <b>afterService</b> method, called when the Service is shut down <b>after each test</b>, we reset our counters to 0.<br />
<br />
Testing the lifecyle method calls is now very easy:<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>/*
Test that the Service's lifecycle methods are called the exact number of times in response
to binding, unbinding and calls to startService.
*/
@Test
public void testLifecyleMethodCalls() throws TimeoutException {
// Create the service Intent.
Intent serviceIntent = RecordingService.makeIntent(InstrumentationRegistry.getTargetContext(), true);
mServiceRule.startService(serviceIntent);
IBinder binder = mServiceRule.bindService(serviceIntent);
RecordingService service = ((RecordingService.LocalBinder) binder).getService();
mServiceRule.startService(serviceIntent);
mServiceRule.startService(serviceIntent);
assertNotNull("Service reference is null", service);
assertEquals("onCreate called multiple times", 1, RecordingService.onCreateCalls);
assertEquals("onStartCommand not called 3 times as expected", 3, RecordingService.onStartCommandCalls);
mServiceRule.unbindService();
assertEquals("onDestroy not called after unbinding from Service", 1, RecordingService.onDestroyCalls);
}
</code></pre>
<br />
You can have a look at the entire test class here:<br />
<a href="https://github.com/iClaude/SoundRecorder/blob/scheduled-recorder/app/src/androidTest/java/com/danielkim/soundrecorder/RecordingServiceTest.java" target="_blank">RecordingServiceTest.java</a><br />
<br />iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com2tag:blogger.com,1999:blog-4837974211659692060.post-37980084777529043482017-05-14T00:51:00.000-07:002017-05-14T00:51:29.088-07:00Scheduling repeated tasks offline at (almost) exact times<div style="margin-bottom: 0cm;">
<span lang="en-US">As you probably
know, starting from API level 21 (Lollipo) the best way to </span><span lang="en-US"><b>schedule
repeated tasks</b></span><span lang="en-US"> on Android is using:</span></div>
<ul>
<li><div style="margin-bottom: 0cm;">
<span lang="en-US">the
</span><span lang="en-US"><b>JobScheduler API</b></span><span lang="en-US">
(requires API level 21+);</span></div>
</li>
<li><div style="margin-bottom: 0cm;">
<span lang="en-US">the </span><span lang="en-US"><b>Firebase
JobDispatcher</b></span><span lang="en-US">, which provides a
JobScheduler-compatible API that works on all recent versions of
Android (API level 9+) that have Google Play services installed.</span></div>
</li>
</ul>
<div style="margin-bottom: 0cm;">
<span lang="en-US">Running apps in the
background is </span><span lang="en-US"><b>expensive</b></span><span lang="en-US">,
which is especially harmful when they're not actively doing work
that's important to the user.</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">In recognition of
these issues, the Android framework team created the </span><span lang="en-US"><b>JobScheduler</b></span><span lang="en-US">.
This provides developers a simple way of specifying runtime
constraints on their jobs. Available constraints include network
type, charging state, and idle state.</span></div>
<br />
<div style="margin-bottom: 0cm;">
<span lang="en-US">On the other hand,
the </span><span lang="en-US"><b>Firebase JobDispatcher</b></span><span lang="en-US">
uses the scheduling engine inside Google Play services(formerly the
GCM Network Manager component) to provide a backwards compatible
(back to Gingerbread) JobScheduler-like API.</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<h2>
Problem</h2>
<div class="western" style="margin-bottom: 0cm;">
<span lang="en-US">However,
both the JobScheduler API and the Firebase JobDispatcher, in order to
save battery life, depend on the </span><span lang="en-US"><b>mainance
windows of Doze</b></span><span lang="en-US">.</span></div>
<div class="western" style="margin-bottom: 0cm;">
<span lang="en-US">In
other words, i</span><span style="font-family: "roboto" , "times new roman";"><span lang="en-US"><span style="background: #ffffff;">f
a user leaves a device unplugged and stationary for a period of time,
with the screen off, the device enters Doze mode. In Doze mode, the
system attempts to conserve battery by restricting apps' access to
network and CPU-intensive services. It also prevents apps from
accessing the network </span></span></span><span style="font-family: "roboto" , "times new roman";"><span lang="en-US"><u><b><span style="background: #ffffff;">and
defers their jobs</span></b></u></span></span><span style="font-family: "roboto" , "times new roman";"><span lang="en-US"><span style="background: #ffffff;">,
syncs, and standard alarms.</span></span></span><span style="font-family: "roboto" , "times new roman";"><span lang="en-US">Periodically,
the system exits Doze for a brief time to let apps complete their
deferred activities. During this</span></span><em><span style="font-family: "roboto" , "times new roman";"><span lang="en-US">maintenance
window</span></span></em><span style="font-family: "roboto" , "times new roman";"><span lang="en-US">,
the system runs all pending syncs, jobs, and alarms, and lets apps
access the network.</span></span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">
</span></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVUxbYkD4dw8Cq-ck-BFkKYfEg_EFVqN4Xen_O5BSTEnWJP8CrFCjGjVAYsOqJIIJjGtPykqP_4iKkhBfc9MowWiuIAGMEI64rawb-_2QHhDYcM8KeqLNxeA9q_VFFjm2vdeunAiQKhAo/s1600/doze-header.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="255" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVUxbYkD4dw8Cq-ck-BFkKYfEg_EFVqN4Xen_O5BSTEnWJP8CrFCjGjVAYsOqJIIJjGtPykqP_4iKkhBfc9MowWiuIAGMEI64rawb-_2QHhDYcM8KeqLNxeA9q_VFFjm2vdeunAiQKhAo/s400/doze-header.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Doze - mantainance windows</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: center;">
</div>
<h3>
</h3>
<h3>
Warning</h3>
<div>
In this post we'll focus on scheduling repeated tasks (even offline, whithout an internet connection) that should start at (almost) exact times.</div>
<div>
<br /></div>
<h2>
AlarmManager</h2>
<div style="margin-bottom: 0cm;">
<span lang="en-US">Although the
aforementioned solution is preferable, because it enables to save
battery life, there might be scenarios in which you want to schedule
a repetead task to run with an exact timing, </span><span lang="en-US"><b>even
when the device is in Doze mode</b></span><span lang="en-US">.</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
A possible solution is
using the AlarmManager. The exact methods and the pattern to follow
varies depending on the Android version, because:</div>
<ul>
<li><div style="margin-bottom: 0cm;">
<span lang="en-US">Doze was first
introduced with Marshmallow (API level 23);</span></div>
</li>
<li><div style="margin-bottom: 0cm;">
<span lang="en-US">the
AlarmManager methods for scheduling tasks have slightly changed with
API leve 19.</span></div>
</li>
</ul>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div class="western" style="background: #ffffff; line-height: 0.64cm; margin-bottom: 0.32cm;">
</div>
<div lang="en-US" style="margin-bottom: 0cm;">
The following table shows
the methods to use:</div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<table border="1" bordercolor="#000000" cellpadding="4" cellspacing="0" style="width: 472px;">
<colgroup><col width="87"></col>
<col width="171"></col>
<col width="187"></col>
</colgroup><tbody>
<tr valign="TOP">
<td width="87"><br />
<br /></td>
<td width="171"><div class="western" lang="en-US" style="margin-bottom: 0cm;">
<b>repeated</b></div>
<div class="western" lang="en-US" style="margin-bottom: 0cm;">
<b>exact
times</b></div>
<div class="western" lang="en-US">
<b>display ON</b></div>
</td>
<td width="187"><div class="western" lang="en-US" style="margin-bottom: 0cm;">
<b>repeated</b></div>
<div class="western" lang="en-US" style="margin-bottom: 0cm;">
<b>exact
times</b></div>
<div class="western" lang="en-US">
<b>display OFF</b></div>
</td>
</tr>
<tr valign="TOP">
<td width="87"><div align="CENTER" class="western" lang="en-US">
<b>up to API 18</b></div>
</td>
<td width="171"><div class="western" lang="en-US" style="margin-bottom: 0cm;">
setRepeating</div>
<div class="western" style="margin-bottom: 0cm;">
RTC or
ELAPSED_REALTIME</div>
<div class="western" lang="en-US">
(1)</div>
</td>
<td width="187"><div class="western" style="margin-bottom: 0cm;">
setRepeating</div>
<div class="western" style="margin-bottom: 0cm;">
RTC_WAKEUP or </div>
<div class="western">
ELAPSED_REALTIME_WAKEUP</div>
</td>
</tr>
<tr valign="TOP">
<td width="87"><div align="CENTER" class="western" lang="en-US">
<b>API 19-22</b></div>
</td>
<td width="171"><div class="western" style="margin-bottom: 0cm;">
setExact with manual
re-scheduling</div>
<div class="western" style="margin-bottom: 0cm;">
RTC </div>
<div class="western" lang="en-US" style="margin-bottom: 0cm;">
ELAPSED_REALTIME</div>
<div class="western" lang="en-US">
(1) (2)</div>
</td>
<td width="187"><div class="western" lang="en-US" style="margin-bottom: 0cm;">
setExact
with manual re-scheduling</div>
<div class="western" style="margin-bottom: 0cm;">
RTC_WAKEUP </div>
<div class="western" lang="en-US">
ELAPSED_REALTIME_WAKEUP</div>
</td>
</tr>
<tr valign="TOP">
<td width="87"><div align="CENTER" class="western" lang="en-US">
<b>API 23+</b></div>
</td>
<td width="171"><div class="western" style="margin-bottom: 0cm;">
setExact or
<span lang="en-US">setExactAndAllowWhileIdle with manual
re-scheduling</span></div>
<div class="western" lang="en-US">
(3)</div>
</td>
<td width="187"><div class="western" lang="en-US" style="margin-bottom: 0cm;">
setExactAndAllowWhileIdle
with manual re-scheduling</div>
<div class="western" lang="en-US">
(3)</div>
</td>
</tr>
</tbody></table>
<div>
<br /></div>
<div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">(1) If an alarm is
delayed (by system sleep, for example, for non _WAKEUP alarm types),
a skipped repeat will be delivered as soon as possible. After that,
future alarms will be delivered according to the original schedule;
they do not drift over time. For example, if you have set a recurring
alarm for the top of every hour but the phone was asleep from 7:45
until 8:45, an alarm will be sent as soon as the phone awakens, then
the next alarm will be sent at 9:00.</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">(2) as of API 19,
all repeating alarms are inexact. If your application needs precise
delivery times then it must use one-time exact alarms, rescheduling
each time. Legacy applications whose targetSdkVersion is earlier than
API 19 will continue to have all of their alarms, including repeating
alarms, treated as exact. With setExact the alarm will be delivered
</span><span lang="en-US"><u>as nearly as possible</u></span><span lang="en-US">
to the requested trigger time.</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">(3) If you don't
need exact scheduling of the alarm but still need to execute while
idle, consider using setAndAllowWhileIdle(int, long, PendingIntent).</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<h3>
<span lang="en-US">Frequency</span></h3>
<div>
<span lang="en-US"><span style="background-color: white; color: rgba(0 , 0 , 0 , 0.87); font-family: "roboto" , "robotodraft" , "helvetica" , "arial" , sans-serif; font-size: 14px; white-space: pre-wrap;">For events less than 60 seconds apart, alarms aren’t the best choice: use the much more efficient Handler (</span><a class="ot-anchor aaTEdf" dir="ltr" href="http://goo.gl/CE9vAw" jslog="10929; track:click" rel="nofollow" style="-webkit-tap-highlight-color: transparent; background-color: white; color: #2962ff; font-family: Roboto, RobotoDraft, Helvetica, Arial, sans-serif; font-size: 14px; text-decoration-line: none; white-space: pre-wrap;" target="_blank">http://goo.gl/CE9vAw</a><span style="background-color: white; color: rgba(0 , 0 , 0 , 0.87); font-family: "roboto" , "robotodraft" , "helvetica" , "arial" , sans-serif; font-size: 14px; white-space: pre-wrap;">) for frequent work.</span></span></div>
<div>
<span lang="en-US"><span style="background-color: white; color: rgba(0 , 0 , 0 , 0.87); font-family: "roboto" , "robotodraft" , "helvetica" , "arial" , sans-serif; font-size: 14px; white-space: pre-wrap;"><br /></span></span></div>
<h2>
<span lang="en-US">setExactAndAllowWhileIdle:
exact or not?</span></h2>
<div style="margin-bottom: 0cm;">
<span lang="en-US">The method
setExactAndAllowWhileIdle, used to trigger alarms even when the
device is idle, can significantly impact the power use of the device
when idle (and thus cause significant battery blame to the app
scheduling them), so </span><span lang="en-US"><b>it should be used
with care</b></span><span lang="en-US">.</span><br />
<span lang="en-US"><br /></span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">To reduce abuse,
</span><span lang="en-US"><b>there are restrictions</b></span><span lang="en-US">
on how frequently these alarms will go off for a particular
application: </span>
</div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">
</span></div>
<ul>
<li><div style="margin-bottom: 0cm;">
<span lang="en-US">Under normal
system operation, it will not dispatch these alarms more than </span><span lang="en-US"><u><b>about
every minute</b></u></span><span lang="en-US"> (at which point every
such pending alarm is dispatched) </span>
</div>
</li>
<li><div style="margin-bottom: 0cm;">
<span lang="en-US">When in
low-power idle modes this duration may be significantly longer, </span><span lang="en-US"><u><b>such
as 15 minutes</b></u></span></div>
</li>
</ul>
<div>
<h3>
<span lang="en-US"><br /></span></h3>
<h2>
<span lang="en-US">Manual rescheduling</span></h2>
<div style="margin-bottom: 0cm;">
<span lang="en-US">As you can see from the above table, starting with
API 19 you have to use setExact or setExactAndAllowWhileIdle the
schedule a repeated task </span><span lang="en-US"><b>at exact times</b></span><span lang="en-US">.</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">Infact, as of API 19, all repeating alarms </span><span lang="en-US"><b>are
inexact</b></span><span lang="en-US">. </span><span lang="en-US"><b>If
your application needs precise delivery times then it must use
one-time exact alarms, rescheduling each time as described below</b></span><span lang="en-US">.
Legacy applications whose targetSdkVersion is earlier than API 19
will continue to have all of their alarms, including repeating
alarms, treated as exact. </span>
</div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">Create an <b>AlarmManager </b>instance:</span></div>
</div>
</div>
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
</code></pre>
<br />
Create an <b>Intent </b>to broadcast to a BroadcastReceiver:
<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>Intent intent = new Intent(MyActivity.this, MyReceiver.class);
</code></pre>
<br />
Create a <b>PendingIntent </b>that holds the intent:<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>PendingIntent pendingIntent = PendingIntent.getBroadcast(MyActivity.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
</code></pre>
<br />
Create the <b>alarm</b>:
<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>alarmManager.setExact(AlarmManager.RTC_WAKEUP, initialDelay, pendingIntent);
</code></pre>
<br />
Reschedule the next alarm in the onReceive method of your BroadcastReceiver using the same code described above.
<br />
<br />
<h2>
<span lang="en-US">WakefulBroadcastReceiver</span></h2>
<div style="margin-bottom: 0cm;">
<span lang="en-US">The Alarm Manager holds a </span><span lang="en-US"><b>CPU
wake lock</b></span><span lang="en-US"> as long as the alarm
receiver's onReceive() method is executing. This guarantees that the
phone will not sleep until you have finished handling the broadcast.
Once </span><span lang="en-US"><b>onReceive() returns</b></span><span lang="en-US">,
the Alarm Manager releases this wake lock. This means that the phone
will in some cases sleep as soon as your onReceive() method
completes. If your alarm receiver called </span><span lang="en-US"><b>Context.startService()</b></span><span lang="en-US">,
it is possible that the phone will sleep before the requested service
is launched. To prevent this, your BroadcastReceiver and Service will
need to implement a separate wake lock policy to ensure that the
phone continues running until the service becomes available.</span><br />
<span lang="en-US"><br /></span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">An easy way to achieve this is by using a
</span><span lang="en-US"><b>WakefulBroadcastReceiver</b></span><span lang="en-US">.
WakefulBroadcastReceiver is a BroadcastReceiver that receives a
device wakeup event and then passes the work off to a Service, </span><span lang="en-US"><b>while
ensuring that the device does not go back to sleep during the
transition.</b></span><span lang="en-US"> This class takes care of
creating and managing a partial wake lock for you; </span><span lang="en-US"><u><b>you
must request the WAKE_LOCK permission to use it</b></u></span><span lang="en-US">.</span><br />
<span lang="en-US"><br /></span></div>
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>public class MyWakefulBroadcastReceiver extends WakefulBroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// Reschedule the alarm. See the code above.
// Create an Intent to start a Service.
Intent service = new Intent(context, MyService.class);
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, service);
}
}
</code></pre>
<br />
The service (in this example, an IntentService) does some work. When it is finished, it releases the wake lock by calling completeWakefulIntent(intent). The intent it passes as a parameter is the same intent that the WakefulBroadcastReceiver originally passed in.
<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>
public class MyService extends IntentService {
public MyService() {
super("MyService");
}
@Override
protected void onHandleIntent(Intent intent) {
// Do some work here.
// At this point SimpleWakefulReceiver is still holding a wake lock
// for us.
// Note that when using this approach you should be aware that if your
// service gets killed and restarted while in the middle of such work
// (so the Intent gets re-delivered to perform the work again), it will
// at that point no longer be holding a wake lock since we are depending
// on SimpleWakefulReceiver to that for us. If this is a concern, you can
// acquire a separate wake lock here.
// Release the wake lock after executing the task.
SimpleWakefulReceiver.completeWakefulIntent(intent);
}
}
</code></pre>
iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com7tag:blogger.com,1999:blog-4837974211659692060.post-72020594438542005482017-05-06T11:43:00.000-07:002017-05-06T11:43:37.198-07:00Sticky Broadcast<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQu_M4xTg_4QvlHsblFD4RhGzRBS-_QXdGBZrKVxnMUGtSD0TQ45xTp9ez5DkMh-mmNjf6tyGSygPJxJfYWWerZ_RnHIp70xkOTIt4Y298JCsVLD81o_wDseiwdx6I0d_HNVU-GCcBsuQ/s1600/broadcast.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="193" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQu_M4xTg_4QvlHsblFD4RhGzRBS-_QXdGBZrKVxnMUGtSD0TQ45xTp9ez5DkMh-mmNjf6tyGSygPJxJfYWWerZ_RnHIp70xkOTIt4Y298JCsVLD81o_wDseiwdx6I0d_HNVU-GCcBsuQ/s320/broadcast.jpg" width="320" /></a></div>
<b><br /></b>
<b>Sticky Broadcast(s) </b>are a special kind of Broadcast(s) that <b>remain active for awhile</b> after being sent.
You can send a sticky Broadcast with the method:<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>Context.sendStickyBroadcast()
</code></pre>
<br />
If you register a BroadcastReceiver that listens to sticky Broadcast(s), it can receive two kind of Broadcast(s):
<br />
<ol>
<li>Broadcast(s) that <b>have just been sent</b></li>
<li>Broadcast(s) that <b>have been sent previously</b> and are still active</li>
</ol>
<div>
You can find out what kind of Broadcast you have just received with the method:</div>
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>isInitialStickyBroadcast()
</code></pre>
returning <b>false </b>if the Broadcast represents an event <b>that has just occured</b>.<br />
<br />
Sticky Broadcast(s) are generally used for events <b>lasting for a certain period of time</b>. Examples of such Broadcast(s) sent by the system are:<br />
<ul>
<li><b>Intent.ACTION_BATTERY_CHANGED</b>: indicates changes in the battery level. BroadcastReceiver(s) must be programmatically registered with Context.registerReceiver()</li>
<li><b>Intent.ACTION_DOCK_EVENT</b>: indicates when a device is placed on a dock</li>
<li><b>Intent.ACTION_DEVICE_STORAGE_LOW</b>: indicates low memory condition</li>
</ul>
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>public class MyBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals(Intent.ACTION_DOCK_EVENT)) {
if(!isInitialStickyBroadcast()) {
// this is a new broadcast
}
else {
// this is an old broadcast
}
}
}
}
</code></pre>
<br />
In order <b>to send</b> sticky Broadcast(s) you must include the <b>permission </b>android.permission.BROADCAST_STICKY in the Manifest file.<br />
<br />
If you want to <b>remove a sticky Broadcast</b> you can use the method:<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>Context.removeStickyBroadcast(Intent intent)
</code></pre>
passing the Intent that was previously broadcast.
<br />
<br />
<b><u>NB.</u></b> Sticky Broadcast(s) consume system resources, so use them sparingly <b>when really needed</b>!<br />
<br />
<h3>
API level 21</h3>
<div>
Starting from API level 21 sticky Broadcast(s) <b><u>are deprecated</u></b>.</div>
<div>
"<i>Sticky broadcasts should not be used. They provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. The recommended pattern is to use a non-sticky broadcast to report that something has changed, with another mechanism for apps to retrieve the current value whenever desired</i>".</div>
<div>
<br /></div>
iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com7tag:blogger.com,1999:blog-4837974211659692060.post-81789021091571242252016-09-26T10:01:00.000-07:002016-09-26T10:10:03.244-07:00Reverse engineering part 2: apktoolAfter getting the apk file (see article: <a href="http://androidtechnicalblog.blogspot.it/2016/09/reverse-engineering-part-1-getting-apk.html" target="_blank">Reverse engineering part 1: getting the apk file</a>) it's time to disassemble it and <b>analyze its content</b>.<br />
The tool I will talk about is called <b>apktool </b>and can be downloaded from <a href="https://ibotpeaches.github.io/Apktool/" target="_blank">https://ibotpeaches.github.io/Apktool/</a>, where you can also read the <b>complete documentation</b>. Apktool is especially useful to analyze <b>resource files</b> (xml layout files, Manifest, drawables, xml animation files, strings).<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEaSMZ71xzyh6mCKflcotBme5cq2s_JTHgD2Dl1q-VAizN3HlikjFUyjAICc085EzsJbv9sxEEToGCLtpr6ahyphenhyphen2WuqrcBsYzS99Bt3USNU0Stu9YgvzMmW7CqNEqzzohA-PxSDcm-mCCg/s1600/apktool48.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="229" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEaSMZ71xzyh6mCKflcotBme5cq2s_JTHgD2Dl1q-VAizN3HlikjFUyjAICc085EzsJbv9sxEEToGCLtpr6ahyphenhyphen2WuqrcBsYzS99Bt3USNU0Stu9YgvzMmW7CqNEqzzohA-PxSDcm-mCCg/s320/apktool48.png" width="320" /></a></div>
<br />
<h3>
Apktool</h3>
Apktool is a tool for reverse engineering 3rd party, closed, binary Android apps. It can decode resources to nearly original form and rebuild them after making some modifications. It also makes working with an app easier because of the project like file structure and automation of some repetitive tasks like building apk, etc.<br />
<br />
<h3>
Reverse engineering</h3>
After installing apktool you'll find the <b>apktool.bat</b> file that can be run from the command line.<br />
You just have to type:<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>apktool d filename.apk
</code></pre>
(replace filename.apk with the actual file name of the apk file)<br />
<br />
and apktool disassembles the apk file in a folder where you can find all the <b>resource files</b> perfectly readable.<br />
<br />
For example, I ran apktool for Whatsapp and this is the result:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjTFfeznruu525DZsWv1ZRggyQsfV5qc7XhY2RdV-4gMEVxAZlrw2CdXj43piZ-_EQjbTNBPcDJjaDH6WHvqQLOSqAG82-ElTOnIBhLhHxI1zxQJtktsuSxL1kBHtRhGEcKu7dKZDMcSI/s1600/Cattura.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="111" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjTFfeznruu525DZsWv1ZRggyQsfV5qc7XhY2RdV-4gMEVxAZlrw2CdXj43piZ-_EQjbTNBPcDJjaDH6WHvqQLOSqAG82-ElTOnIBhLhHxI1zxQJtktsuSxL1kBHtRhGEcKu7dKZDMcSI/s400/Cattura.PNG" width="400" /></a></div>
<br />
In the "res" folder you can have a look at <b>almost every resource file </b>of the app:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMBzubcYwjClcCyHVXYkPCrqLX3Ru4thwzUf8tcUeoy6Tb5E1BemLbr_zaYzloxJDmo18InK8sERqOknqiCrNvKf1NtIeuUlRnrt0PW0pPiBSFdh-ST5xUYL_16LXVtXPer7Mt7t95jHc/s1600/Cattura2.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMBzubcYwjClcCyHVXYkPCrqLX3Ru4thwzUf8tcUeoy6Tb5E1BemLbr_zaYzloxJDmo18InK8sERqOknqiCrNvKf1NtIeuUlRnrt0PW0pPiBSFdh-ST5xUYL_16LXVtXPer7Mt7t95jHc/s400/Cattura2.JPG" width="312" /></a></div>
<br />
<br />
This is the layout file settings_security.xml of Whatsapp. As you can see the file is <b>completely readable</b>.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw4PEVVr3VNjVg_Oma1xOOsqbTUizr3xNGKJfi1PSMYyGFO40GUBTktLQFHN2l2IAJzYVf-dgRw5J8V_61nCx2Y79GFWEx-4jWThuYEkpdxQSOJhspfq6i32CcTfrJm5N52P6Ktk-FNlI/s1600/Cattura3.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="190" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw4PEVVr3VNjVg_Oma1xOOsqbTUizr3xNGKJfi1PSMYyGFO40GUBTktLQFHN2l2IAJzYVf-dgRw5J8V_61nCx2Y79GFWEx-4jWThuYEkpdxQSOJhspfq6i32CcTfrJm5N52P6Ktk-FNlI/s400/Cattura3.JPG" width="400" /></a></div>
<br />
This is another example: the animation defined in design_fab_out.xml, that fades out a FloatingActionButton:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmtx9Uld3PpsY8D_JoWUbeZAyVz25JvrPGmleBALJxpEy-RSc0M0sPYv4NkAYpZwT-L6QBlri5bX5MocKgCrTj0eFYza78fPwUqkTrg2vYmApR1k4TebYs8dHneL_hhfme51VngBox9iQ/s1600/Cattura4.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="90" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmtx9Uld3PpsY8D_JoWUbeZAyVz25JvrPGmleBALJxpEy-RSc0M0sPYv4NkAYpZwT-L6QBlri5bX5MocKgCrTj0eFYza78fPwUqkTrg2vYmApR1k4TebYs8dHneL_hhfme51VngBox9iQ/s640/Cattura4.JPG" width="640" /></a></div>
Analyzing the file you can find out <b>how the animation is achieved</b>: animating alpha from 1 to 0 and the scale of the FAB from 1 to 0. Very easy!<br />
<br />
<h3>
Conclusion</h3>
Apktool is a very powerful utility especially if you want to analyze the <b>resource files</b> of an app. If you have found an app with a <b>beautiful design</b>, or a <b>fancy animation</b>, and want to find out how they are made, apktool is the tool to use.iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com7Berlino, Germania52.520006599999988 13.40495399999997552.210736099999991 12.759506999999974 52.829277099999985 14.050400999999976tag:blogger.com,1999:blog-4837974211659692060.post-12183633754264339512016-09-21T08:32:00.001-07:002016-09-21T08:32:03.257-07:00Reverse engineering part 1: getting the apk file<b>Reverse engineering</b>, also called back engineering, is the processes of <b>extracting knowledge or design information</b> from anything man-made and re-producing it or re-producing anything based on the extracted information. The process often involves disassembling something (a mechanical device, electronic component, computer program, or biological, chemical, or organic matter) and analyzing its components and workings in detail.<br />
<br />
As far as Android is concerned, suppose we have full-working Android app and we would like to find out how a particular layout is structured, how a specific animation is coded, how a visual effect is made. We can do that by reverse-engineering the apk file and extract useful information from it.<br />
<br />
There are <b>different tools</b> for doing that and in the following articles we'll have a look at some of the most widely used.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnEv7Z22ksM4brKB5JutuABqPlB25K4N59aVafM6wwp_weMsgIjcXpwysncNxbXXRY4HnCuDlgAFzYSCwfBl0m7le-IJi44ZkrnzlldE4tk8R_NsEZ6vAO9X0WVAw5pTK7_bJUZtbXwVs/s1600/reverse_engineering-icon.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnEv7Z22ksM4brKB5JutuABqPlB25K4N59aVafM6wwp_weMsgIjcXpwysncNxbXXRY4HnCuDlgAFzYSCwfBl0m7le-IJi44ZkrnzlldE4tk8R_NsEZ6vAO9X0WVAw5pTK7_bJUZtbXwVs/s320/reverse_engineering-icon.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Reverse engineering</td></tr>
</tbody></table>
<h3>
Getting the apk file</h3>
<div>
The first step to reverse-engineer an Android app is <b>getting the apk file</b>, in order to disassemble and analyze it using the different tools available.</div>
<div>
<br /></div>
<h4>
From the web</h4>
<div>
The easiest way to obtain the apk file of a particular app is using one the many <b>online resources</b> available.</div>
<div>
For example, using this website:</div>
<div>
<a href="http://apk-dl.com/" target="_blank">http://apk-dl.com/</a></div>
<div>
<br /></div>
<div>
you can paste the Google Play Store Url of the app you're interested in, and the service lets you download the apk file to your pc.</div>
<div>
If you download an apk file from the web, like the online service previously mentioned, be aware of the risk of possible <b>viruses or other malware</b>.</div>
<div>
<br /></div>
<h4>
From the smartphone</h4>
<div>
You can also very easily extract the apk file from an app <b>installed on your smartphone</b>.</div>
<div>
To do that we can use the <b><u>adb.exe</u></b> utility of the Android Sdk platform (you can find it in the folder: Android\sdk\platform-tools).</div>
<div>
<br /></div>
<div>
Just connect the device to your pc and type the following commands in command line...</div>
<div>
<br /></div>
<div>
<i><b>adb shell pm list packages </b></i></div>
<div>
to obtain a list of the apps (packages) installed and find the package you are interested in</div>
<div>
<br /></div>
<div>
<b><i>adb shell pm path your-package-name</i></b></div>
<div>
replace "your-package-name" with the name of the desired package</div>
<div>
to get the full package name and the name of the app</div>
<div>
<br /></div>
<div>
<b><i>adb pull full_path_of_the.apk</i></b></div>
<div>
replace "full_path_of_the.apk" with the full package name of the apk file obtained with the previous command</div>
<div>
to get the apk file in the folder where the command is executed</div>
<div>
<br /></div>
<div>
<br /></div>
iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com26tag:blogger.com,1999:blog-4837974211659692060.post-8098548558817720122016-09-19T12:07:00.000-07:002016-09-19T12:07:21.383-07:00How to blur an image using Renderscript<span style="background-color: white; color: rgba(0 , 0 , 0 , 0.682353); font-family: "roboto" , sans-serif; font-size: 16px;">RenderScript is a framework for running <b>computationally intensive tasks</b> at high performance on Android. RenderScript is primarily oriented for use with <b>data-parallel computation</b>, although serial workloads can benefit as well. The RenderScript runtime parallelizes work across processors available on a device, such as <b>multi-core CPUs and GPUs</b>.</span><br />
<span style="background-color: white; color: rgba(0 , 0 , 0 , 0.682353); font-family: "roboto" , sans-serif; font-size: 16px;">RenderScript is especially useful for applications performing <b>image processing</b>, computational photography, or computer vision.</span><br />
<span style="background-color: white; color: rgba(0 , 0 , 0 , 0.682353); font-family: "roboto" , sans-serif; font-size: 16px;">Let's see how you can use Renderscript <b><u>to effectively blur an image</u></b>.</span><br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTRAxQoe2uAiQYkildgvU4ww_rLIF3GybCUc-NoCEglsu7iSC1DIce6kIrLP3ZpamJmkYHxXycUrpycFRlMQeARV3OmadY_KXJKqpazQa177He2Fwy-7hSY4emjbSYEVg3Spg5fTKsKYY/s1600/blurred-traffic-jam-victor-bezrukov.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTRAxQoe2uAiQYkildgvU4ww_rLIF3GybCUc-NoCEglsu7iSC1DIce6kIrLP3ZpamJmkYHxXycUrpycFRlMQeARV3OmadY_KXJKqpazQa177He2Fwy-7hSY4emjbSYEVg3Spg5fTKsKYY/s320/blurred-traffic-jam-victor-bezrukov.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Blurred image</td></tr>
</tbody></table>
<br />
<h3>
<span style="background-color: white; color: rgba(0 , 0 , 0 , 0.682353); font-family: "roboto" , sans-serif; font-size: 16px;">Integrating Renderscript with Gradle</span></h3>
<span style="background-color: white; color: rgba(0 , 0 , 0 , 0.682353); font-family: "roboto" , sans-serif; font-size: 16px;">To add the Renderscript support library to your Android Studio project just add the following lines to <b>build.gradle</b> (module: app).</span><br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>android {
...
defaultConfig {
renderscriptTargetApi 19
renderscriptSupportModeEnabled true
}
...
}
</code></pre>
<br />
<br />
<h3>
Code to blur the image</h3>
Now create the <b>utility class</b> BlurBuilder that uses RenderScript to blur the image:<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>/*
* Copyright (c) - Software developed by iClaude.
*/
package com.flingsoftware.personalbudget.utilita;
import android.content.Context;
import android.graphics.Bitmap;
import android.support.v8.renderscript.Allocation;
import android.support.v8.renderscript.Element;
import android.support.v8.renderscript.RenderScript;
import android.support.v8.renderscript.ScriptIntrinsicBlur;
/**
* This class is used to blur a Bitmap.
* The static method blur takes a Bitmap as input e returns a blurred version of if.
*/
public class BlurBuilder {
private static final float BITMAP_SCALE = 0.4f;
private static final float BLUR_RADIUS = 7.5f;
public static Bitmap blur(Context context, Bitmap image) {
int width = Math.round(image.getWidth() * BITMAP_SCALE);
int height = Math.round(image.getHeight() * BITMAP_SCALE);
Bitmap inputBitmap = Bitmap.createScaledBitmap(image, width, height, false);
Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);
RenderScript rs = RenderScript.create(context);
ScriptIntrinsicBlur theIntrinsic = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
theIntrinsic.setRadius(BLUR_RADIUS);
theIntrinsic.setInput(tmpIn);
theIntrinsic.forEach(tmpOut);
tmpOut.copyTo(outputBitmap);
return outputBitmap;
}
}
</code></pre>
<br />
As you can see the class exposes a static method, "blur", that takes the original Bitmap as a parameter and returns the blurred version of the image.<br />
You can adjust the constants BITMAP_SCALE and BLUR_RADIUS to control the <b>amount of blurriness</b>.<br />
<br />
<h3>
Blurring the image</h3>
Now, if you have a Bitmap you can blur it using the following code (remeber to do this in a separate thread to avoid locking the UI):<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>Bitmap origBitmap = ...
Bitmap blurredBitmap = BlurBuilder.blur(mContext, origBitmap);
myImageView.setImageBitmap(blurredBitmap );
</code></pre>
<br />
<br />iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com3tag:blogger.com,1999:blog-4837974211659692060.post-39763656108016886092015-10-05T10:05:00.000-07:002015-10-05T10:05:09.491-07:00Managing AsyncTasks on configuration changes<h3>
The problem</h3>
<div style="margin-bottom: 0cm;">
<span lang="en-US">Suppose you have an
AsyncTask performing some task in the background (downloading data
from a web service, updating an online database, etc.). If the user
</span><span lang="en-US"><b>rotates the device</b></span><span lang="en-US">,
as you probably know, the current Activity is </span><span lang="en-US"><b>destroyed
and recreated</b></span><span lang="en-US"> (the callback methods
onDestroy and onCreate are invoked).</span><br />
<span lang="en-US"><br /></span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">As a result, when
the AsyncTask finishes its task and should deliver its results, the
original Activity </span><span lang="en-US"><b>may no longer exist</b></span><span lang="en-US">
or it could have been replaced by a brand new Activity. However the
AsyncTask is tied to the original Activity and its onPostExecute
method won’t work with the newly created Activity. The newly
created Activity may even start another AsyncTask (like in our
example, see below), thus wasting system resources.</span><br />
<span lang="en-US"><br /></span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">That’s why, as a
general rule, </span><span lang="en-US"><b>you should always perform
network operations in a Service</b></span><span lang="en-US">: the
Service’s lifecycle isn’t directly tied to the Activity
lifecycle; a Service is not destroyed and recreated on configuration
changes, like AsyncTasks do.</span></div>
<span lang="en-US">However AsyncTasks
are generally easier and quicker to program than Services, so let’s
examine some </span><span lang="en-US"><b>possibile solutions</b></span><span lang="en-US">
to our “configuration changes problem” using AsyncTasks.</span><br />
<div style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<h3>
Code</h3>
You can download the code
for this tutorial from the <a href="https://github.com/iClaude/RetainedFragment" target="_blank">Android – The Techinal Blog Githubrepository</a>.<br />
<br />
<h3>
The easy solution</h3>
<div style="margin-bottom: 0cm;">
<span lang="en-US">A very easy solution
to our problem is </span><span lang="en-US"><b>preventing the
Activity from being destroyed and recreated</b></span><span lang="en-US">
on configuration changes. For example, if you use the same layout for
portrait and landscape orientation there is no need to destroy and
recreate the Activity when the user rotates the device.</span><br />
<span lang="en-US"><br /></span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">To achieve this,
just insert the following line in the </span><span lang="en-US"><b>AndroidManifest.xml</b></span><span lang="en-US">
file under the Activity tag:</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
android:configChanges="orientation|screenSize|keyboardHidden”</div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">This way, when the
user rotates the device, the Activity is not destroyed and recreated
anymore; conversely the method </span><span lang="en-US"><b>onConfigurationChanged</b></span><span lang="en-US">
gets called and you can override it if you need it.</span><br />
<span lang="en-US"><br /></span></div>
<h3>
The correct solution</h3>
<div style="margin-bottom: 0cm;">
<span lang="en-US">The correct solution
to the “configuration change problem” is using a so called
“</span><span lang="en-US"><b>retained Fragment</b></span><span lang="en-US">”.</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">A Fragment
represents a behavior or a portion of the user interface within an
Activity. Fragment’s life cycle is generally </span><span lang="en-US"><b>coordinated
with the lifecycle of its containing Activity</b></span><span lang="en-US">:
when the Activity is destroyed on configuration changes all the
contained Fragments get destroyed too.</span><br />
<span lang="en-US"><br /></span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">However if you call
</span><span lang="en-US"><b>setRetainInstance(true)</b></span><span lang="en-US">
within the Fragment class the destroy-and-recreated cycle of the
Fragment is bypassed. As a result you can use a “retained Fragment”
to hold active objects, like the AsyncTasks, Sockets, etc.</span></div>
<div style="margin-bottom: 0cm;">
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.vogella.com/tutorials/AndroidFragments/images/xretainedfragmentlifecyle10.png.pagespeed.ic.7-q2ddz2ze.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://www.vogella.com/tutorials/AndroidFragments/images/xretainedfragmentlifecyle10.png.pagespeed.ic.7-q2ddz2ze.png" height="161" width="400" /></a></div>
<span lang="en-US"><br /></span>
<span lang="en-US"><br /></span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">
</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
Let’s start with the
retained Fragment:</div>
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>/**
* This Fragment performs a specific background task and is not
* destroyed on configuration changes.
*/
public class RetainedFragment extends Fragment {
/**
* Interface used by the retained Fragment to communicate with
* the Activity.
*/
interface RetainedFragmentCallbacks {
void onPreExecute();
void onProgressUpdate(int progress);
void onCancelled();
void onPostExecute();
}
private RetainedFragmentCallbacks retainedFragmentCallbacks;
private MyAsyncTask myAsyncTask;
/**
* Hold a reference to the parent Activity so we can report the
* task's current progress and results (the Activity must implement
* the RetainedFragmentCallbacks interface to receive the data sent
* by this Fragment).
* On configuration changes the Android framework passes to this
* method a reference to the newly created Activity. This way
* the AsyncTask can deliver its results to the new Activity.
*/
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
retainedFragmentCallbacks = (RetainedFragmentCallbacks) activity;
}
/**
* This method gets invoked when the Fragment is created for
* first time.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// This Fragment won’t be destroyed on configuration changes.
setRetainInstance(true);
// Create and execute the background task.
myAsyncTask = new MyAsyncTask();
myAsyncTask.execute();
}
/**
* Set the callback to null so we don't accidentally leak the
* Activity instance.
*/
@Override
public void onDetach() {
super.onDetach();
retainedFragmentCallbacks = null;
}
/**
* This AsyncTask performs a long task in the background
* (we fake it with a sleep) and communicates progress and
* results to the containing Activity.
* In each method we check that retainedFragmentCallbacks is
* not null because the Activity may have been destroyed on
* configuration changes or because the user exits the Activity
* pressing the back button.
*/
private class MyAsyncTask extends AsyncTask<void integer="" void=""> {
@Override
protected void onPreExecute() {
if (retainedFragmentCallbacks != null) {
retainedFragmentCallbacks.onPreExecute();
}
}
/**
* Note that we do NOT call the callback object's methods
* directly from the background thread, as this could result
* in a race condition.
*/
@Override
protected Void doInBackground(Void... ignore) {
for (int i = 0; !isCancelled() && i < 10; i++) {
SystemClock.sleep(1000);
publishProgress(i);
}
return null;
}
@Override
protected void onProgressUpdate(Integer... progress) {
if (retainedFragmentCallbacks != null) {
retainedFragmentCallbacks.onProgressUpdate(progress[0]);
}
}
@Override
protected void onCancelled() {
if (retainedFragmentCallbacks != null) {
retainedFragmentCallbacks.onCancelled();
}
}
@Override
protected void onPostExecute(Void ignore) {
if (retainedFragmentCallbacks != null) {
retainedFragmentCallbacks.onPostExecute();
}
}
}
}
</void></code></pre>
<br />
<div lang="en-US" style="margin-bottom: 0cm;">
And now the code of the
main Activity:</div>
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>/**
* This Activity creates a RetainedFragment to perform a background
* task, and receives progress updates and results from the
* Fragment when they occur.
*/
public class MainActivity extends AppCompatActivity implements RetainedFragment. RetainedFragmentCallbacks {
private static final String TAG_RETAINED_FRAGMENT = "RETAINED FRAGMENT";
private RetainedFragment retainedFragment;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);
FragmentManager fm = getFragmentManager();
retainedFragment = (RetainedFragment) fm.findFragmentByTag(TAG_RETAINED_FRAGMENT);
// If the Fragment is not null, then it is currently being
// retained across a configuration change.
if (retainedFragment == null) {
retainedFragment = new RetainedFragment();
fm.beginTransaction().add(retainedFragment, TAG_RETAINED_FRAGMENT).commit();
Log.d(TAG_RETAINED_FRAGMENT, "Retained Fragment created anew");
}
else {
Log.d(TAG_RETAINED_FRAGMENT, "Retained Fragment retained on configuration change");
}
}
// The four methods below are called by the RetainedFragment when new
// progress updates or results are available. The MainActivity
// should respond by updating its UI to indicate the change.
@Override
public void onPreExecute() {
Log.d(TAG_RETAINED_FRAGMENT, "onPreExecute() received...");
textView.setText("onPreExecute() received...");
}
@Override
public void onProgressUpdate(int progress) {
Log.d(TAG_RETAINED_FRAGMENT, "onProgressUpdate received with progress: " + progress);
textView.setText("onProgressUpdate received with progress: " + progress);
}
@Override
public void onCancelled() {
Log.d(TAG_RETAINED_FRAGMENT, "onCancelled() received...");
textView.setText("onCancelled() received...");
}
@Override
public void onPostExecute() {
Log.d(TAG_RETAINED_FRAGMENT, "onPostExecute() received...");
textView.setText("onPostExecute() received...");
}
}
</code></pre>
<br />
<div lang="en-US" style="margin-bottom: 0cm;">
The code is quite
self-explanatory.</div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">When the Activity is
created for the first time the method findFragmentByTag </span><span lang="en-US"><b>returns
null</b></span><span lang="en-US">, since no Fragment has already
been created. As a result a new instance of the RetainedFragment
class is created and attached to the main Activity. The main Activity
implements </span><span lang="en-US">Retained</span><span lang="en-US">Fragment.</span><span lang="en-US">RetainedFragmentCallbacks
interface and is </span><span lang="en-US"><b>registered to receive
updates</b></span><span lang="en-US"> from the Fragment in the method
onAttach.</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">When the Fragment is
created setRetainInstance(true) ensures that </span><span lang="en-US"><b>it
won’t be destroyed on configuration changes</b></span><span lang="en-US">.
In addition to that the Fragment creates and starts an AsyncTask,
defined and managed inside the Fragment class, to perform a long
lasting task in the background (for example downloading data from a
web service).</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">Progress updates and
final results are delivered to the main Activity through the
</span><span lang="en-US">Retained</span><span lang="en-US">Fragment.</span><span lang="en-US">RetainedFragmentCallbacks
interface, which is implemented in the Activity (see the logs).</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
Now let’s suppose that
the user rotates the device. This is what happens:</div>
<br />
<span lang="en-US"><ul>
<li><span lang="en-US">the
RetainedFragment </span><span lang="en-US"><b>is not destroyed</b></span><span lang="en-US">
(because we have called setRetainInstance(true) when the Fragment
was created) and the AsyncTask </span><span lang="en-US"><b>continues
to work</b></span><span lang="en-US"> in the background;</span></li>
<li><span lang="en-US">the main
Activity is </span><span lang="en-US"><b>destroyed and recreated</b></span><span lang="en-US">
as usual. When it’s destroyed it’s also detached from the
RetainedFragment and the retainedFragmentCallbacks variable inside
the Fragment class is set to null as a result. When the Activity is
recreated it’s re-attached to the existing Fragment and the
retainedFragmentCallbacks variable inside the Fragment is now set to
point to the newly created Activity: results and progress updates
are therefore delivered to this new Activity, and not to the old one
(which doesn’t exist anymore). Notice that the RetainedFragment
itself is not recreated because the method findFragmentByTag in
onCreate now returns the existing Fragment.</span></li>
</ul>
</span>iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com8tag:blogger.com,1999:blog-4837974211659692060.post-17796195286521920542014-06-23T08:46:00.000-07:002014-06-23T08:46:58.942-07:00Ordered Broadcasts<div style="margin-bottom: 0cm;">
<span lang="en-US">There are two types
of broadcasts in Android: </span><span lang="en-US"><b>normal and
ordered</b></span><span lang="en-US">. The following table shows the
main differences:</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<table border="1" bordercolor="#000000" cellpadding="7" cellspacing="0" style="width: 653px;">
<colgroup><col width="115"></col>
<col width="241"></col>
<col width="252"></col>
</colgroup><tbody>
<tr valign="TOP">
<td width="115"><div lang="en-US">
<div style="text-align: justify;">
<br /></div>
</div>
</td>
<td width="241"><div lang="en-US" style="text-align: center;">
<div style="text-align: center;">
<b>Normal</b></div>
</div>
</td>
<td width="252"><div lang="en-US" style="text-align: center;">
<div style="text-align: center;">
<b>Ordered</b></div>
</div>
</td>
</tr>
<tr valign="TOP">
<td width="115"><div lang="en-US">
<div style="text-align: justify;">
<b>Way of delivery</b></div>
</div>
</td>
<td width="241"><div style="text-align: justify;">
<span lang="en-US">Normal broadcasts are delivered to the
available receivers asynchronously, in an </span><span lang="en-US"><b>unspecified
order</b></span></div>
</td>
<td width="252"><div style="text-align: justify;">
<span lang="en-US">Ordered broadcasts are delivered to the
available receivers one at a time, in a </span><span lang="en-US"><b>specified
order</b></span><span lang="en-US"> (the order depends on the
android:priority attribute of the different receivers in the
AndroidManifest file)</span></div>
</td>
</tr>
<tr valign="TOP">
<td width="115"><div lang="en-US">
<div style="text-align: justify;">
<b>Feedback</b></div>
</div>
</td>
<td width="241"><div style="text-align: justify;">
<span lang="en-US">With normal broadcasts </span><span lang="en-US"><b>no
feedback</b></span><span lang="en-US"> can be sent to the
broadcaster</span></div>
</td>
<td width="252"><div style="text-align: justify;">
<span lang="en-US">With ordered broadcasts the receiver </span><span lang="en-US"><b>can
send information</b></span><span lang="en-US"> to the broadcaster
(using the methods abortBroadcast(), seResultCode(),
setResultData()</span></div>
</td>
</tr>
</tbody></table>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<br />
<div style="margin-bottom: 0cm;">
<span lang="en-US"><b>Tip:</b></span><span lang="en-US">
in a receiver (handling ordered broadcasts) you can call the method
abortBroadcast() to make sure that the broadcast is not sent to other
receivers. If you combine this method with a high value for the
android:priority attribute, you can make sure that your receiver is
the only one to handle that broadcast (SMS apps can use this
technique).</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgduah85segpzFn4_-E26OjuUc8YykEQ6Db-fXTDBrLY0qKyz8EYGNDDfX-hS8vkGRgo3FoFifOa7IefnDzy_XcltnLUp-qVuCR1JUGOwRKX8GnvsKq_V5849cWNeIHRVD0efZaMakAzFc/s1600/04-BroadcastReceiver.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgduah85segpzFn4_-E26OjuUc8YykEQ6Db-fXTDBrLY0qKyz8EYGNDDfX-hS8vkGRgo3FoFifOa7IefnDzy_XcltnLUp-qVuCR1JUGOwRKX8GnvsKq_V5849cWNeIHRVD0efZaMakAzFc/s1600/04-BroadcastReceiver.png" height="238" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">BroadcastReceiver in Android</td></tr>
</tbody></table>
<div style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<div style="margin-bottom: 0cm;">
<h2>
<span style="font-size: x-large;">BroadcastReceiver</span></h2>
</div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">Let’s see how a
BroadcastReceiver can </span><span lang="en-US"><b>handle ordered
broadcasts</b></span><span lang="en-US"> (se the comments in the code
for more information):</span></div>
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>public class MyReceiver extends BroadcastReceiver {
[...]
public void onReceive(Context context, Intent intent) {
//is this an ordered broadcast or not?
if(isOrderedBroadcast() {
//here you can handle the broadcast
[...]
//here you can send information back to the broadcaster
setResultCode(Activity.RESULT_OK);
setResultData(“here you can pass a String”);
//you can also create complex data to send to the broadcaster
Bundle myBundle = getResultExtras(true);
myBundle.put [...] //code omitted for brevity
}
}
}
</code></pre>
<h2>
<span lang="en-US" style="font-size: x-large;"><br /></span></h2>
<h2>
<span lang="en-US" style="font-size: x-large;">Broadcaster</span></h2>
<div style="margin-bottom: 0cm;">
<span lang="en-US"><b>Sending an
ordered broadcast</b></span><span lang="en-US"> is quite simple.
Let’s look at the code:</span></div>
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>Intent int = new Intent(YOUR_FILTER);
sendOrderedBroadcast(int, responseReceiver, null, RESULT_OK, null, null);
</code></pre>
<div lang="en-US" style="margin-bottom: 0cm;">
<span lang="en-US">As you can see you
just have to </span><span lang="en-US"><b>create an Intent</b></span><span lang="en-US">
with the filter registered for the BroadcastReceiver MyReceiver and
call the method sendOrderedBroadcast. This method takes a
BroadcastReceiver (</span><span lang="en-US"><b>responseReceiver</b></span><span lang="en-US">)
as a parameter: this is the receiver that will receive the
information sent back by the BroadcastReceiver MyReceiver.</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">So you finally have
to register the BroadcastReceiver responseReceiver (</span><span lang="en-US"><b>to
handle the results</b></span><span lang="en-US">) in the following
way:</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>BroadcastReceiver responseReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//here you can retrieve the results sent by MyReceiver
String str = getResultData();
//here you can retrieve the complex data sent by MyReceiver
Bundle myBundle = getResultExtras(false);
if(myBundle != null) {
//here you can retrieve the data using myBundle.get... methods
}
}
}
</code></pre>
</div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">
</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com2tag:blogger.com,1999:blog-4837974211659692060.post-2611874782327378532014-06-13T07:19:00.000-07:002014-06-13T07:19:03.034-07:00Creating a pie chart with aChart Engine<div lang="en-US" style="margin-bottom: 0cm;">
In many Android apps you
may need to show data in <b>graphical format</b> (pie charts, bar charts,
time charts, etc.). To do this you can write the code from scratch,
or use one of the many third-party libraries available. One of the
most used is certainly <b>aChart Engine</b>, and there are several good
reasons for that:</div>
<ol>
<li><div lang="en-US" style="margin-bottom: 0cm;">
it is leight;</div>
</li>
<li><div lang="en-US" style="margin-bottom: 0cm;">
it is free;</div>
</li>
<li><div lang="en-US" style="margin-bottom: 0cm;">
it is relatively
complete.</div>
</li>
</ol>
<br />
<div lang="en-US" style="margin-bottom: 0cm;">
In this brief tutorial I
will explain the most important features you must know to create a
<b>pie chart </b>using aChart Engine.</div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLZ5G_8ZAIyWX073tJHalKrwW4hq8171I8dsF-EVyOyE85IJNxtwlQO0QWREY6MqKNNG4xgbea9gaGHnD8rH4AnLnoF31a_dHGz4fwo3AwBDDMQcLcY4oKr-Mvk8FRPtJqhZAAhqnf6Ck/s1600/achartengine_piechart_android_distribution.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLZ5G_8ZAIyWX073tJHalKrwW4hq8171I8dsF-EVyOyE85IJNxtwlQO0QWREY6MqKNNG4xgbea9gaGHnD8rH4AnLnoF31a_dHGz4fwo3AwBDDMQcLcY4oKr-Mvk8FRPtJqhZAAhqnf6Ck/s1600/achartengine_piechart_android_distribution.png" height="320" width="194" /></a></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<h3>
Download and install the library</h3>
<div lang="en-US" style="margin-bottom: 0cm;">
First of all you have to
<b>download the library</b> (version 1.1.0) and <b>set up</b> your Eclipse project
to use it. The steps are the following:</div>
<ol>
<li><div style="margin-bottom: 0cm;">
<span lang="en-US">donwload the
library (jar file, version 1.1.0) from </span><span lang="en-US"><span style="background-attachment: initial; background-clip: initial; background-color: white; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial;"><a href="https://code.google.com/p/achartengine/downloads/list" target="_blank">this link</a></span></span><span lang="en-US">. You can find the complete
documentation of the package </span><span lang="en-US"><span style="background-attachment: initial; background-clip: initial; background-color: white; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial;"><a href="http://www.achartengine.org/content/javadoc/index.html" target="_blank">here</a></span></span><span lang="en-US">;</span></div>
</li>
<li><div style="margin-bottom: 0cm;">
<span style="background-color: white;">open Eclipse; right click on the main project folder; select "Build Path" and "Configure Build Path..."; select "Libraries" tab; click on "Add external Jars..." and select the library Jar file you have downloaded.</span></div>
</li>
</ol>
<div lang="en-US" style="margin-bottom: 0cm;">
</div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">Now your Eclipse
project is ready to use the library. Of course, if you want to use
the different classes, you first have <b>to import</b> them in your Activity
(import org.achartengine.model.CategorySeries ... etc.). </span>
</div>
<div style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<h3>
Source data</h3>
<div lang="en-US" style="margin-bottom: 0cm;">
Let’s suppose we want to
create a pie chart showing the <b>distribution of the different Android
versions</b>, using the following data:</div>
<div lang="en-US" style="margin-bottom: 0cm;">
Kit Kat – 7.8%</div>
<div lang="en-US" style="margin-bottom: 0cm;">
Jelly Bean – 33%</div>
<div lang="en-US" style="margin-bottom: 0cm;">
Ice Cream Sandwich – 25%</div>
<div lang="en-US" style="margin-bottom: 0cm;">
Honeycomb – 17%</div>
<div lang="en-US" style="margin-bottom: 0cm;">
Gingerbread – 11%</div>
<div lang="en-US" style="margin-bottom: 0cm;">
Older – 6.2%</div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
Each slice of the pie
chart is represented by a <b>different color</b>.</div>
<div lang="en-US" style="margin-bottom: 0cm;">
The source data in Java is
represented by <b>three arrays</b>, each with six elements:</div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;">String[] labels = new
String[] {“Kit Kat”, “Jelly Bean”, “Ice Cream Sandwich”,
“Honeycomb”, “Gingerbread”, “Older”};</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;">double[] values = {7.8,
33, 25, 17, 11, 6.2};</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;">int[] colors = {Color.RED,
Color.BLUE, Color.GREEN, Color.MAGENTA, Color.YELLOW, Color.GRAY};</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
<h3>
CategorySeries</h3>
<div style="margin-bottom: 0cm;">
<span lang="en-US">The class
<b>CategorySeries </b>of aChart Engine
(</span><span lang="en-US"><span style="background-attachment: initial; background-clip: initial; background-color: white; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial;"><a href="http://www.achartengine.org/content/javadoc/org/achartengine/model/CategorySeries.html" target="_blank">org.achartengine.model.CategorySeries</a></span></span><span lang="en-US">)
is used to represent a series for the category charts like the pie
ones.</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
We create an instance of
this class <b>and populate it</b> with the previously showed source data
(labels and values):</div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;">CategorySeries
categorySeries = new CategorySeries(“Android versions”);</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;">for(int i=0;
i<labels.length; i++) {</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> categorySeries.add(labels[i],
values[i]);</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
</div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;">}</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">
</span></div>
<h3>
DefaultRenderer</h3>
<div style="margin-bottom: 0cm;">
<span lang="en-US">The class
<b>DefaultRenderer </b>(</span><span lang="en-US"><span style="background-attachment: initial; background-clip: initial; background-color: white; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial;"><a href="http://www.achartengine.org/content/javadoc/org/achartengine/renderer/DefaultRenderer.html" target="_blank">org.achartengine.renderer.DefaultRenderer</a></span></span><span lang="en-US">)
is an abstract renderer used to <b>format the charts</b>.</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
We can create an instance
of this class and specify how we want our pie chart to be rendered:</div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="de-DE" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;">DefaultRenderer
defaultRenderer = new DefaultRenderer();</span></div>
<div lang="de-DE" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;">defaultRenderer.setChartTitle(“Android
versions”);</span></div>
<div lang="de-DE" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;">defaultRenderer.setChartTitleTextSize(30);</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><span lang="de-DE">defaultRenderer.setZoomButtonsVisible(</span><span style="color: red;"><span lang="de-DE"><b>false</b></span></span><span lang="de-DE">);</span></span></div>
<div lang="de-DE" style="margin-bottom: 0cm;">
...</div>
<div style="margin-bottom: 0cm;">
<span lang="en-US"><b><u>NB: It is important
to set the zoom buttons visibility to false, otherwise you may get a
NullPointerException in the onDraw() method of the class
GraphicalView (as far as I know, this should be a bug in the
library).</u></b></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
The are of course many
other formattings you can control using a DefaultRenderer: you can
read the <b>official documentation</b> for more information.</div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br />
</div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">To control the
<b>rendering of each slice</b> of the pie chart (color, showing or not
showing values, etc.) you can use the <b>SimpleSeriesRenderer</b> class
(</span><span lang="en-US"><span style="background-attachment: initial; background-clip: initial; background-color: white; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial;"><a href="http://www.achartengine.org/content/javadoc/org/achartengine/renderer/SimpleSeriesRenderer.html" target="_blank">org.achartengine.renderer.SimpleSeriesRenderer</a></span></span><span lang="en-US">):
you just have to create an instance of this class for each slice, set
the relevant data and add it to the previously defined
DefaultRenderer:</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;">for(int i=0;
i<labels.length; i++) {</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> SimpleSeriesRenderer
simpleSeriesRenderer = new SimpleSeriesRenderer();</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> simpleSeriesRenderer.setColor(colors[i]);</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> simpleSeriesRenderer.setDisplayChartValues(true);</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> ...</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> defaultRenderer.addSeriesRenderer(simpleSeriesRenderer);</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
</div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;">}</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
<h3>
Starting a new Activity</h3>
<div style="margin-bottom: 0cm;">
<span lang="en-US">To show our pie
chart we first have to <b>retrieve an Intent</b>, populated with the
relevant data, using the <b>ChartFactory</b> class:</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;">Intent intPiechart =
ChartFactory.getPieChartIntent(context, categorySeries,
defaultRenderer, “Android versions”);</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;">startActivity(intPieChart);</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br />
</div>
<div lang="en-US" style="margin-bottom: 0cm;">
The new Activity <b>must be
declared</b> in the AndroidManifest.xml file as well:</div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
</div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><activity
android:name=”org.achartengine.GraphicalActivity”/></span></div>
iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com3tag:blogger.com,1999:blog-4837974211659692060.post-75435988782013040162014-05-05T10:20:00.001-07:002014-05-05T10:20:32.166-07:00Spinner with "re-select" functionalityThis is an advanced tutorial: I'll cover <b>custom views</b>, the <b>Android source code</b> and <b>Java reflection</b>.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpRUahnV0472iQhG5aoouQfDNZp3HssczRFgNKdpgUb4-oOzNSBe-rZvZJqMQbBbw_7-6qAZoECJZowIsmubHL1hgqtD5yVGmg2gcv12AGw2nOP52bloM7iVuynSxN4Bfdtf6RGpco5mw/s1600/Y57Wc.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpRUahnV0472iQhG5aoouQfDNZp3HssczRFgNKdpgUb4-oOzNSBe-rZvZJqMQbBbw_7-6qAZoECJZowIsmubHL1hgqtD5yVGmg2gcv12AGw2nOP52bloM7iVuynSxN4Bfdtf6RGpco5mw/s1600/Y57Wc.png" height="320" width="240" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">A simple Spinner</td></tr>
</tbody></table>
<br />
As you probably already know, when the user selects an item from a Spinner the event <b>onItemSelected </b>is triggered.<br />
To define the selection event handler for a Spinner, you have to implement the <b>AdapterView.OnItemSelectedListener</b> interface and the corresponding <b>onItemSelected()</b> callback method:<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>public class SpinnerActivity extends Activity implements OnItemSelectedListener {
//...
public void onItemSelected(AdapterView<?> parent, View view,
int pos, long id) {
// An item was selected. You can retrieve the selected item using
// parent.getItemAtPosition(pos)
}
public void onNothingSelected(AdapterView<?> parent) {
// Another interface callback
}
}
</code></pre>
<br />
<span style="color: #222222; font-family: inherit; line-height: 150%; orphans: 2; widows: 2;">However, if the Spinner is set to a specific item and <b>the user re-selects the same item</b>, no callback method is invoked. The reason is that the default implementation of the Spinner class <b>uses an internal variable</b> to keep track of the currently selected item: if the user re-selects the same item, no callback method is triggered.</span><br />
<div style="margin-bottom: 0.4cm; orphans: 2; widows: 2;">
<div style="line-height: 150%;">
<span style="color: #222222; font-family: inherit;"><span lang="en-US">To be more precise, to understand exactly what happens we have to look at the <b>source code </b>of the Spinner class, using AndroidXRef:</span></span><br />
<span style="color: #222222; font-family: inherit;"><span lang="en-US"><br /></span></span></div>
<div class="separator" style="clear: both; line-height: 150%; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgux8HCuZWViK26CBHNcw46D_niIiB_N82l48HP60Bg_biWIp-qa1p454drFFEm2dorxGmrfFXxZ6eZ0xWUQHPB1v3jYLWDJtXVqO7o56tLcJbfrK-27p32Ho7tVSqi1WiF1PegwscXs_s/s1600/xref.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgux8HCuZWViK26CBHNcw46D_niIiB_N82l48HP60Bg_biWIp-qa1p454drFFEm2dorxGmrfFXxZ6eZ0xWUQHPB1v3jYLWDJtXVqO7o56tLcJbfrK-27p32Ho7tVSqi1WiF1PegwscXs_s/s1600/xref.jpg" height="156" width="400" /></a></div>
<div style="line-height: 150%;">
<span style="color: #222222;">By examining the source code you can discover that when the user selects an item the method <b>setSelection </b>is invoked (check the methods <b>onClick and show</b>) . The method setSelection is defined in the <b>superclass AbsSpinner</b> (Spinner infact extends AbsSpinner).</span><br />
<span style="color: #222222;"><br /></span></div>
<div class="separator" style="clear: both; line-height: 150%; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYSa8LniW_Gq8DQCKczR-RiRZsFaLaZqvs8E6pPxMdnTYR_gh-geYpEqt8TVwYU0U5P2JdZ3pVcUqcM-M5VOfoBfAOUfe-bgJp2OOX0ifCA0UZ-wK8pou5CRVmmS70pPk_2GKAvhPTDSs/s1600/setselection.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYSa8LniW_Gq8DQCKczR-RiRZsFaLaZqvs8E6pPxMdnTYR_gh-geYpEqt8TVwYU0U5P2JdZ3pVcUqcM-M5VOfoBfAOUfe-bgJp2OOX0ifCA0UZ-wK8pou5CRVmmS70pPk_2GKAvhPTDSs/s1600/setselection.jpg" height="327" width="400" /></a></div>
<div style="line-height: 150%;">
<span style="color: #222222;"><br /></span>
<span style="color: #222222;">As you can see the method setSelection calls setSelectionInt, which checks if the currently selected item <b>is equal to the item already selected</b>: in this case no event is triggered.</span></div>
<div style="line-height: 150%;">
<span style="color: #222222;">From the source code of setSelectionInt we discover that the class uses the variable <b>mOldSelectedPosition </b>to keep track of the already selected item of the Spinner. However, the AbsSpinner class contains no definition of this variable, so <b>we have to check the superclasses</b>.</span></div>
<div style="line-height: 150%;">
<span style="color: #222222;">After a brief search you can discover that mOldSelectedPosition is defined in the class <b>AdapterView </b>(superclass of AbsSpinner):</span><br />
<span style="color: #222222;"><br /></span></div>
<div class="separator" style="clear: both; line-height: 150%; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVDkggSu9STyL9h3B6duyRfEfftky6Cx41q2PGCLQzU2iJNhmvbwwcfa63m-Cf99A3eXvkWJcbEjLX7yn-lw7ZAd1DvOMqdUcrXHXiS61_cV1WvSZ4erGN7y1SlTnynGo24NCS8PrdE1Q/s1600/variabile.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVDkggSu9STyL9h3B6duyRfEfftky6Cx41q2PGCLQzU2iJNhmvbwwcfa63m-Cf99A3eXvkWJcbEjLX7yn-lw7ZAd1DvOMqdUcrXHXiS61_cV1WvSZ4erGN7y1SlTnynGo24NCS8PrdE1Q/s1600/variabile.jpg" height="70" width="400" /></a></div>
<div style="line-height: 150%;">
<span style="color: #222222;"><br /></span>
<span style="color: #222222;">Now we have all the elements to create our custom Spinner with "re-select" functionality:</span></div>
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>import java.lang.reflect.Field;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.Spinner;
public class SpinnerReselect extends Spinner {
public SpinnerReselect(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public SpinnerReselect(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public SpinnerReselect(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
@Override
public void setSelection(int position, boolean animate) {
ignoreOldSelectionByReflection();
super.setSelection(position, animate);
}
private void ignoreOldSelectionByReflection() {
try {
Class<?> c = this.getClass().getSuperclass().getSuperclass().getSuperclass();
Field reqField = c.getDeclaredField("mOldSelectedPosition");
reqField.setAccessible(true);
reqField.setInt(this, -1);
} catch (Exception e) {
Log.d("Exception Private", "ex", e);
// TODO: handle exception
}
}
@Override
public void setSelection(int position) {
ignoreOldSelectionByReflection();
super.setSelection(position);
}
}
</code></pre>
<div style="line-height: 150%;">
<span style="color: #222222;"><br /></span>
</div>
<br />
<div style="line-height: 150%;">
<br /></div>
<div style="line-height: 150%;">
<span style="color: #222222;"></span><span style="color: #222222;">By implementing our custom Spinner we have to <b>override the default implementation</b> of the setSelection methods. To do so, we simply call the method </span><span style="color: #222222;">ignoreOldSelectionByReflection before calling the default methods (defined in the class AbsSpinner: that's why we use super.setSelection...).</span><br />
<span style="color: #222222;"><br /></span></div>
<span style="color: #222222; line-height: 150%;">In the method </span><span style="color: #222222; line-height: 150%;">ignoreOldSelectionByReflection <b>we make use of Java reflection</b>. </span><span style="color: #222222;"><span style="line-height: 24px;">Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine. </span></span><span style="orphans: auto; widows: auto;">This is a relatively advanced feature and should be used only by developers who have a strong grasp of the fundamentals of the language. With that caveat in mind, reflection is a powerful technique and can enable applications to perform operations which would otherwise be impossible.</span><br />
<span style="orphans: auto; widows: auto;"><br /></span>
<span style="orphans: auto; widows: auto;">Let's examine the code:</span><br />
<span style="orphans: auto; widows: auto;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; orphans: auto; widows: auto;">Class<?> c = this.getClass().getSuperclass().getSuperclass().getSuperclass();</span><br />
<span style="orphans: auto; widows: auto;"><br /></span>
<span style="orphans: auto; widows: auto;">As we already saw the variable mOldSelectedPosition is<b> defined the class AdapterView</b> (superclass of AbsSpinner). So we have to get a reference to this class by calling getClass and getSuperclass respectively.</span><br />
<span style="orphans: auto; widows: auto;"><br /></span>
<br />
<div style="orphans: auto; widows: auto;">
<span style="font-family: Courier New, Courier, monospace;">Field reqField = c.getDeclaredField("mOldSelectedPosition");</span></div>
<div style="orphans: auto; widows: auto;">
<span style="font-family: Courier New, Courier, monospace;">reqField.setAccessible(true);</span></div>
<div style="orphans: auto; widows: auto;">
<br /></div>
<div style="orphans: auto; widows: auto;">
The secondo step is to <b>get access to the field mOldSelectedPosition</b>. By calling reqField.setAccessible(true) we make sure that the reflected object should suppress Java language access checking when it is used.</div>
<div style="orphans: auto; widows: auto;">
<br /></div>
<div style="orphans: auto; widows: auto;">
<b>reqField.setInt(this, -1);</b></div>
<div style="orphans: auto; widows: auto;">
<br /></div>
<div style="orphans: auto; widows: auto;">
The trick is quite clear: we set the value of mOldSelectedPosition to -1 to make sure that the currently selected item of the Spinner <b>is always different</b> from the previously selected item, even if the user re-selectes the same item.<br />
This way the method setSelection is always triggered!</div>
<div style="orphans: auto; widows: auto;">
<br /></div>
</div>
<div style="line-height: 150%; margin-bottom: 0.4cm; orphans: 2; widows: 2;">
<span style="color: #222222;"><span style="font-family: Roboto, Times New Roman;"><span lang="en-US"><br /></span></span></span></div>
iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com4tag:blogger.com,1999:blog-4837974211659692060.post-88475858002188688302014-04-27T13:04:00.000-07:002014-04-27T13:04:34.840-07:00ListPreference: how to load data dinamicallyIn this tutorial I'll explain how to <b>populate a ListPreference programmatically</b>. It is easier than you might expect; however I haven't found any official tutorial about it. If you need <b>more information</b> about Settings in Android you can read the <a href="http://developer.android.com/guide/topics/ui/settings.html" target="_blank">official documentation</a>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfUzsNyGD0Eom3s39eQBptxLVKk0nRjwlRzSZSnGL8iZdlqK6dyDs3qNarRr_RQ65FAmDSaz6ZbrmzNJYv2bEjYd2KUiO1IByig8jdB_g5SgbZidMPxhLFi15Maoa0MI0GxaBiR_fz3Jc/s1600/android.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfUzsNyGD0Eom3s39eQBptxLVKk0nRjwlRzSZSnGL8iZdlqK6dyDs3qNarRr_RQ65FAmDSaz6ZbrmzNJYv2bEjYd2KUiO1IByig8jdB_g5SgbZidMPxhLFi15Maoa0MI0GxaBiR_fz3Jc/s1600/android.jpg" height="214" width="320" /></a></div>
<br />
Generally speaking, if you want to add a ListPreference to your app's settings, you have to add a ListPreference object in the preference XML file, like in the following example:<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code><ListPreference
android:dependency="pref_sync"
android:key="pref_syncConnectionType"
android:title="@string/pref_syncConnectionType"
android:dialogTitle="@string/pref_syncConnectionType"
android:entries="@array/pref_syncConnectionTypes_entries"
android:entryValues="@array/pref_syncConnectionTypes_values"
android:defaultValue="@string/pref_syncConnectionTypes_default" />
</code></pre>
<br />
As you can see you provide the entries of the ListPreference, and the corresponding values, with the items <span style="font-family: Courier New, Courier, monospace;"><b>android:entries</b></span> and <span style="font-family: Courier New, Courier, monospace;"><b>android:entryValues</b>,</span> that refer to an array loaded in the res/values folder.<br />
But if you want to <b>load the data programmatically</b> (for example, if you want to fetch the data from a local database or from an online service), you must create a <b>custom ListPreference class</b>.<br />
<br />
To begin with, let's see the new preference XML file with a reference to our custom ListPreference:<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code><com.androidthetechnicalblog.preference.MyCustomPreference
android:key="pref_mycustompreference"
android:title="@string/pref_mycustompreference"
android:summary="@string/pref_mycustompreference_summary"/>
</code></pre>
<br />
We are creating a custom ListPreference class, so we must provide the <b>full path of the class</b>. As you can also see, we omitted <span style="font-family: Courier New, Courier, monospace;">android:entries</span> and <span style="font-family: Courier New, Courier, monospace;">android:entryValues</span>, because we want to load the data programmatically.<br />
<br />
Now let's see how MyCustomPreference class looks like (not relevant code omitted for brevity):<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>public class MyCustomPreference extends ListPreference {
// ...
public MyCustomPreference (Context context, AttributeSet attrs) {
super(context, attrs);
setEntries(entries());
setEntryValues(entryValues());
setValueIndex(initializeIndex());
}
public MyCustomPreference (Context context) {
this(context, null);
}
private CharSequence[] entries() {
//action to provide entry data in char sequence array for list
String myEntries[] = {"one", "two", "three", "four", "five"};
return myEntries;
}
private CharSequence[] entryValues() {
//action to provide value data for list
String myEntryValues[] = {"ten", "twenty", "thirty", "forty", "fifty"};
return myEntryValues;
}
private int initializeIndex() {
//here you can provide the value to set (typically retrieved from the SharedPreferences)
//...
int i = 2;
return i;
}
}
</code></pre>
<span style="font-family: Times, Times New Roman, serif;"><br /></span>
<span style="font-family: inherit;">The code is quite simple. You just have to provide the entries and entryValues through the methods <b>setEntries </b>and <b>setEntryValues</b>, that accept a CharSequence (or String) array as a parameter.
You can also set the default initial value, typically retrieved from the SharedPreferences, through the method <b>setValueIndex</b>. </span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">For everything that is not explicitly covered in this tutorial you can refer to the <a href="http://developer.android.com/guide/topics/ui/settings.html" target="_blank">official documentation aboud Android settings</a>.</span>iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com2tag:blogger.com,1999:blog-4837974211659692060.post-82814895842119951432014-04-23T10:27:00.000-07:002014-04-23T10:27:52.951-07:00Animating a ProgressBar to a specific valueIn this tutorial I'll explain how to set a specific progress value to a ProgressBar <b>using a smooth animation</b>.<div>
<br /><div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinqD2FKmGVnTXDgNIraqC019htWZRdD9LYbRQQSEs4xQUqlbNaM08vW8Hf4c6dHqCKxRoX-J7ZIrPv88kK8dG0pM1yV14bbxVxA93IlAXvPoPfOaX85pu6yFaIpbDIdBXqOexE9y2pa9c/s1600/ascreen.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinqD2FKmGVnTXDgNIraqC019htWZRdD9LYbRQQSEs4xQUqlbNaM08vW8Hf4c6dHqCKxRoX-J7ZIrPv88kK8dG0pM1yV14bbxVxA93IlAXvPoPfOaX85pu6yFaIpbDIdBXqOexE9y2pa9c/s1600/ascreen.png" height="320" width="312" /></a></div>
<div>
<br /><div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">ObjectAnimator animation = ObjectAnimator.ofInt(pbBudget, "progress", 0, 50);</span></div>
<div>
To begin with we create an <b><a href="http://developer.android.com/reference/android/animation/ObjectAnimator.html" target="_blank">ObjectAnimator</a> </b>object: this is a subclass of ValueAnimator that <span style="font-family: inherit;"><span style="background-color: #f9f9f9; color: #222222; line-height: 19px;">provides support for animating properties on target objects. The constructors of this class take parameters to define the target object that will be animated as well as the name of the property that will be animated. In this example we used the following parameters:</span></span></div>
<div>
<ul>
<li><span style="color: #222222;"><span style="line-height: 19px;"><b>pbBudget</b>: reference to the ProgressBar in the layout;</span></span></li>
<li><span style="color: #222222;"><span style="line-height: 19px;">"<b>progress</b>": the name of the property to be animated;</span></span></li>
<li><span style="color: #222222;"><span style="line-height: 19px;"><b>0</b>: starting point of the animation;</span></span></li>
<li><span style="color: #222222;"><span style="line-height: 19px;"><b>50</b>: ending point of the animation.</span></span></li>
</ul>
<div>
<span style="color: #222222; font-family: Courier New, Courier, monospace;"><span style="line-height: 19px;"><br /></span></span></div>
<div>
<span style="color: #222222; font-family: Courier New, Courier, monospace;"><span style="line-height: 19px;">animation.setDuration(1500);</span></span></div>
</div>
<div>
<span style="color: #222222; line-height: 19px;">The code is self-explanatory: the animation </span><b style="color: #222222; line-height: 19px;">lasts 1,5 seconds</b><span style="color: #222222; line-height: 19px;">.</span></div>
<div>
<span style="color: #222222;"><span style="line-height: 19px;"><br /></span></span></div>
<div>
<span style="color: #222222;"><span style="line-height: 19px;"><br /></span></span></div>
<div>
<span style="color: #222222; font-family: Courier New, Courier, monospace;"><span style="line-height: 19px;">animation.setInterpolator(new DecelerateInterpolator());</span></span></div>
<div>
<span style="color: #222222; line-height: 19px;">It is possible to use different interpolators for our animation, like for example:</span></div>
<div>
<ul>
<li><span style="color: #222222;"><span style="line-height: 19px;"><b><a href="http://developer.android.com/reference/android/view/animation/LinearInterpolator.html" target="_blank">LinearInterpolator</a></b>, </span></span><span style="background-color: #f9f9f9; color: #222222; line-height: 19px;"><span style="font-family: inherit;">where the rate of change is constant;</span></span></li>
<li><span style="color: #222222;"><span style="line-height: 19px;"><b><a href="http://developer.android.com/reference/android/view/animation/DecelerateInterpolator.html" target="_blank">DecelerateInterpolator</a></b>, </span></span><span style="background-color: #f9f9f9; color: #222222; line-height: 19px;"><span style="font-family: inherit;">where the rate of change starts out quickly and and then decelerates</span></span><span style="background-color: #f9f9f9; color: #222222; line-height: 19px;"><span style="font-family: inherit;">;</span></span></li>
<li><span style="background-color: #f9f9f9; color: #222222; line-height: 19px;"><span style="font-family: inherit;"><b><a href="http://developer.android.com/reference/android/view/animation/AccelerateInterpolator.html" target="_blank">AccelerateInterpolator</a></b>, </span></span><span style="background-color: #f9f9f9; color: #222222; line-height: 19px;"><span style="font-family: inherit;">where the rate of change starts out slowly and and then accelerates;</span></span></li>
<li><span style="background-color: #f9f9f9; color: #222222; line-height: 19px;"><span style="font-family: inherit;"><b>OvershootInterpolator</b>, </span></span><span style="background-color: #f9f9f9; color: #222222; line-height: 19px;"><span style="font-family: inherit;">where the change flings forward and overshoots the last value then comes back;</span></span></li>
<li><span style="background-color: #f9f9f9; color: #222222; line-height: 19px;"><span style="font-family: inherit;">etc... (for other interpolator check the interface <b><a href="http://developer.android.com/reference/android/view/animation/Interpolator.html" target="_blank">android.view.animation.Interpolator</a></b>).</span></span></li>
</ul>
<div>
<span style="color: #222222;"><span style="line-height: 19px;"><br /></span></span></div>
<div>
<span style="color: #222222; font-family: Courier New, Courier, monospace;"><span style="line-height: 19px;">animation.start();</span></span></div>
</div>
<div>
<span style="color: #222222; font-family: Courier New, Courier, monospace;"><span style="line-height: 19px;"><br /></span></span></div>
<div>
<span style="color: #222222; line-height: 19px;">You can also create an animation for the ProgressBar </span><b style="color: #222222; line-height: 19px;">from scratch</b><span style="color: #222222; line-height: 19px;">, using the method setProgress(int progress) with a delay (android.os.SystemClock.sleep(long ms)).</span></div>
<div>
<span style="color: #222222;"><span style="line-height: 19px;">If you decide to do so, <b>I suggest to use an <a href="http://developer.android.com/reference/android/os/AsyncTask.html" target="_blank">AsyncTask</a></b><a href="http://developer.android.com/reference/android/os/AsyncTask.html" target="_blank"> </a>and update the ProgressBar using the onProgressUpdate method.</span></span></div>
<div>
<span style="color: #222222;"><span style="line-height: 19px;">Avoid animating the ProgressBar in the UI thread with a loop:</span></span></div>
<div>
<ol>
<li><span style="color: #222222; line-height: 19px;">because <b>this will freeze the UI</b> until the animation is completed;</span></li>
<li><span style="color: #222222; line-height: 19px;">because even though you are in the UI thread, you don't release the UI thread until the animation is completed, <b>thus preventing the system to update the UI (and the ProgressBar) itself</b>.</span></li>
</ol>
</div>
<div>
<span style="color: #222222;"><span style="line-height: 19px;"><br /></span></span></div>
</div>
</div>
iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com4tag:blogger.com,1999:blog-4837974211659692060.post-79332433488681724892014-04-16T10:03:00.002-07:002014-04-16T10:03:37.201-07:00Hidden Android APIs: hiding SMS messages to the default SMS receiverIn a previous tutorial we saw how to take advantage of the hidden Android APIs to listen to incoming SMS messages.<br />
Now suppose that we want to <b>listen to specific SMS messages</b> (messages coming from a particular number or containing specific strings) and to <b>hide them to the default SMS receiver</b> (like Google Hangout or other client).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgjSDONCR-txd4eTAtFXfsOqnapVzEFFlj3FOHEXKoV0EYiS1Lc7D5x8CGiE0U4n_NQM_A7nDCT0UiuHo6ufhrGdH9SBFMrR-uRTrG4WfIgM5ildVwzi7WsC46eT-agBXruob7hC1eY7Q/s1600/Android+Spy+Apps+Boon+or+Bane%5B5%5D.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgjSDONCR-txd4eTAtFXfsOqnapVzEFFlj3FOHEXKoV0EYiS1Lc7D5x8CGiE0U4n_NQM_A7nDCT0UiuHo6ufhrGdH9SBFMrR-uRTrG4WfIgM5ildVwzi7WsC46eT-agBXruob7hC1eY7Q/s1600/Android+Spy+Apps+Boon+or+Bane%5B5%5D.jpg" height="227" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">This is a private message!</td></tr>
</tbody></table>
<br />
As in the previous tutorial we have to declare a BroadcastReceiver in the AndroidManifest.xml file. However, in order to take priority over the default SMS receiver, we also have to <b>set a high priority</b> for our SMS BroadcastReceiver:<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code><receiver android:name="com.androidthetechinalblog.SMSReceiver">
<intent-filter android:priority="9999">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
</code></pre>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
Now we just have to make some minor changes to the SMSReceiver class:<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>public class SMSReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals(“android.provider.Telephony.SMS_RECEIVED”)) {
Object incomingSMSs[] = (Object[]) intent.getSerializableExtra(“pdus”);
for(Object tmp : incomingSMSs) {
byte message[] = (byte[]) tmp;
SmsMessage smsMessage = SmsMessage.createFromPdu(message);
String phoneNumber = smsMessage.getOriginatingAddress();
String messageBody = smsMessage.getMessageBody();
if(phoneNumber.equals("3457148596") || messageBody.contains("test")) {
//we have found our SMS! here you can perform some actions
<b>abortBroadcast();
setResultData(null);</b>
}
}
}
}
}
</code></pre>
<br />
<span style="background-color: white;">As you can see, by calling <b>abortBroadcast()</b> and <b>setResultData(null) </b>(methods working only for "ordered broadcasts", like in our example) we make sure that our SMS won't be propagated to any other receiver.</span>iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com7tag:blogger.com,1999:blog-4837974211659692060.post-53699071655487311462014-04-02T11:14:00.000-07:002014-04-02T11:14:33.871-07:00Quick trick of the week: EditText inside a ListView<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpDGanxEPkmT6w6xwdain89M_8I9JMxwFWg6UCNP5-tsq2lizGN9Qxbn7uglFhjOkrQ2lu8YD3sIzwMPhgHg6gWksAW17QcLzvAMfdSGSpo0Jac040LdOivF0H4hay3LDZKiloAQ2hFZo/s1600/Coolest-Android-Tricks-And-Tips-You-Must-Try.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpDGanxEPkmT6w6xwdain89M_8I9JMxwFWg6UCNP5-tsq2lizGN9Qxbn7uglFhjOkrQ2lu8YD3sIzwMPhgHg6gWksAW17QcLzvAMfdSGSpo0Jac040LdOivF0H4hay3LDZKiloAQ2hFZo/s1600/Coolest-Android-Tricks-And-Tips-You-Must-Try.gif" height="188" width="320" /></a></div>
<br />
<br />
Let's suppose you want to create a layout with a ListView <b>containing an EditText in each item</b>, like in the following picture:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw-D1g8CAZ5Hj02HsR0MFsBKIW-RXtOEmr_ZsARUzS-875_dAslAHlLhKJxQB3iQHpVyzfhKTBz34EkgsbdVI47I1yKVIhu-WjzKkxHuNZUI4qJUU1Obzhqjzcitc8I_HGzXEJtu-NUdM/s1600/Android+EditText+onFocus+inside+ListView.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw-D1g8CAZ5Hj02HsR0MFsBKIW-RXtOEmr_ZsARUzS-875_dAslAHlLhKJxQB3iQHpVyzfhKTBz34EkgsbdVI47I1yKVIhu-WjzKkxHuNZUI4qJUU1Obzhqjzcitc8I_HGzXEJtu-NUdM/s1600/Android+EditText+onFocus+inside+ListView.png" height="320" width="202" /></a></div>
<br />
If yout set up your layout like the one showed above you'll soon have to deal with an annoying problem: for some unknown reason the EditText <b>immediately loses focus</b>, and it's almost impossible to write anything.<br />
For some devices a good workaround would be to <b>double tap on the EditText</b>, but this is not an accetable solution for the end users of our apps.<br />
<br />
Fortunately the solution is quite easy: you just have to add the following lines of code:<br />
<ol>
<li>in the <b>AndroidManifest.xml file</b> add the following line for the Activity containing the ListView: android:windowSoftInputMode="adjustPan";</li>
<li>in the <b>layout file of the Activity</b> add the following line to your ListView: android:descendantFocusability="beforeDescendants".</li>
</ol>
<br />
<br />
Now the EditText(s) should behave as expected...<br />
<br />
<span style="font-family: inherit;"> <activity android:name="com.androidthetechnicalblog.MyActivity"</span><br />
<span style="font-family: inherit;"> android:configChanges="keyboardHidden|orientation|screenSize" </span><br />
<span style="font-family: inherit;"> <b>android:windowSoftInputMode="stateHidden|adjustPan"</b></span><br />
<span style="font-family: inherit;"> android:label="@string/app_name"></activity>
</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">
</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> </span><br />
<br />
<span style="font-family: inherit;"><ListView</span><br />
<span style="font-family: inherit;"> android:id="@android:id/list"
</span><br />
<span style="font-family: inherit;"> <b>android:descendantFocusability="beforeDescendants" </b> </span><br />
<span style="font-family: inherit;"> android:layout_width="match_parent"</span><br />
<span style="font-family: inherit;"> android:layout_height="wrap_content"
</span><br />
<span style="font-family: inherit;"> android:layout_marginTop="10dp" /></span>iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com13tag:blogger.com,1999:blog-4837974211659692060.post-52187945216452138572014-03-31T11:17:00.000-07:002014-03-31T11:18:33.696-07:00Hidden Android APIs: SettingsIn the previous tutorial we talked about the <b>hidden Android APIs</b>, how to discover them and how to use them in our apps. To be more precise, we saw that the easiest way to use the hidden APIs is to <b>copy hidden constants</b> from the Android source code into our Activities (this way we can, for example, set up a BroadcastReceiver to intercept incoming SMS messages).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmD_qPkwXX7dJZfpP5a6dZYrdusUOsISUk8k8uBx0oeJ_PFutEclzTTKw9pgdm3S_UEm5xqoeYfrttLc2TtsKJQPVRzZEzOkqsQzR-Tb_aIW8hyphenhyphenTklfUW1QjsWuSRqT9vheEJg85VcuF8/s1600/settings.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmD_qPkwXX7dJZfpP5a6dZYrdusUOsISUk8k8uBx0oeJ_PFutEclzTTKw9pgdm3S_UEm5xqoeYfrttLc2TtsKJQPVRzZEzOkqsQzR-Tb_aIW8hyphenhyphenTklfUW1QjsWuSRqT9vheEJg85VcuF8/s1600/settings.jpg" height="244" width="320" /></a></div>
<br />
<br />
The same method can be used to start Activities to <b>change specific system settings</b> directly from our app. As far as system settings are concerned, there are some settings that are available in the official and public APIs. An example is the constant <span style="font-family: Courier New, Courier, monospace;">Settings.ACTION_AIRPLANE_MODE_SETTINGS</span>, through which we can show settings to allow entering/exiting airplane mode.
But there are a lot of other settings which are available only in the hidden APIs. To find them, look for the Settings class <b>with AndroidXRef</b>, as follows:
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9N84Z23xdvzZbTbEQ77CrIT8NBJTmMY5hVIpljGML8-51nXYt9azjDDs-mMkPUdbEgkDn6SSIsn6LCsoHy6qjQWjbS_RiW8GqHDZWREqsIvvSmEwdQR6rToCwbzEXgYZ7nGQCudPk7EE/s1600/xref.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9N84Z23xdvzZbTbEQ77CrIT8NBJTmMY5hVIpljGML8-51nXYt9azjDDs-mMkPUdbEgkDn6SSIsn6LCsoHy6qjQWjbS_RiW8GqHDZWREqsIvvSmEwdQR6rToCwbzEXgYZ7nGQCudPk7EE/s1600/xref.jpg" height="165" width="400" /></a></div>
<br />
To find the hidden settings you just have to look for the <b>"@hide" tag</b>. You will find all the constants you can use to create Intents to <b>launch specific parts of the settings UI</b>.<br />
For example, if you want to launch an Activity to check system updates, you can use the hidden constant <span style="font-family: Courier New, Courier, monospace;">Settings.</span><span style="text-decoration: none;"><a class="xfld" href="http://androidxref.com/4.4.2_r2/s?refs=ACTION_SYSTEM_UPDATE_SETTINGS&project=frameworks" style="text-decoration: none;"><span style="color: black; font-family: Courier New, Courier, monospace;">ACTION_SYSTEM_UPDATE_SETTINGS</span></a>:</span><br />
<span style="color: black; text-decoration: none;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiPGXkpGrEbbEKOlQhEoFp9k7-9wU-_omFJnz7SHTQ7Yyj_shq7vgkCw9mYSiOcLjHDCkUSIJ9gxKGMg_4zvfTmt-4HhU8gCZrbM2jy1oqZP_8-RW07hZCoGQn1ZJZnoTw-rOkH9QE-9c/s1600/imm.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiPGXkpGrEbbEKOlQhEoFp9k7-9wU-_omFJnz7SHTQ7Yyj_shq7vgkCw9mYSiOcLjHDCkUSIJ9gxKGMg_4zvfTmt-4HhU8gCZrbM2jy1oqZP_8-RW07hZCoGQn1ZJZnoTw-rOkH9QE-9c/s1600/imm.jpg" height="170" width="400" /></a></div>
<span style="color: black; text-decoration: none;"><br /></span>
<span style="color: black; text-decoration: none;">As you can see from the Android source code, this constant is marked with the "@hide" tag, so it is <b>not visible in the official API</b>.</span><br />
You can use this constant in the following way:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">Intent pref = new Intent("android.settings.SYSTEM_UPDATE_SETTINGS");</span>
<span style="font-family: Courier New, Courier, monospace;">startActivity(pref);</span><br />
<span style="color: black; font-family: inherit; text-decoration: none;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">
</span>
<span style="color: black; text-decoration: none;">
</span>
<span style="color: black; font-family: inherit; text-decoration: none;">When you want to use hidden constants to change system settings you must be aware of two things:</span><br />
<br />
<ol>
<li>in some cases a matching Activity for a given constant <b>may not exist</b>, so ensure you safeguard against this;</li>
<li>for some settings you have to add <b>special permissions</b> to the AndroidManifest.xml file (you can refer to the error messages in the Logcat to discover the permissions needed).</li>
</ol>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com0tag:blogger.com,1999:blog-4837974211659692060.post-37323431566285168352014-03-26T09:56:00.000-07:002014-03-26T10:20:31.573-07:00Hidden Android APIs: listening to incoming SMS messages<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
In the
Android platform there are two classes, <b>SmsManager and SmsMessage</b>,
for sending SMS messages; hower there is no official class for
receiving them. To be able to receive SMS messages we have to use a
<b>hidden API</b>, present in the Android platform but not generally
available for developers.</div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
Hidden
Android APIs contain several <b>constants, methods, interfaces</b>, etc.
that can come in handy in a variety of situations.</div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8OwtgJCm4zKSuhkzVsVF4nYb1AyRsazSY1d_LlplBIkgP5_Luc-DtT_klwR-iEwWXiD5N5c7P__k_ikS4oB7tFjD4OluQP7_CadHnqAjItZLqf0hGkMewQwsagB-oOuvdLkNBNYIhp9I/s1600/secret.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8OwtgJCm4zKSuhkzVsVF4nYb1AyRsazSY1d_LlplBIkgP5_Luc-DtT_klwR-iEwWXiD5N5c7P__k_ikS4oB7tFjD4OluQP7_CadHnqAjItZLqf0hGkMewQwsagB-oOuvdLkNBNYIhp9I/s1600/secret.jpg" height="180" width="320" /></a></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
To discover
hidden Android APIs you can use the following resource:</div>
<ul>
<li><div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US"><b><u>AndroidXRef
</u></b> (</span><span style="color: blue;"><u><a href="http://androidxref.com/"><span lang="en-US">http://androidxref.com</span></a></u></span><span lang="en-US">):
this site has indexed all the Android source code and offers a
useful search box; however you have to know exactly what you are
looking for.</span></div>
</li>
</ul>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgv_LXy7NVRvaoAnAS3Xb31tX4UjNsVn91-asSve29CKL7qG1Yyoihx2vQNoJmMUqnx9G4dy0uatLdEYps5Z-0gUlJRzLEe3p5r58oGUWsICkY649xGtV17vewckQm9YI6qgQxMLFudXe8/s1600/xref.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgv_LXy7NVRvaoAnAS3Xb31tX4UjNsVn91-asSve29CKL7qG1Yyoihx2vQNoJmMUqnx9G4dy0uatLdEYps5Z-0gUlJRzLEe3p5r58oGUWsICkY649xGtV17vewckQm9YI6qgQxMLFudXe8/s1600/xref.jpg" height="166" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Searching class Telephony from AndroidXRef</td></tr>
</tbody></table>
<div style="text-align: justify;">
<br /></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US">In
order to make use of the Android hidden APIs, there are two possible
scenarios:</span></div>
<ul>
<li><div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US"><b><u>constants</u></b>:
if you just need to use a hidden constant (for example for broacast
actions), you can simply copy them from the Android source code into
your app. In this tutorial we will use this technique;</span></div>
</li>
<li><div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<b><u>methods,
classes, interfaces, etc.</u></b>: hidden methods, classes and interfaces
must be compiled, before beeing able to use them. To do this you can
either modify the SDK jar file used to compile your app, or make use
of the java reflection method, each of which has its pros and cons.</div>
</li>
</ul>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
To be able
to receive incoming SMS messages we will use the following hidden
constants contained in the class telephony-common (you can find them
using the utilities listed above):</div>
<ul>
<li><div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
“<b>android.provider.Telephony.SMS_RECEIVED</b>”:
Intent action used in our BroadcastReceiver to listen to incoming
SMS messages;</div>
</li>
<li><div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
“<b>pdus</b>”:
constant used to retrieve SMS data from the Intent.</div>
</li>
</ul>
<div style="text-align: justify;">
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjJ5N2O5dkEKZ2lrjdqI1Q39TjHZiVPQ9g8pN3QMKolUFo2f1S-9dTJTcY-dr-5zM17oc1arDgisGNYn2sNTuKITm-QASdYQTc_yysP0w2wYL2RK1MugxWD3V3bx_tTrzTWD4WDp9PTuE/s1600/source2.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjJ5N2O5dkEKZ2lrjdqI1Q39TjHZiVPQ9g8pN3QMKolUFo2f1S-9dTJTcY-dr-5zM17oc1arDgisGNYn2sNTuKITm-QASdYQTc_yysP0w2wYL2RK1MugxWD3V3bx_tTrzTWD4WDp9PTuE/s1600/source2.jpg" height="232" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Extract from the class Telephony of the Android source code</td></tr>
</tbody></table>
<div style="text-align: justify;">
<br /></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRKPiIONKi7g4ouIEKH3YPXPMeY5PX8FFXSKyv00dIOd2ugIlWjGrfnuwJt3x1ZzVhYJHSRqRYRJa-ffUzPjre1Wr8dX7tQZZ4BtYCaDIx1rHVbiWq761UykQW24Kt6hfhI8u1cQlKN3A/s1600/source.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRKPiIONKi7g4ouIEKH3YPXPMeY5PX8FFXSKyv00dIOd2ugIlWjGrfnuwJt3x1ZzVhYJHSRqRYRJa-ffUzPjre1Wr8dX7tQZZ4BtYCaDIx1rHVbiWq761UykQW24Kt6hfhI8u1cQlKN3A/s1600/source.jpg" height="236" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Extract from the class Telephony of the Android source code</td></tr>
</tbody></table>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
So here is
the code:</div>
<ol>
<li><div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
declare
the use of the RECEIVE_SMS <b>permission </b>in the AndroidManifest.xml
file;</div>
</li>
<li><div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<b>declare
a BroadcastReceiver</b> in the AndroidManifest.xml file with the
intent-filter “android.provider.Telephony.SMS_RECEIVED”;</div>
</li>
<li><div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US"><b>implement
the BroadcastReceiver</b> as follows:</span></div>
</li>
</ol>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<pre class="brush: csharp">
public class SMSReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals(“android.provider.Telephony.SMS_RECEIVED”)) {
Object incomingSMSs[] = (Object[]) intent.getSerializableExtra(“pdus”);
for(Object tmp : incomingSMSs) {
byte message[] = (byte[]) tmp;
SmsMessage smsMessage = SmsMessage.createFromPdu(message);
}
}
}
}
</pre>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
Once you
have a SmsMessage object, you can use one ot its several methods to
retrieve useful info about the SMS received:</div>
<pre class="brush: csharp">
smsMessage.getOriginatingAddress();
smsMessage.getMessageBody();
etc.
</pre>
iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com6tag:blogger.com,1999:blog-4837974211659692060.post-49297897615888334732014-03-12T11:01:00.000-07:002014-03-12T11:04:05.146-07:00Binding Services – part 3 (communication Service -> Activity)<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US">In our
previous tutorial about IntentService we saw that a </span><span lang="en-US"><b>BroadcastReceiver</b></span><span lang="en-US">
can be used as a means of communication between the Service and the
calling client. Hower this method cannot be used for </span><span lang="en-US"><b>frequent
and fast calls</b></span><span lang="en-US">, such as for progress
updates. For this purpose we have to use a different approach...</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
For more
information about binding Services and the way they are connected to
a calling Activity, please refer to my previous tutorials.</div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEij7ajn9ZmDtgywUY47T4NiFRjlKwsv9WNf_Z7EAXVKSrm0E6VcctRWZyv-1JLNErBF9R2apIak4haJCvoB70HzzCpSohaCFJg3EtdegchVj3invY_q7o1TVp8stw_ioTrKbAnIsjmcSFU/s1600/android_robot_thumb.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEij7ajn9ZmDtgywUY47T4NiFRjlKwsv9WNf_Z7EAXVKSrm0E6VcctRWZyv-1JLNErBF9R2apIak4haJCvoB70HzzCpSohaCFJg3EtdegchVj3invY_q7o1TVp8stw_ioTrKbAnIsjmcSFU/s1600/android_robot_thumb.jpg" height="246" width="320" /></a></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<h2 class="western" lang="en-US">
</h2>
<h3>
SERVICE</h3>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US">First
of all we have to define a </span><span lang="en-US"><b>public
interface</b></span><span lang="en-US"> inside our Service as a means
of communication between the Service and the calling Activity:</span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">public
interface InterfaceCallback {</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"> void
onProgressUpdate(int progress);</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span lang="en-US"> void
onTaskCompleted(MyResult myResult);</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">}</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US">where
</span><span style="font-family: Courier New, monospace;"><span lang="en-US">MyResult</span></span><span lang="en-US">
is a </span><span lang="en-US"><b>user defined class</b></span><span lang="en-US">
carrying the results of the operation performed by the Service in the
background.</span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US">The
next step is to connect our Service to the calling Activity. To do
this, we define an </span><span lang="en-US"><b>instance variable</b></span><span lang="en-US">
of the type </span><span style="font-family: Courier New, monospace;"><span lang="en-US">InterfaceCallback</span></span><span lang="en-US">
and create a </span><span lang="en-US"><b>public method</b></span><span lang="en-US">
that will be called by the calling Activity to connect itself to the
Service (the following code goes inside the Service class):</span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span lang="en-US">private
InterfaceCallback interfaceCallback;</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">...</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span lang="en-US">public
void setInterfaceCallback(InterfaceCallback interfaceCallback) {</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"> this.interfaceCallback
= interfaceCallback;</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">}</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US">Now
our Service is ready to communicate with the calling Activity using
the </span><span style="font-family: Courier New, monospace;"><span lang="en-US">interfaceCallback
</span></span><span lang="en-US">reference</span><span style="font-family: Courier New, monospace;"><span style="font-size: x-small;"><span lang="en-US">.
</span></span></span><span lang="en-US">For example, if we want to
</span><span lang="en-US"><b>notify the updates</b></span><span lang="en-US">
of a background task (from the </span><span style="font-family: Courier New, monospace;"><span lang="en-US">onProgressUpdate</span></span><span lang="en-US">
method of an AsyncTask, for instance) we can call:</span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">interfaceCallback.onProgressUpdate(progress);</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: x-small;"><br /></span></span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US">In the
same way, if we need to communicate that the background operation </span><span lang="en-US"><b>has
been completed</b></span><span lang="en-US"> and send and object
containing the results, we can simply call:</span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">interfaceCallback.onTaskCompleted(myResult);</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><br /></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXYfd7LK9Tl40t3gxQmVnXLvKGtWTaJXEh-NStIF314CUmI6_6dY8z7oeu3g1c8z_JMoaRPSJ6TSsF_Dg3Cfbno_rCmDcjjWIqXvlYc8lSA9mbfRBZZmFVYsSwmN8IsJgv0IYVCgDSgVA/s1600/service_lifecycle.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXYfd7LK9Tl40t3gxQmVnXLvKGtWTaJXEh-NStIF314CUmI6_6dY8z7oeu3g1c8z_JMoaRPSJ6TSsF_Dg3Cfbno_rCmDcjjWIqXvlYc8lSA9mbfRBZZmFVYsSwmN8IsJgv0IYVCgDSgVA/s1600/service_lifecycle.png" height="400" width="330" /></a></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><br /></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<h3>
CALLING ACTIVITY</h3>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US">To
make sure that our Activity can receive updates from the Service </span><span lang="en-US"><b>we
have to implement</b></span><span lang="en-US"> the previously
defined interface:</span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">public
class CallingActivity extends Activity implements ServiceConnection,
MyService.InterfaceCallback {</span></div>
<div lang="en-US" style="margin-bottom: 0cm; text-indent: 1.25cm;">
<span style="font-family: Courier New, monospace;">//see
previous tutorial</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">}</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><br /></span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US">Once
we have established a valid connection with the Service, we can
</span><span lang="en-US"><b>register our Activity</b></span><span lang="en-US">
as a callback (our Activity overrides the InterfaceCallback methods
that are triggered by the Service):</span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">@Override</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">public
void onServiceConnected(ComponentName componentName, IBinder iBinder)
{</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"> MyService
myService = ((MyService.MyBinder) iBinder).getReference();</span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span lang="en-US"></span></span><span style="font-family: Courier New, monospace;"><span lang="en-US"><b> myService.setInterfaceCallback(this);</b></span></span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm; text-indent: 1.25cm;">
<span style="font-family: Courier New, monospace;">myService.startBackgroundTask();</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">}</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">@Override</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">protected
void onPause() {</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"> super.onPause();</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"> </span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"> ...</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"> if(myService
!= null) {</span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span lang="en-US"> myService</span></span><span style="font-family: Courier New, monospace;"><span lang="en-US"><b>.setInterfaceCallback(null);</b></span></span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"> unbindService(this);</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"> }</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">}</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US">Finally
we have to </span><span lang="en-US"><b>override the methods</b></span><span lang="en-US">
</span><span style="font-family: Courier New, monospace;"><span lang="en-US">onProgressUpdate</span></span><span lang="en-US">
and </span><span style="font-family: Courier New, monospace;"><span lang="en-US">onTaskCompleted</span></span><span lang="en-US">
of the implemented </span><span style="font-family: Courier New, monospace;"><span lang="en-US">InterfaceCallback
</span></span><span lang="en-US">interface</span><span style="font-family: Courier New, monospace;"><span style="font-size: x-small;"><span lang="en-US">.
</span></span></span><span lang="en-US">These methods, as we already
saw, are called from the Service to notify the connected Activity about the
progress updates and the completion of the background task:</span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">@Override</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span lang="en-US">public
void onProgressUpdate(int progress) {</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"> //code
left out for brevity</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">}</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">@Override</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span lang="en-US">public
void onTaskCompleted(MyResult myResult) {</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"> //code
left out for brevity</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">}</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<br />
<div lang="en-US" style="margin-bottom: 0cm;">
to be continued...</div>
iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com2tag:blogger.com,1999:blog-4837974211659692060.post-61112228742068997272014-03-05T09:13:00.001-08:002014-03-05T09:13:26.019-08:00Binding Services - part 2 (staying in the foreground)In our previous tutorial we saw how to create a <b>binding Service</b> and how to bind to it using the <b>Binder pattern</b>. This is a very useful pattern because, once we retrieve a valid reference to our Service, we can use this reference to call Service's methods like any other Java object.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqFzfQ9MNH4nEE_RBn5qmSrnugXFwW2bJ7Qb4EXlXlRTT3S8wuUBjK-xiwjdWy84HyxKzytNB-Ee-S72HoPKZVdknD2jYpOPf4HjIf6BRqY66RZyI0C_lYL13xUzV7zqNgYcxPlo_Cyd0/s1600/android-vs-apple.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqFzfQ9MNH4nEE_RBn5qmSrnugXFwW2bJ7Qb4EXlXlRTT3S8wuUBjK-xiwjdWy84HyxKzytNB-Ee-S72HoPKZVdknD2jYpOPf4HjIf6BRqY66RZyI0C_lYL13xUzV7zqNgYcxPlo_Cyd0/s1600/android-vs-apple.jpg" height="200" width="320" /></a></div>
<br />
<br />
Binding Services usually stay alive <b>until the last client disconnects</b>, calling the unbindService method. When no more clients are connected, the Service is <b>no longer running in the foreground</b> and may be targeted by the system for shutdown (usually when Android is <b>running out of resources</b>).<br />
In order to prevent the system from doing this, we can use the <b>startForeground method</b>. This method makes sure that the Service will stay in the foreground state (usually when executing long running tasks in the background) even if <b>no client is connected</b>.<br />
The only thing to remember is to <b>always call stopForeground</b>, with the parameter true, when the Service has completed its task, otherwise we could potentially waste system resources.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEOLKLM0Tyjw6syl1d_82VW2jVx2hIp7Q6OB-de1mPTP170E7Pi4Zwwk7RYH3ysIouSCOqKUZl9NagF0cfFMNOyjThMS8BywzJFu9HrvvxdMhw410_uxkvEdgkgeckEZWVQ1EF2Z2N4wU/s1600/Android_process_priorities.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEOLKLM0Tyjw6syl1d_82VW2jVx2hIp7Q6OB-de1mPTP170E7Pi4Zwwk7RYH3ysIouSCOqKUZl9NagF0cfFMNOyjThMS8BywzJFu9HrvvxdMhw410_uxkvEdgkgeckEZWVQ1EF2Z2N4wU/s1600/Android_process_priorities.png" height="259" width="320" /></a></div>
<br />
<br />
Let's suppose to define a method in our Service class called executeTask, which is meant to perform <b>long running operations</b>. This method is called from our Activity, once a valid reference to our Service is obtained (see previous tutorial for more details), with the following code:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">myService.executeTask();</span><br />
<br />
Now we want that our Service will stay in the foreground <b><u>until the task is completed</u></b>. We also create a notification reporting that a background operation is running:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">public void executeTask() {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> //create the Notification</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Notification.Builder builder = new Notification.Builder(this);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> builder.setContentTitle("Notification title");</span><br />
<span style="font-family: Courier New, Courier, monospace;"> builder.setContentText("Notification text");</span><br />
<span style="font-family: Courier New, Courier, monospace;"> builder.setSmallIcon(R.drawable.icon_for_notification);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Notification mNotification = builder.build();</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> //the Service won't be stopped by the system</span><br />
<span style="font-family: Courier New, Courier, monospace;"> startForeground(1001, mNotification);</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> //background operations: left out for brevity</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ...</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> //remove the Service from foreground state</span><br />
<span style="font-family: Courier New, Courier, monospace;"> stopForeground(true);</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span>iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com0tag:blogger.com,1999:blog-4837974211659692060.post-78732823812913453952014-02-24T10:12:00.001-08:002014-02-24T10:27:12.336-08:00Binding Services – part 1<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span style="font-family: inherit;"><span lang="en-US">In
this tutorial I’ll explain the basics of </span><span lang="en-US"><b>binding
Services</b></span><span lang="en-US">. For more information about
what Services are and what they are used for please refer to my
previous tutorial, IntentServices in Android, that you can find <a href="http://androidtechnicalblog.blogspot.it/2014/01/intentservice-in-android.html" target="_blank">here</a>.</span></span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span style="font-family: inherit;"><span lang="en-US"><br /></span></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgynfeFy5F8Q_qi59tWTrcYsYjAj5UZ1zWWXBhR6aolN2meWH8Cg0HA5Jcbwfhyumv5MfZ89eCziotLcTXGh1g4PBSDHsa4ioh6zRyJU5ytEH6L63rPSZMzSz1CtfS7mGJIRcQxM1yZvss/s1600/android_fb3_final.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgynfeFy5F8Q_qi59tWTrcYsYjAj5UZ1zWWXBhR6aolN2meWH8Cg0HA5Jcbwfhyumv5MfZ89eCziotLcTXGh1g4PBSDHsa4ioh6zRyJU5ytEH6L63rPSZMzSz1CtfS7mGJIRcQxM1yZvss/s1600/android_fb3_final.png" height="182" width="200" /></a></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span style="font-family: inherit;"><span lang="en-US"><br /></span></span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span style="font-family: inherit;">Services in Android can be activated in
two ways:</span></div>
<ul>
<li><div align="JUSTIFY">
<span lang="en-US">you can </span><span lang="en-US"><b>start
a Service</b></span><span lang="en-US"> through the
Context.startService() method;</span></div>
</li>
<li><div align="JUSTIFY">
<span lang="en-US">or you can </span><span lang="en-US"><b>bind
to a Service</b></span><span lang="en-US"> through the
Context.bindService() method.</span></div>
</li>
</ul>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US">The
main difference is that if you bind to a Service, the Service </span><span lang="en-US"><b>will
stay alive</b></span><span lang="en-US"> until the last client
disconnects. In addition to that, if you bind to a Service, instead
of starting it, you have a</span><span lang="en-US"><b> reference</b></span><span lang="en-US">
</span><span lang="en-US"><b>to the Service</b></span><span lang="en-US">
class that can be used to easily call the Service’s methods.</span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US">In
this first tutorial about binding Services we’ll see how you have
to </span><span lang="en-US"><b>set up your Service class</b></span><span lang="en-US">
to allow other components to be able to bind to it. To do this you
have to </span><span lang="en-US"><b>implement the onBind method</b></span><span lang="en-US">
of the Service class, which must return an IBinder object.</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
In the
following example we create an inner class, called MyBinder
(extending the Binder class – please note that the Binder class
implements the IBinder interface), and we return an object of this
class in the onBind method (we can do so because, as already said,
the Binder class implements the IBinder interface).</div>
<br />
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US">In our
MyBinder class we create a method returning a </span><span lang="en-US"><b>reference
to our Service class</b></span><span lang="en-US">, which is used in
the clients binding to the Service:</span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;">public
class MyService extends Service {</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> //the
content of the Service is omitted for brevity</span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US"><span style="font-family: Courier New, Courier, monospace;"> public
void startBackgroundTask() {</span></span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> ...</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: 'Courier New', Courier, monospace; text-indent: 1.25cm;"> ...</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><br />
</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> //MyBinder
class extending Binder</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> public
class MyBinder extends Binder {</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> public
MyService getReference() {</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> return
MyService.this;</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><br />
</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> //create
an instance of our MyBinder class</span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><span lang="en-US"></span><span lang="de-DE"> private
MyBinder myBinder = new MyBinder();</span></span></div>
<div align="JUSTIFY" lang="de-DE" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><br />
</span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><span lang="de-DE"></span><span lang="en-US"> //onBind
method, returning an instance of our MyBinder</span></span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><span lang="en-US"></span><span lang="de-DE"> @Override</span></span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span style="font-family: 'Courier New', Courier, monospace; text-indent: 1.25cm;"> public
IBinder onBind(Intent intent) {</span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm; text-indent: 1.25cm;">
<span lang="de-DE"><span style="font-family: Courier New, Courier, monospace;">return
myBinder;</span></span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm; text-indent: 1.25cm;">
<span lang="de-DE"><span style="font-family: Courier New, Courier, monospace;">}</span></span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;">}</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><br /></span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
</div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US">Now
that we have implemented the onBind method in our Service, we can
</span><span lang="en-US"><b>easily bind to the Service</b></span><span lang="en-US">
through the Context.bindService method. </span>
</div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US">To
begin with, our Activity (or other component binding to the Service)
</span><span lang="en-US"><b>must implement the ServiceConnection
interface</b></span><span lang="en-US">. The ServiceConnection
interface </span><span lang="en-US"><b>provides a callback method</b></span><span lang="en-US">,
onServiceConnected, called when a valid connection to the Service is
established.</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">public
class MyActivity extends Activity implements ServiceConnection {</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">...</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">}</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US"><b>To
bind to MyService</b></span><span lang="en-US"> we can use the
following code, typically in the onResume method (</span><span lang="en-US"><i>this</i></span><span lang="en-US">
refers to the component, our Activity in this example, that
implements the ServiceConnection interface):</span></div>
<div align="JUSTIFY">
<span style="font-family: Courier New, monospace;"><span lang="en-US"><br /></span></span></div>
<div align="JUSTIFY">
<span style="font-family: Courier New, monospace;"><span lang="en-US">Intent
intent = new Intent(this, MyService.class);</span></span></div>
<div align="JUSTIFY">
<span style="font-family: Courier New, monospace;"><span lang="en-US">bindService(intent,
this, BIND_AUTO_CREATE);</span></span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US"><b>To
unbind from MyService</b></span><span lang="en-US"> the code is the
following (typically in the onPause method):</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><br /></span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;">unbindService(this);</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US">Finally
we have to override </span><span lang="en-US"><b>the
onServiceConnected and onServiceDisconneted methods</b></span><span lang="en-US">
of the ServiceConnection interface. These methods are called,
respectively, when MyService is connected/disconnected to/from our
Activity.</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace; font-size: x-small;">@Override</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace; font-size: x-small;">public
void onServiceConnected(ComponentName componentName, IBinder iBinder)
{</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace; font-size: x-small;"> MyService
myService = ((MyService.MyBinder) iBinder).getReference();</span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace; font-size: x-small;"><span lang="en-US"> myService.startBackgroundTask();</span></span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace; font-size: x-small;">}</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-size: x-small;"><br />
</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace; font-size: x-small;">@Override</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace; font-size: x-small;">public
void onServiceDisconnected(ComponentName componentName) {</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace; font-size: x-small;"> ...</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace; font-size: x-small;">}</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
As you can
see in the onServiceConnected method we have an IBinder parameter, of
the type MyService.MyBinder, because in the onBind method of our
Service we return an object of this type (MyService.MyBinder extends
Binder and implements the IBinder interface).</div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US">Using
the iBinder reference, casting it to MyService.Binder and calling the
method getReference we obtain a </span><span lang="en-US"><b>reference
to our MyService class</b></span><span lang="en-US">. You can then
use this reference to call specific methods of MyService, omitted
here for brevity, to perform background operations (you have of
course to use </span><span lang="en-US"><b>different threads</b></span><span lang="en-US">
to perform background tasks, because all methods of the Service class
run in the UI thread).</span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<div align="JUSTIFY" style="margin-bottom: 0cm;">
<span lang="en-US">
</span></div>
<div align="JUSTIFY" lang="en-US" style="margin-bottom: 0cm;">
To be
continued...</div>
iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com0tag:blogger.com,1999:blog-4837974211659692060.post-62652905581301586242014-02-15T08:47:00.000-08:002014-02-15T08:47:19.790-08:00Using ViewPager to swipe between Fragments in an ActionBarIn this tutorial I'll briefly explain how to use the <b><span style="font-size: large;">ViewPager </span></b>widget to swipe between different <b><span style="font-size: large;">Fragments </span></b>in an <b><span style="font-size: large;">ActionBar</span></b>.<br />
In our example we not only want to swipe between Fragments using a ViewPager widget: we also need to set up an ActionBar, where each Tab contains a different Fragment, and be able to swipe between them with a <b>smooth animated transition.</b><br />
<b><br /></b>
In the following example <b>the ViewPager manages the loading of the Fragments,</b> but the widget has to be synchronized with the ActionBar, in other words:<br />
<br />
<ol>
<li>when you swipe to a different Fragment, the ActionBar must select the correct Tab;</li>
<li>when you select a Tab in the ActionBar the ViewPager must select the correct Fragment.</li>
</ol>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwAuvSmT-QdynqVt09ly-SG_XIRMmE6AZosmVYHWJHzdQ1tYgQ06o4VM5BBKwjq6nz7G1WGsH4kask32rYbz2o-V5QN7EnzYeJo5FSLCoLZMGcntEcy8VgkRp66KUT7GE4QOIO34JSYf8/s1600/actionscreen3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwAuvSmT-QdynqVt09ly-SG_XIRMmE6AZosmVYHWJHzdQ1tYgQ06o4VM5BBKwjq6nz7G1WGsH4kask32rYbz2o-V5QN7EnzYeJo5FSLCoLZMGcntEcy8VgkRp66KUT7GE4QOIO34JSYf8/s1600/actionscreen3.png" height="320" width="180" /></a></div>
<br />
<h3>
1) XML FILE OF THE MAIN ACTIVITY</h3>
<br />
<span style="font-family: Courier New, Courier, monospace;"><?xml version="1.0" encoding="utf-8"?></span><br />
<span style="font-family: Courier New, Courier, monospace;"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"</span><br />
<span style="font-family: Courier New, Courier, monospace;"> android:layout_width="match_parent"</span><br />
<span style="font-family: Courier New, Courier, monospace;"> android:layout_height="match_parent"</span><br />
<span style="font-family: Courier New, Courier, monospace;"> android:orientation="vertical" ></span><br />
<span style="font-family: Courier New, Courier, monospace;"> </span><br />
<span style="font-family: Courier New, Courier, monospace;"> <android.support.v4.view.ViewPager</span><br />
<span style="font-family: Courier New, Courier, monospace;"> android:id="@+id/pager"</span><br />
<span style="font-family: Courier New, Courier, monospace;"> android:layout_width="match_parent"</span><br />
<span style="font-family: Courier New, Courier, monospace;"> android:layout_height="match_parent" /></span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"></LinearLayout></span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: inherit;">As you can see you have to place the ViewPager widget (here named "pager"), which is provided by the <b>android.support.v4 library</b>, in your layout. We set layout_width and layout_height attributes both to "match_parent" in order to make sure that the ViewPager covers the entire display.</span><br />
<br />
<h3>
<span style="font-family: inherit;">2) MAIN ACTIVITY AND FRAGMENTS: IMPORTS</span></h3>
<span style="font-family: inherit;">To be able to use the ViewPager widget you have to use the classes provided by the <b>support library</b>, not the standard library:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">import android.support.v4.app.Fragment;</span><br />
<span style="font-family: Courier New, Courier, monospace;">import android.support.v4.app.FragmentManager;</span><br />
<span style="font-family: Courier New, Courier, monospace;">import android.support.v4.app.FragmentActivity;</span><br />
<span style="font-family: Courier New, Courier, monospace;">import android.support.v4.app.FragmentPagerAdapter;</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace;">import android.support.v4.view.ViewPager;</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: inherit;">In addition to that your main Activity <b>must extend FragmentActivity</b>, not the standard Activity class:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">public class MainActivity extends FragmentActivity {</span><br />
<span style="font-family: Courier New, Courier, monospace;">...</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Make sure to import the Fragment class <b><u>provided by the support library</u></b> also in the classes of each Fragment displayed by the ActionBar through our ViewPager:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">import android.support.v4.app.Fragment;</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">...</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">public class FragmentOne extends Fragment {</span><br />
<span style="font-family: Courier New, Courier, monospace;">...</span><br />
<span style="font-family: Courier New, Courier, monospace;">//the code of the Fragments is omitted for brevity</span><br />
<span style="font-family: Courier New, Courier, monospace;">...</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<span style="font-family: inherit;"><br /></span>
<br />
<h3>
<span style="font-family: inherit;">3) ONCREATE METHOD OF THE MAIN ACTIVITY</span></h3>
<span style="font-family: inherit;">In the onCreate method of the main Activity we have to <b>create the Fragments</b> used to display our data, the <b>ActionBar </b>and setup the <b>ViewPager widget</b> to be able to swipe between different Fragments.</span><br />
<span style="font-family: inherit;">Here is the code:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">@Override</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">protected void onCreate(Bundle savedInstanceState){</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> super.onCreate(savedInstanceState);</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>setContentView(R.layout.main_activity);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> //first we create the Fragments</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> firstFragment = new FirstFragment();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>secondFragment = new SecondoFragment();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>thirdFragment = new ThirdFragment();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>fourthFragment = new FourthFragment();</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> </span></span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> //now we put the Fragments in an array to use them with the ViewPager</span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>arrFragment = new Fragment[4];</span><br />
<span style="font-size: x-small;"><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>arrFragment[0] = </span><span style="font-family: 'Courier New', Courier, monospace;">firstFragment</span><span style="font-family: Courier New, Courier, monospace;">;</span></span><br />
<span style="font-size: x-small;"><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>arrFragment[1] = </span><span style="font-family: 'Courier New', Courier, monospace;">secondFragment</span><span style="font-family: Courier New, Courier, monospace;">;</span></span><br />
<span style="font-size: x-small;"><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>arrFragment[2] = </span><span style="font-family: 'Courier New', Courier, monospace;">thirdFragment</span><span style="font-family: Courier New, Courier, monospace;">;</span></span><br />
<span style="font-size: x-small;"><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>arrFragment[3] = </span><span style="font-family: 'Courier New', Courier, monospace;">fourthFragment</span><span style="font-family: Courier New, Courier, monospace;">;</span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> //now we create an adapter between our Fragments and the ViewPager</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> //for this purpose we use and instance of our class MyAdapter, which is </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> //explained later</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>myFragmentPagerAdapter = new MyAdapter(getSupportFragmentManager());</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>myViewPager = (ViewPager) findViewById(R.id.pager);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> //we load 3 pages in memory on both sides of the current page</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> //p</span><span style="background-color: #f9f9f9; color: #222222; font-size: 14px; line-height: 19px;"><span style="font-family: Courier New, Courier, monospace;">ages beyond this limit are recreated from the adapter when needed</span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>myViewPager.setOffscreenPageLimit(3); </span><br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>myViewPager.setAdapter(myFragmentPagerAdapter);</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> </span></span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> //here we set up our ActionBar </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>setupTabs();</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>myViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> @Override</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>public void onPageSelected(int position) {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>getActionBar().setSelectedNavigationItem(position);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>});</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: inherit;">With the method setOnPageChangeListener we <span style="background-color: #f9f9f9; color: #222222; line-height: 19px;">set a listener that will be invoked <b>whenever the page changes </b>or is incrementally scrolled. </span></span><br />
<span style="font-family: inherit;"><span style="background-color: #f9f9f9; color: #222222; line-height: 19px;">In this case we retrieve a reference of our ActionBar and <b>select the Tab</b> at the position specified by the ViewPager. In this example we have 4 tabs (see next paragraph), so let's select the Tab at the specified position.</span></span><br />
<span style="font-family: inherit;"><span style="background-color: #f9f9f9; color: #222222; line-height: 19px;"><br /></span></span>
<br />
<h3>
<span style="font-family: inherit;">4) SETTING UP THE ACTION BAR.</span></h3>
<span style="font-family: inherit;">In our example we not only want to swipe between Fragments using a ViewPager widget: <b>we also need to set up an ActionBar</b>, where each Tab contains a different Fragment.</span><br />
<span style="font-family: inherit;">The method setupTabs(), called from onCreate, creates the ActionBar, the 4 Tabs and sets up a connection between the ActionBar and the ViewPager widget.</span><br />
<span style="font-family: inherit;">Basically <b>we register a listener</b>, called every time a Tab is selected (pressed), which forces the ViewPager to change page (load a different Fragment) with a smooth transition:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">private void setupTabs() {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>final ActionBar actionBar = getActionBar();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>ActionBar.TabListener tabListener = new ActionBar.TabListener() {</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>@Override</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>public void onTabUnselected(Tab tab, FragmentTransaction ft) {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>// TODO Auto-generated method stub</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>@Override</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>public void onTabSelected(Tab tab, FragmentTransaction ft) {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>// TODO Auto-generated method stub</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>myViewPager.setCurrentItem(tab.getPosition());</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>@Override</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>public void onTabReselected(Tab tab, FragmentTransaction ft) {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>// TODO Auto-generated method stub</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> };</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> actionBar.addTab(actionBar.newTab().setText(R.string.tab_one).setTabListener(tabListener));</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>actionBar.addTab(actionBar.newTab().setText(R.string.tab_two).setTabListener(tabListener));</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>actionBar.addTab(actionBar.newTab().setText(R.string.tab_three).setTabListener(tabListener));</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>actionBar.addTab(actionBar.newTab().setText(R.string.tab_four).setTabListener(tabListener));</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<br />
<h3>
<span style="font-family: inherit;">5) ADAPTER</span></h3>
To make all things work we need an Adapter class (<b>inner class of the main Activity class</b>) to link our Fragments with the ViewPager widget:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">public class MyAdapter extends FragmentPagerAdapter {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>private final int PAGE_COUNT = 4;</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>public MyAdapter(FragmentManager fm) {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>super(fm);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>@Override</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>public Fragment getItem(int i) {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>return arrFragment[i];</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>@Override</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>public int getCount() {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>return PAGE_COUNT;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>@Override</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>public CharSequence getPageTitle(int position) {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>switch(position) {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>case TAB_ONE:</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>return getResources().getString(R.string.tab_one);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>case TAB_TWO:</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>return getResources().getString(R.string.tab_two);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>case TAB_THREE:</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return getResources().getString(R.string.tab_three);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>case TAB_FOUR:</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>return getResources().getString(R.string.tab_four);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> default:</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>return null;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: inherit;">where of course:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">//constants</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">private static final int TAB_ONE = 0;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">private static final int TAB_TWO = 1;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">private static final int TAB_THREE = 2;</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">private static final int TAB_FOUR = 3;</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">As you can see from the previous example we have:</span><br />
<br />
<ol>
<li>a <b>ViewPager widget </b>which loads our Fragments through the class MyAdapter defined above;</li>
<li>an <b>ActionBar </b>which forces the ViewPager to load the correct Fragment each time a Tab is selected (pressed);</li>
<li><b>a listener</b> linked to our ViewPager which selects the correct Tab whenever the user swipes to a different Fragment.</li>
</ol>
iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com0tag:blogger.com,1999:blog-4837974211659692060.post-28918488459764822362014-02-09T01:33:00.000-08:002014-02-09T01:33:13.570-08:00"Listening" to preference changesAs you already know in an Android app <b>settings, options and user preferences</b> are generally stored using <i>SharedPreferences </i>objects.<br />
The name of the preference file created by <i>PreferenceManager.getDefaultSharedPreferences()</i> is formed by the <b>package name</b> of your app (com.....) plus the suffix <b>_preferences</b>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlNrYM6D-gqbemCKQwm0TEhDSF8n7h8UWK1mPMMMl87PRyvHVYHazgYFOOpfM4Olgwxuxb8EdUquEXIXURyYZ3v8nqTsZEtnPlOCFIVRzJRB0b1vOMgqUDbANEpNEqHabApMy9_I_h3Uw/s1600/sharedpref.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlNrYM6D-gqbemCKQwm0TEhDSF8n7h8UWK1mPMMMl87PRyvHVYHazgYFOOpfM4Olgwxuxb8EdUquEXIXURyYZ3v8nqTsZEtnPlOCFIVRzJRB0b1vOMgqUDbANEpNEqHabApMy9_I_h3Uw/s1600/sharedpref.jpg" /></a></div>
<br />
What you might not know (at least I didn't know it until I discovered this week while developing my next app) is that <b>Android uses a single instance of the preference file </b>within the same app. This means that if you open <b>the same preference</b> file twice (for example in 2 different Activities) at the same time, every change that you commit <b>using one object</b> (better apply, because the apply() method works asynchronously) <b>will immediately be reflected in the other object</b>.<br />
So, if you change a preference within an Activity you need a method to notify the other components of your app (Activities, Services, etc.), <b>using the same preference file</b>, tha the change has occured.<br />
<br />
To do this you have to implement the <i>SharedPreferences.OnSharedPreferenceChangeListener </i>interface within your Activity, Service, etc.<br />
Basically you have to follow the following steps:<br />
<br />
<b><u>1) implement the SharedPreferences.OnSharedPreferenceChangeListener interface, for example:</u></b><br />
<b><u><br /></u></b>
<span style="font-family: Courier New, Courier, monospace;">public class MyExample extends Activity implements SharedPreferences.OnSharedPreferenceChangeListener {</span><br />
<span style="font-family: Courier New, Courier, monospace;">...</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
<b><u>2) register and unregister the listener in the appropriate methods, like onResume and onPause:</u></b><br />
<br />
<span style="font-family: Courier New, Courier, monospace;">SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);</span><br />
<span style="font-family: Courier New, Courier, monospace;">pref.registerOnSharedPreferenceChangeListener(this);</span><br />
<span style="font-family: Courier New, Courier, monospace;">String currency = pref.getString("currency", "USD");</span><br />
<br />
and (unregister):<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);</span><br />
<span style="font-family: Courier New, Courier, monospace;">pref.unregisterOnSharedPreferenceChangeListener(this);</span><br />
<br />
<b><u>3) override the method onSharedPreferenceChanged in order to listen to preference changes:</u></b><br />
<br />
<span style="font-family: Courier New, Courier, monospace;">@Override</span><br />
<span style="font-family: Courier New, Courier, monospace;">public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> if(key.equals("currency") {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> currency = pref.getString("currency", "USD");</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
Now you know that another component of your app has just changed the value of the currency preference. You may want to perform some actions in response.iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com3tag:blogger.com,1999:blog-4837974211659692060.post-40765825502573966772014-02-05T09:07:00.000-08:002014-02-05T09:10:50.000-08:00Exporting SQLite database into pdf with PDFJET<div style="margin-bottom: 0cm;">
<span lang="en-US">In this tutorial I
will explain how to <b>convert an SQLite database into pdf</b> using a third
party library, PDFJET. You can download the library, as well as the
documentation, from <a href="http://pdfjet.com/" target="_blank">this site</a>. Make sure to download the <b>open
source library</b>, which is free but relatively complete (there is also
a more complete version, which you can use only for evaluation
purposes, but you have to pay for it for developing your apps).</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBbCV8CanWVZHgiNaXqA-8pJKZxz0RgVA4hEYXSQGKEsEvK6pYImolrNg6KIBmWSEhE3xp92uFgzO07YV_N_kP0GXkJKqoccNBTfGOD68mJ8n1Gc4OPtoNhzsDWHyj7HT8OTGPRIFWBZU/s1600/sql-pdf.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBbCV8CanWVZHgiNaXqA-8pJKZxz0RgVA4hEYXSQGKEsEvK6pYImolrNg6KIBmWSEhE3xp92uFgzO07YV_N_kP0GXkJKqoccNBTfGOD68mJ8n1Gc4OPtoNhzsDWHyj7HT8OTGPRIFWBZU/s1600/sql-pdf.png" height="124" width="320" /></a></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<h3>
Why using PDFJET library</h3>
<div lang="en-US" style="margin-bottom: 0cm;">
There are 3 main reasons
for using PDFJET library in my opinion:</div>
<ol>
<li>there is an <b>open
source</b> version of the library (FREE);</li>
<li>it’s
<b>relatively complete </b>(it has all the main features you need to create
a pdf file);</li>
<li><b>it’s light</b> (about
350 kb).</li>
</ol>
<div style="margin-bottom: 0cm;">
<span lang="en-US">
</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">Of course if you
need <b>more advanced features</b> you should better use the pay version of
the library, or other librarries that you prefer.</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US"></span></div>
<h3>
Setting up your project (Eclipse) to
use the library</h3>
<div>
To use PDFJET library in your project (Eclipse) follow these steps:</div>
<div>
<ol>
<li>download the library <a href="http://pdfjet.com/os/download.html" target="_blank">from this page</a> (open source version);</li>
<li>extract the files to a different folder;</li>
<li>in Eclipse create the package <b>com.pdfjet</b> in the <b>src </b>folder;</li>
<li>copy alla java files that you find in the folder <b>open source\PDFjet-Open-Source\com\pdfjet</b> in the package <b>com.pdfjet </b>that you have created;</li>
<li>import the package in your class with <i>import com.pdfjet.</i></li>
</ol>
Now you can use the PDFJET library in your class.</div>
<div>
<br /></div>
<div>
<h3>
Using the library</h3>
<div style="margin-bottom: 0cm;">
<span lang="en-US">If you visit the <a href="http://pdfjet.com/index.html" target="_blank">PDFJET official site</a> you’ll find <b>dozens of examples</b> about how to
use the library and a <b>complete documentation</b> of all the classes
available (the documentation can also be found in the library you
download from the website: look at the folder <b>open source\PDFjet-Open-Source\docs\java\com\pdfjet</b>).</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">In this tutorial I
will only give you a few examples of the instructions you can use to
quickly <b>convert an SQLite database into a pdf file</b>.</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<h4>
Creating the pdf file</h4>
<div lang="en-US" style="margin-bottom: 0cm;">
Let’s suppose we want to
create a pdf file, Budget.pdf, in the <b>external storage directory</b> of
our device. Here is the code:</div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">String
state = Environment.getExternalStorageState();</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">//check
if the external directory is availabe for writing</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">if
(!Environment.MEDIA_MOUNTED.equals(state)) {</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm; text-indent: 1.25cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">return;</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">}</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">else
{</span></span></div>
<div style="margin-bottom: 0cm; text-indent: 1.25cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US">File
exportDir =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
</span></span></span>
</div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">}</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">//if
the external storage directory does not exists, we create it</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">if
(!exportDir.exists()) {</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm; text-indent: 1.25cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">exportDir.mkdirs();</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">}</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">
</span></span>
</div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">File
file;</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">file
= new File(exportDir, "Budget.pdf");</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">//PDF
is a class of the PDFJET library</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">PDF
pdf = new PDF(new FileOutputStream(file));</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">//instructions
to create the pdf file content</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">pdf.flush();</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<h4>
Title</h4>
<div style="margin-bottom: 0cm;">
<span lang="en-US">Now suppose that we
want to create a title and <b>center it on the page</b> (horizontally):</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">//first
we create a page with portrait orientation</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">Page
page = new Page(pdf, Letter.PORTRAIT);</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">//font
of the title</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">Font
f1 = new Font(pdf, CoreFont.HELVETICA_BOLD);</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">f1.setSize(7.0f);</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">//title:
font f1 and color blue</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US">TextLine
title = new TextLine(f1, “TABLE’S TITLE”);</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US">title.setFont(f1);</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US">title.setColor(Color.blue);</span></span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US">//center
the title horizontally on the page</span></span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">title.setPosition(page.getWidth()/2
– title.getWidth()/2, 40f);</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">//draw
the title on the page</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">title.drawOn(page);</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<h4>
<span lang="en-US">Links</span></h4>
<div lang="en-US" style="margin-bottom: 0cm;">
Here is the code to create
a link to our website:</div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">//font
of the link</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">Font
f2 = new Font(pdf, CoreFont.HELVETICA);</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">f2.setSize(7.0f);</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">//text
of the link</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US">TextLine
website = new TextLine(f2, "Visit Website");</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US">website.setColor(Color.blue);</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US">website.setUnderline(true);</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US">website.setURIAction("https://sites.google.com/site/flingsoftware/");</span></span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">//position
of the link</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">website.setPosition(40f,
40f);</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">//draw
the link on the page</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">website.drawOn(page);</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<h4>
Creating a table</h4>
<div lang="en-US" style="margin-bottom: 0cm;">
To convert an SQLite
database into pdf <b>we need of course a table</b>. Here is the code to
create it:</div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">Table
table = new Table();</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">List<List<Cell>>
tableData = new ArrayList<List<Cell>>();</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
As you can see to create a
table we use an ArrayList where each element is represented by
another ArrayList containing <b>Cell </b>objects. <b>Cell </b>is a class of the
PDFJET library used to create a single cell in the table.</div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<h4>
Adding columns’ titles</h4>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US">List<Cell>
columnTitles = new ArrayList<Cell>();</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US">columnTitles.add(new
Cell(f1, “COLUMN 1”);</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US">columnTitles.add(new
Cell(f1, “COLUMN 2”);</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US">columnTitles.add(new
Cell(f1, “COLUMN 3”);</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US">columnTitles.add(new
Cell(f1, “COLUMN 4”);</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US">columnTitles.add(new
Cell(f1, “COLUMN 5”);</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US">columnTitles.add(new
Cell(f1, “COLUMN 6”);</span></span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">//light
gray background and center alignment</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">for(int
i=0; i<6; i++) {</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"></span></span><span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> ((Cell)
columnTitles.get(i)).setBgColor(Color.lightyellow);</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> ((Cell)
columnTitles.get(i)).setTextAlignment(Align.CENTER);</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">}</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">tableData.add(</span></span><span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US">columnTitles</span></span></span><span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">);</span></span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">In this example we
created an <b>ArrayList of Cells</b>, each of which representing the title
of a column, we set the <b>color background</b> and alignment of each Cell,
and finally added the ArrayList to the “ArrayList of ArrayLists”
tableData, our complete table.</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<h4>
Adding database records to the table</h4>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">DateFormat
df = DateFormat.getDateInstance(DateFormat.SHORT,
Locale.getDefault());</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">NumberFormat
nf = NumberFormat.getCurrencyInstance(Locale.getDefault());</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">int i = 1;</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US">while(myCursor.moveToNext())
{</span></span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"> //retrieve
data from cursor </span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: 'Courier New', monospace; font-size: 9pt; text-indent: 1.25cm;"> Long
date = myCursor.getLong(myCursor.getColumnIndex("date"));</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> String
item = myCursor.getString(myCursor.getColumnIndex("item"));</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> Double
amount = myCursor.getDouble(myCursor.getColumnIndex("amount"));</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> String
currency = myCursor.getString(myCursor.getColumnIndex("currency"));</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> Double
convAmount =
myCursor.getDouble(myCursor.getColumnIndex("converted_amount"));</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> String
description =
myCursor.getString(myCursor.getColumnIndex("description"));</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"><br /></span></span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"> </span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> //next
record in the table </span></span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"> List<Cell>
record = new ArrayList<Cell>();</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><br /></span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"> </span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"> //create
Cells and add them to the record</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> Cell
dateCell = new Cell(f2, df.format(new Date(date)));</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> dateCell.setTextAlignment(Align.CENTER);</span></span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"> record.add(dataCell);</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> record.add(new
Cell(f2, item));</span></span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> Cell
amountCell = new Cell(f2, nf.format(amount));</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> amountCell.setTextAlignment(Align.RIGHT);</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> record.add(amountCell);</span></span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> Cell
currencyCell = new Cell(f2, currency);</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> currencyCell.setTextAlignment(Align.CENTER);</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> record.add(currencyCell);</span></span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> Cell
convAmountCell = new Cell(f2, nf.format(convAmount));</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> convAmountCell.setTextAlignment(Align.RIGHT);</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> record.add(convAmountCell);</span></span></span></div>
<div style="margin-bottom: 0cm; text-indent: 0px;">
<span style="font-family: 'Courier New', monospace; font-size: 9pt; text-indent: 1.25cm;"> record.add(new
Cell(f2, description));</span></div>
<div style="margin-bottom: 0cm; text-indent: 0px;">
<span style="font-family: 'Courier New', monospace; font-size: 9pt; text-indent: 1.25cm;"> </span></div>
<div style="margin-bottom: 0cm; text-indent: 0px;">
<span style="font-family: 'Courier New', monospace; font-size: 9pt; text-indent: 1.25cm;"> //add
the record to the table</span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"> tableData.add(record);</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><br /></span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"> //one line gray and one line white...</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 12px;"> if(i%2 == 0) {</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 12px;"><span class="Apple-tab-span" style="white-space: pre;"> </span>dateCell.setBgColor(Color.lightgray);</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 12px;"><span class="Apple-tab-span" style="white-space: pre;"> </span>amountCell.setBgColor(Color.lightgray);</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 12px;"> ...</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 12px;"> }</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-size: 12px;"><span style="font-family: Courier New, monospace;"></span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 12px;"> i++;</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">}</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US">In the previous
example we <b>iterate over the Cursor</b> retrieved from the database and
write each record in the table, field (each represented by a Cell
object of the PDFJET library) after field.</span></div>
<div style="margin-bottom: 0cm;">
<span lang="en-US"><br /></span></div>
<h4>
<span lang="en-US">Printing the table on the page</span></h4>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">//populate
the table with our tableData ArrayList</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">table.setData(tableData,
Table.DATA_HAS_1_HEADER_ROWS);</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">//autoadjust
column widths to fit the content</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">table.autoAdjustColumnWidths();</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">//let’s
suppose we want to manually set the width of column 0</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">table.setColumnWidth(0,
40.0f);</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">//each
cell can contain more rows</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">table.wrapAroundCellText();</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">table.setPosition(page.getWidth()/2
– table.getWidth()/2, 40f);</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">table.drawOn(page);</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<h4>
Printing the table on more than one
page</h4>
<div lang="en-US" style="margin-bottom: 0cm;">
If your table is
particularly long and you need more than one page to print it, you
can use the following loop:</div>
<div lang="en-US" style="margin-bottom: 0cm;">
<br /></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">int
numOfPages = table.getNumberOfPages(page);</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US">int
currentPage = 0;</span></span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">while
(true) {</span></span></div>
<div style="margin-bottom: 0cm; text-indent: 1.25cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">point
= table.drawOn(page);</span></span></div>
<div style="margin-bottom: 0cm; text-indent: 1.25cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><br /></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"> //print
page number</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"></span></span><span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> TextLine
numPag = new TextLine(f2, ++currentPage + “ of “ + numOfPages);</span></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"></span></span></span><span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"> numPag.setPosition(largPag
- 30.0f - numPag.getWidth(), page.getHeight() - 20.0f);</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"> numPag.drawOn(page);</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">
</span></span>
</div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><br /></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"> //scrivo
il nome tabella a fondo pagina</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"> TextLine
tabella = new TextLine(f2, mioContext.getString(R.string.menu_esporta_tabellaPdf_fondoPaginaSpese));</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"></span></span><span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> tabella.setPosition(30.0f,
page.getHeight() - 20.0f);</span></span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"> tabella.drawOn(page);</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">
</span></span>
</div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"> if
(!table.hasMoreData()) {</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> //
Allow the table to be drawn again later:</span></span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"> table.resetRenderedPagesCount();</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"> break;</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"><span lang="en-US"> }</span></span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;"> page
= new Page(pdf, Letter.PORTRAIT);</span></span></div>
<div lang="en-US" style="margin-bottom: 0cm;">
<span style="font-family: Courier New, monospace;"><span style="font-size: 9pt;">}</span></span></div>
</div>
iClaudehttp://www.blogger.com/profile/17029011590096990842noreply@blogger.com11