{"id":65,"date":"2009-05-06T12:20:05","date_gmt":"2009-05-06T16:20:05","guid":{"rendered":"http:\/\/www.bitquill.net\/blog\/?p=65"},"modified":"2016-05-12T14:46:46","modified_gmt":"2016-05-12T19:46:46","slug":"hello-android","status":"publish","type":"post","link":"http:\/\/bitquill.net\/blog\/hello-android\/","title":{"rendered":"Hello Android"},"content":{"rendered":"<p>After blabbering about Android, I decided to get my hands a little dirty and actually write some code. For various reasons, I won&#8217;t describe the app (it was a &#8220;weekend hack&#8221; anyway), but hopefully my first impressions will be clear even without a specific context.  <!--more--><\/p>\n<p>Overall, the Android APIs are quite impressive, even though some edges are still rough. \u00c2\u00a0It was reasonably easy to get up to speed, even though my prior experience on mobile application frameworks was zero. \u00c2\u00a0The toughest part was getting used to the heavily event-based programming style, as well as the idea that your code may be interrupted, killed and restarted at any time.<\/p>\n<p><strong>Activity lifecycle.<\/strong> Although Android supports multitasking and concurrency, on a mobile device with limited memory and no swap it&#8217;s likely that the O\/S will have to kill some or all of your tasks to reclaim resources needed by higher-priority, user-visible processes (e.g., an incoming phone call). \u00c2\u00a0If you have non-persistent or external state, such as open database connections or separate threads that fetch data in the background, things may get a little tricky. Although Android has auxiliary features such as managed cursors and dialogs, you still need to know they exist and use them properly.<\/p>\n<p>However, even things like <a title=\"Configuration Changes - android.app.Activity Javadoc\" href=\"http:\/\/code.google.com\/android\/reference\/android\/app\/Activity.html#ConfigurationChanges\">screen orientation changes<\/a>\u00c2\u00a0are handled by terminating and restarting any affected activities. At first, while spending a couple of hours to figure out why my app was crashing when I opened the keyboard, I bitched about this. Apparently, I wasn&#8217;t the only one who was confused. To my surprise, I found\u00c2\u00a0that many Android Market apps crash when the screen is rotated. \u00c2\u00a0Some Market apps even come with grave-sounding warnings that, e.g., &#8220;the life counter [sic] resets on screen orientation change =\/ Will fix for new version.&#8221; Luckily, I also found numerous good posts about orientation changes, such as <a title=\"Rotational Forces, Part Two - Mark Murphy on AndroidGuys blog\" href=\"http:\/\/androidguys.com\/?p=2642\">this<\/a> or <a title=\"Rotational Forces, Part Three - Mark Murphy on AndroidGuys blog\" href=\"http:\/\/androidguys.com\/?p=2723\">this<\/a>\u00c2\u00a0(the <a title=\"Mark Murphy on AndroidGuys\" href=\"http:\/\/androidguys.com\/?author=20\">series by Mark Murphy<\/a> are pretty good, by the way), as well as a\u00c2\u00a0<a title=\"Faster screen orientation changes - Android Developers Blog\" href=\"http:\/\/android-developers.blogspot.com\/2009\/02\/faster-screen-orientation-change.html\">post on the official blog<\/a>.<\/p>\n<p>In retrospect, handling orientation changes in this way is a good thing: it forces app developers to be prepared. After I fixed my code to handle orientation changes gracefully, I found that I was also ready to properly handle other sources of interruption: when an incoming call came as I was testing my app, everything worked out beautifully.<\/p>\n<p>Now, whenever I download an app, I perform the following test: I flip the keyboard open when the app executes a background operation, even if I don&#8217;t need to type anything. \u00c2\u00a0If the app crashes or gets into an inconsistent state (something that happens surprisingly often), that&#8217;s a strong indication that the code is not very robust.<\/p>\n<p><strong>Event handling.<\/strong> For APIs that are so heavily event-based, one of my gripes was that some (but not all) event handlers are based on inheritance rather than\u00c2\u00a0<a title=\"Delegation pattern - Wikipedia\" href=\"http:\/\/en.wikipedia.org\/wiki\/Delegation_pattern\">delegation<\/a>.\u00c2\u00a0These design choices are probably due to\u00c2\u00a0<a title=\"Prefer virtual over interface - Designing for Performance - Android documentation\" href=\"http:\/\/developer.android.com\/guide\/practices\/design\/performance.html#prefer_virtual\">performance reasons<\/a>\u00c2\u00a0that may be specific to Dalvik, the Android VM which is motivated partly for\u00c2\u00a0<a title=\"Dalvik: how Google routed around Sun\u00e2\u20ac\u2122s IP-based licensing restrictions on Java ME - Stefano's Linotype\" href=\"http:\/\/www.betaversion.org\/~stefano\/linotype\/news\/110\/\">non-technical reasons<\/a>.\u00c2\u00a0<\/p>\n<p>However, inheritance sometimes complicates things. For example, Android supports managed cursors and dialogs via methods in the base Activity class. On more than one occasion I found that managed threads would also be nice. \u00c2\u00a0Implementing this requires hooking into the activity lifecycle events (and has, on occasion, been <a title=\"A Simple [sic] Android App and a Threading Bug - OCIWeb\" href=\"http:\/\/www.ociweb.com\/jnb\/jnbJan2009.html\">over-engineered to death<\/a>). Because there are several Activity subclasses (e.g., ListActivity, PreferenceActivity, etc), there is no simple way to extend them all. If lifecycle events were handled via delegates, it would be possible to implement a background UI thread manager as, say, an activity\u00c2\u00a0<a title=\"Decorator pattern - Wikipedia\" href=\"http:\/\/en.wikipedia.org\/wiki\/Decorator_pattern\">decorator<\/a>\u00c2\u00a0that can be added to any activity instance. \u00c2\u00a0<\/p>\n<p>The delegation-based event model was introduced in Java 1.1 precisely\u00c2\u00a0<a title=\"Java AWT: Delegation Event Model - Sun.com\" href=\"http:\/\/java.sun.com\/j2se\/1.3\/docs\/guide\/awt\/designspec\/events.html\">to address such shortcomings<\/a>\u00c2\u00a0of the inheritance-based model. But, being pragmatic about performance on current mobile devices, I should probably not complain too much. \u00c2\u00a0Still, some API design choices seem a bit arbitrary, perhaps even Microsoft-esque: why would performance be an issue with lifecycle events (which are presumably rare, but handlers use inheritance) but not with click events (which are presumably more frequent, but handlers use delegation)?<\/p>\n<p><strong>Data sync and caching.<\/strong> Another gripe was the lack of <a title=\"android.content.AbstractSyncableContentProvider - Git\" href=\"http:\/\/android.git.kernel.org\/?p=platform\/frameworks\/base.git;a=blob;f=core\/java\/android\/content\/AbstractSyncableContentProvider.java\">syncable content providers<\/a>, something I&#8217;ve mentioned before. Also, content providers aren&#8217;t really appropriate for network-hosted data. The requirement that content providers use an integer primary key (row ID) is reasonable for local databases and simplifies the APIs, but requires some book-keeping when that&#8217;s not the &#8220;natural&#8221; primary key.<\/p>\n<p>Ideally, I&#8217;d like to see some support for caching remote data on the SD card (which would require gracefully handling card removal, and transparently fetching data either from the cache or the network). Although the core APIs provide all that is necessary to implement this from scratch, it was getting too complicated for my simple &#8220;weekend hack&#8221; app, so I decided to drop it.<\/p>\n<p>I hope that, in the near future, porting web apps to mobile devices will become easier with the support for\u00c2\u00a0<a title=\"Offline web applications - HTML5 (Working Draft) - W3C\" href=\"http:\/\/www.w3.org\/TR\/html5\/offline.html\">offline applications<\/a>\u00c2\u00a0and\u00c2\u00a0<a title=\"Structured client-side storage - HTML5 (Working draft) - W3C\" href=\"http:\/\/www.w3.org\/TR\/html5\/structured.html\">client-side storage<\/a>\u00c2\u00a0in HTML5, as well the proposed\u00c2\u00a0<a title=\"Geolocation API specification (Editor's draft) - W3C\" href=\"http:\/\/dev.w3.org\/geo\/api\/spec-source.html\">geolocation APIs<\/a>\u00c2\u00a0(all of which are already\u00c2\u00a0<a title=\"Gears as a bleeding-edge HTML 5 implementation\" href=\"http:\/\/almaer.com\/blog\/gears-as-a-bleeding-edge-html-5-implementation\">part of Google Gears<\/a>). An application manifest might include &#8220;web activities&#8221;, translating intents into HTTP POST requests, while granting device access permissions to those activities (e.g., see promising hacks such as\u00c2\u00a0<a title=\"OilCan: GreaseMonkey on steroids for Android\" href=\"http:\/\/www.jsharkey.org\/blog\/2008\/12\/15\/oilcan-greasemonkey-on-steroids-for-android\/\">OilCan<\/a>). Porting might then involve little more than writing a new stylesheet. Perhaps that&#8217;s where Palm is going with its\u00c2\u00a0<a title=\"Palm WebOS Developer Site (retrieved 2\/24)\" href=\"http:\/\/developer.palm.com\/\">WebOS<\/a>\u00c2\u00a0which apparently supports both &#8220;native application&#8221; and &#8220;web application&#8221; models, but information is rather thin\u00c2\u00a0at the moment.<\/p>\n<p><strong>Epilogue.<\/strong>\u00c2\u00a0My first Android app was an interesting learning experience, not only from a technical standpoint (perhaps more on this in another post).\u00c2\u00a0I also found that Android is quite stable. I sometimes used my phone for live debugging, forcefully killing threads and processes through ADB. \u00c2\u00a0Let me put it this way: if it wasn&#8217;t for the RC33 OTA update, my phone would now have an uptime of a few months. For a piece of software that barely existed a year ago, this is impressive.<\/p>\n<p>There is plenty of documentation available, but at times it can take some searching to find the necessary information. \u00c2\u00a0However, since Android is open-source, it&#8217;s always possible to consult the source code itself (which is fairly well-written and documented).<\/p>\n<p><em><strong>Note:<\/strong>\u00c2\u00a0This post was mostly written sometime around February. Since then I had no time to try SDK v1.5, but I believe most points above are still relevant.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>After blabbering about Android, I decided to get my hands a little dirty and actually write some code. For various reasons, I won&#8217;t describe the app (it was a &#8220;weekend hack&#8221; anyway), but hopefully my first impressions will be clear even without a specific context.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[45],"tags":[59,7],"class_list":["post-65","post","type-post","status-publish","format-standard","hentry","category-scitech","tag-android","tag-development"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p7x9xm-13","jetpack-related-posts":[],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"http:\/\/bitquill.net\/blog\/wp-json\/wp\/v2\/posts\/65","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/bitquill.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/bitquill.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/bitquill.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/bitquill.net\/blog\/wp-json\/wp\/v2\/comments?post=65"}],"version-history":[{"count":11,"href":"http:\/\/bitquill.net\/blog\/wp-json\/wp\/v2\/posts\/65\/revisions"}],"predecessor-version":[{"id":712,"href":"http:\/\/bitquill.net\/blog\/wp-json\/wp\/v2\/posts\/65\/revisions\/712"}],"wp:attachment":[{"href":"http:\/\/bitquill.net\/blog\/wp-json\/wp\/v2\/media?parent=65"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/bitquill.net\/blog\/wp-json\/wp\/v2\/categories?post=65"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/bitquill.net\/blog\/wp-json\/wp\/v2\/tags?post=65"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}