Skip to content

Instantly share code, notes, and snippets.

@dlew
Created March 14, 2014 23:38
Show Gist options
  • Save dlew/b3bf5400f4e50e5b901b to your computer and use it in GitHub Desktop.
Save dlew/b3bf5400f4e50e5b901b to your computer and use it in GitHub Desktop.
{
"meta": {
"exported_on": 1394839821454,
"version": "000"
},
"data": {
"posts": [
{
"id": 0,
"title": "New Site, New Blog",
"slug": "new_site_new_blog",
"markdown": "I've decided that I want to try something else for blogging, so I've gotten my own domain name and switched to Ghost.  My new blog will be found at [http://blog.danlew.net/](http://blog.danlew.net/).\n\nThe posts here will remain up until the end of time, but all new content going forwards will be found over there.",
"html": "I've decided that I want to try something else for blogging, so I've gotten my own domain name and switched to Ghost. &nbsp;My new blog will be found at&nbsp;<a href=\"http://blog.danlew.net/\">http://blog.danlew.net/</a>.<br /><br />The posts here will remain up until the end of time, but all new content going forwards will be found over there.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1389366000000,
"created_by": 1,
"updated_at": 1389366002099,
"updated_by": 1,
"published_at": 1389366000000,
"published_by": 1
},
{
"id": 1,
"title": "Testing on Android (Part 2): Functional Tests",
"slug": "testing_on_android_part_2_functional_tests",
"markdown": "Here's part two of my series on Android testing. &nbsp;This time, I'm going to wade into the huge number of functional testing frameworks that exist. &nbsp;The differentiation I made between unit testing and functional testing is that the functional tests operate the actual device (as in, you could watch it running through a test).\n\n* **Part 1:**&nbsp;[Unit Tests](http://goo.gl/m6bXcJ)\n* **Part 2:**&nbsp;[Functional Tests](http://goo.gl/KXHZMg)\n* **Part 3:**&nbsp;[Other Testing Tools](http://goo.gl/X49RoP)\n* **Part 4:**&nbsp;[Testing Services](http://goo.gl/60Xnf7)\n* **Spreadsheet:**&nbsp;[Android Testing](http://goo.gl/XSUxoJ)<div>**<span style=\"font-size: large;\">So Many Frameworks</span>**</div><div>\n</div><div>As you can see in [my spreadsheet](http://goo.gl/XSUxoJ), there are a ton of functional testing frameworks out there. &nbsp;I don't have any inclination to test all of them. &nbsp;Here's what I haven't tried myself, for various reasons:</div><div>\n\n* **Non-Java** - if my code and unit tests are going to be in Java, I might as well make my functional tests in Java as well.\n* **Recorder-based testing**&nbsp;- While this might be good for a less technical tester, I'd prefer exact control over my tests.\n* **Superseded or discontinued** - Some frameworks are old and have been surpassed by more modern frameworks. &nbsp;Others have been discontinued.<div>This leaves just a few frameworks to investigate.\n\n<div>**<span style=\"font-size: large;\">Robotium</span>**</div><div>\nI was already somewhat familiar with [Robotium](https://code.google.com/p/robotium/). &nbsp;It runs off of the official Android testing framework, but adds the capabilities needed to actually run through an entire app.\n\nIt's been around for years, and so it's fairly stable. &nbsp;It's also straightforward; you use the Solo class to run through your app, one step at a time. &nbsp;It requires compiling along with the app's source, which could be a negative for some. &nbsp;Overall, it's a solid functional testing solution.</div>\n<div>**<span style=\"font-size: large;\">uiautomator</span>**</div><div>\n[UiAutomator](http://developer.android.com/tools/help/uiautomator/) is a more recent offering from Google. &nbsp;I found it to be lacking and difficult to use.\n\nFirst, it depends on more recent APIs, so it can only be used on Jelly Bean and above - you can't use it to test backwards compatibility. &nbsp;Second, the deployment is more complex than other frameworks. &nbsp;There's no simple script to put the code you wrote onto a device - you have to write a script yourself because it involves a few dynamic commands (depending on how you named your classes).\n\nThird, it just feels like it's not quite there. &nbsp;For example, simply launching my app from the test was a struggle. &nbsp;The suggested start is to begin on your home page then page towards your app to launch it, except the code for doing so is broken. &nbsp;Instead I had to use some hacky code which used \"am start\" to launch my Activity.\n\nIt does have a few unique advantages. &nbsp;First, it can be written entirely black-box; you don't need access to the source code. &nbsp;You use uiautomatorviewer to examine how an app is written and write tests based on that. &nbsp;Second, it runs on the entire OS, so you can really test cross-app interaction. &nbsp;If you need either of these, then I might check it out; but for my purposes this is a non-starter.</div></div></div><div>\n</div><div>**Espresso**</div><div>\n[Espresso](https://code.google.com/p/android-test-kit/) is the latest toolkit from Google, and it's so awesome I have to wonder if the reason uiautomator is having issues is because everyone was actually working on Espresso.\n\nIt's got a different paradigm from other testing frameworks. &nbsp;It starts with onView() or onData() with Hamcrest matchers to find your View/AdapterView. &nbsp;Once found, you can then either perform an action or check some assertions.\n\nThe reason for the onView()/onData() setup is that Espresso examines the UI thread to know when processing is done. &nbsp;A common problem with functional testing on Android is not knowing when a View will show up, so you end up with a lot of sleeps in your tests. &nbsp;With Espresso you skip all of that, so it's blazing fast!\n\nIt's not all sunshine and roses. &nbsp;It doesn't handle animations well (in fact, the expected setup is to turn all your animations off with dev opts). &nbsp;I also found initial understanding harder, having to learn how to use Hamcrest to match my Views. &nbsp;But once I got past those, the testing was so fast and stable that it blew me away.</div><div>\n<div><span style=\"font-size: large;\">**Appium**</span></div><div>\nI had started to try out Appium, as it seemed to present another way of functional testing, but ultimately gave up.\n\nMaybe it was because I tried uiautomator, robotium, and Espresso before getting to Appium, but the setup was just overwhelming. &nbsp;There was no \"hello, world\" sample I found that could take me from zero to testing. &nbsp;There was a lot of documentation I found that listed out about five things I had to install on my machine (and have play together nicely) before I could start.\n\nIf my entire job was automation testing, or I knew selenium very well already, then I might consider Appium because then the time investment might pay off. &nbsp;But as an Android developer who wants to dabble with testing on the side, I don't want to have to deal with getting this environment setup (not to mention the pain I'd be putting others through to replicate my work).</div></div><div>\n</div><div>**<span style=\"font-size: large;\">Conclusion</span>**</div><div>\n</div><div>I would take my thoughts with a grain of salt; I haven't used any of these long enough to really get into the nitty gritty. &nbsp;That said, I think my future functional tests will be written in Espresso; its design paradigm makes for focused, solid testing. &nbsp;Plus, its basis on the Looper to determine when to continue makes it lightyears faster than the other frameworks could hope to be. &nbsp;I hope it continues to be supported by Google because I like it.</div>",
"html": "Here's part two of my series on Android testing. &nbsp;This time, I'm going to wade into the huge number of functional testing frameworks that exist. &nbsp;The differentiation I made between unit testing and functional testing is that the functional tests operate the actual device (as in, you could watch it running through a test).<br /><ul><li><b>Part 1:</b>&nbsp;<a href=\"http://goo.gl/m6bXcJ\">Unit Tests</a></li><li><b>Part 2:</b>&nbsp;<a href=\"http://goo.gl/KXHZMg\">Functional Tests</a></li><li><b>Part 3:</b>&nbsp;<a href=\"http://goo.gl/X49RoP\">Other Testing Tools</a></li><li><b>Part 4:</b>&nbsp;<a href=\"http://goo.gl/60Xnf7\">Testing Services</a></li><li><b>Spreadsheet:</b>&nbsp;<a href=\"http://goo.gl/XSUxoJ\">Android Testing</a></li></ul><div><b><span style=\"font-size: large;\">So Many Frameworks</span></b></div><div><br /></div><div>As you can see in <a href=\"http://goo.gl/XSUxoJ\">my spreadsheet</a>, there are a ton of functional testing frameworks out there. &nbsp;I don't have any inclination to test all of them. &nbsp;Here's what I haven't tried myself, for various reasons:</div><div><ul><li><b>Non-Java</b> - if my code and unit tests are going to be in Java, I might as well make my functional tests in Java as well.</li><li><b>Recorder-based testing</b>&nbsp;- While this might be good for a less technical tester, I'd prefer exact control over my tests.</li><li><b>Superseded or discontinued</b> - Some frameworks are old and have been surpassed by more modern frameworks. &nbsp;Others have been discontinued.</li></ul><div>This leaves just a few frameworks to investigate.<br /><br /><div><b><span style=\"font-size: large;\">Robotium</span></b></div><div><br />I was already somewhat familiar with <a href=\"https://code.google.com/p/robotium/\">Robotium</a>. &nbsp;It runs off of the official Android testing framework, but adds the capabilities needed to actually run through an entire app.<br /><br />It's been around for years, and so it's fairly stable. &nbsp;It's also straightforward; you use the Solo class to run through your app, one step at a time. &nbsp;It requires compiling along with the app's source, which could be a negative for some. &nbsp;Overall, it's a solid functional testing solution.</div><br /><div><b><span style=\"font-size: large;\">uiautomator</span></b></div><div><br /><a href=\"http://developer.android.com/tools/help/uiautomator/\">UiAutomator</a> is a more recent offering from Google. &nbsp;I found it to be lacking and difficult to use.<br /><br />First, it depends on more recent APIs, so it can only be used on Jelly Bean and above - you can't use it to test backwards compatibility. &nbsp;Second, the deployment is more complex than other frameworks. &nbsp;There's no simple script to put the code you wrote onto a device - you have to write a script yourself because it involves a few dynamic commands (depending on how you named your classes).<br /><br />Third, it just feels like it's not quite there. &nbsp;For example, simply launching my app from the test was a struggle. &nbsp;The suggested start is to begin on your home page then page towards your app to launch it, except the code for doing so is broken. &nbsp;Instead I had to use some hacky code which used \"am start\" to launch my Activity.<br /><br />It does have a few unique advantages. &nbsp;First, it can be written entirely black-box; you don't need access to the source code. &nbsp;You use uiautomatorviewer to examine how an app is written and write tests based on that. &nbsp;Second, it runs on the entire OS, so you can really test cross-app interaction. &nbsp;If you need either of these, then I might check it out; but for my purposes this is a non-starter.</div></div></div><div><br /></div><div><b style=\"font-size: x-large;\">Espresso</b></div><div><br /><a href=\"https://code.google.com/p/android-test-kit/\">Espresso</a> is the latest toolkit from Google, and it's so awesome I have to wonder if the reason uiautomator is having issues is because everyone was actually working on Espresso.<br /><br />It's got a different paradigm from other testing frameworks. &nbsp;It starts with onView() or onData() with Hamcrest matchers to find your View/AdapterView. &nbsp;Once found, you can then either perform an action or check some assertions.<br /><br />The reason for the onView()/onData() setup is that Espresso examines the UI thread to know when processing is done. &nbsp;A common problem with functional testing on Android is not knowing when a View will show up, so you end up with a lot of sleeps in your tests. &nbsp;With Espresso you skip all of that, so it's blazing fast!<br /><br />It's not all sunshine and roses. &nbsp;It doesn't handle animations well (in fact, the expected setup is to turn all your animations off with dev opts). &nbsp;I also found initial understanding harder, having to learn how to use Hamcrest to match my Views. &nbsp;But once I got past those, the testing was so fast and stable that it blew me away.</div><div><br /><div><span style=\"font-size: large;\"><b>Appium</b></span></div><div><br />I had started to try out Appium, as it seemed to present another way of functional testing, but ultimately gave up.<br /><br />Maybe it was because I tried uiautomator, robotium, and Espresso before getting to Appium, but the setup was just overwhelming. &nbsp;There was no \"hello, world\" sample I found that could take me from zero to testing. &nbsp;There was a lot of documentation I found that listed out about five things I had to install on my machine (and have play together nicely) before I could start.<br /><br />If my entire job was automation testing, or I knew selenium very well already, then I might consider Appium because then the time investment might pay off. &nbsp;But as an Android developer who wants to dabble with testing on the side, I don't want to have to deal with getting this environment setup (not to mention the pain I'd be putting others through to replicate my work).</div></div><div><br /></div><div><b><span style=\"font-size: large;\">Conclusion</span></b></div><div><br /></div><div>I would take my thoughts with a grain of salt; I haven't used any of these long enough to really get into the nitty gritty. &nbsp;That said, I think my future functional tests will be written in Espresso; its design paradigm makes for focused, solid testing. &nbsp;Plus, its basis on the Looper to determine when to continue makes it lightyears faster than the other frameworks could hope to be. &nbsp;I hope it continues to be supported by Google because I like it.</div>",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1389018600000,
"created_by": 1,
"updated_at": 1392042340890,
"updated_by": 1,
"published_at": 1389018600000,
"published_by": 1
},
{
"id": 2,
"title": "Who Goes First App",
"slug": "who_goes_first_app",
"markdown": "Continuing with my series of [boardgame-related side projects](http://daniel-codes.blogspot.com/2013/02/resistanceavalon-app.html), I've written a small holo-themed app for determining who goes first called (unsurprisingly) [Who Goes First](https://play.google.com/store/apps/details?id=com.idunnolol.whogoesfirst). &nbsp;As with most side projects it's also [open source](https://github.com/dlew/android-whogoesfirst). &nbsp;I released this app a while ago but thought I'd mention it here.\n\nThere wasn't much complex about it; mostly I was pleased with how easy it is to make a good-looking app with holo theming (even if you're not very talented in the design department).\n\nThe only interesting thing I learned relate to the arrow pointing towards who goes first. &nbsp;If you need more than six arrows, then it'll just show \"X#\" inside of the arrow instead. &nbsp;This required scaling the text size depending on how long the text was. &nbsp;I ended up using a [Region](http://developer.android.com/reference/android/graphics/Region.html)&nbsp;for the arrow (defined via the [Path](http://developer.android.com/reference/android/graphics/Path.html) used to construct the arrow) and another Region for the text and test if they overlapped; if they did, shrink text size until they don't. &nbsp;You can check out what I'm talking about in [the actual ArrowView](https://github.com/dlew/android-whogoesfirst/blob/master/project/src/com/idunnolol/whogoesfirst/ArrowView.java).\n\nThe one problem I've run into is when there are multiple people at the table with this app. &nbsp;The app does not use networking to sync their random seeds, so you can end up with multiple people going first. &nbsp;I guess my next project will have to be a \"Who Runs Who Goes First First\" app. &nbsp;:)",
"html": "Continuing with my series of <a href=\"http://daniel-codes.blogspot.com/2013/02/resistanceavalon-app.html\">boardgame-related side projects</a>, I've written a small holo-themed app for determining who goes first called (unsurprisingly) <a href=\"https://play.google.com/store/apps/details?id=com.idunnolol.whogoesfirst\">Who Goes First</a>. &nbsp;As with most side projects it's also <a href=\"https://github.com/dlew/android-whogoesfirst\">open source</a>. &nbsp;I released this app a while ago but thought I'd mention it here.<br /><br />There wasn't much complex about it; mostly I was pleased with how easy it is to make a good-looking app with holo theming (even if you're not very talented in the design department).<br /><br />The only interesting thing I learned relate to the arrow pointing towards who goes first. &nbsp;If you need more than six arrows, then it'll just show \"X#\" inside of the arrow instead. &nbsp;This required scaling the text size depending on how long the text was. &nbsp;I ended up using a <a href=\"http://developer.android.com/reference/android/graphics/Region.html\">Region</a>&nbsp;for the arrow (defined via the <a href=\"http://developer.android.com/reference/android/graphics/Path.html\">Path</a> used to construct the arrow) and another Region for the text and test if they overlapped; if they did, shrink text size until they don't. &nbsp;You can check out what I'm talking about in <a href=\"https://github.com/dlew/android-whogoesfirst/blob/master/project/src/com/idunnolol/whogoesfirst/ArrowView.java\">the actual ArrowView</a>.<br /><br />The one problem I've run into is when there are multiple people at the table with this app. &nbsp;The app does not use networking to sync their random seeds, so you can end up with multiple people going first. &nbsp;I guess my next project will have to be a \"Who Runs Who Goes First First\" app. &nbsp;:)",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1387378800000,
"created_by": 1,
"updated_at": 1387378806783,
"updated_by": 1,
"published_at": 1387378800000,
"published_by": 1
},
{
"id": 3,
"title": "Testing on Android (Part 1): Unit Tests",
"slug": "testing_on_android_part_1_unit_tests",
"markdown": "I've recently been doing research on Android testing. &nbsp;I'm quite new to this business; automated testing has (for the longest time) felt unnecessary. &nbsp;But I've been slowly convinced that the benefits outweigh the time costs - as long as you do it in an efficient manner. &nbsp;To that end, I set out to evaluate the many, many Android testing frameworks to see which ones seemed to save the most time.\n\nI began by summarizing all the tools/services I could find in&nbsp;[a spreadsheet](http://goo.gl/XSUxoJ)&nbsp;(let me know if I'm missing anything). &nbsp;Beyond that, I am going to do a series of posts going into more detail about different parts of Android testing:\n\n* **Part 1:&nbsp;**[Unit Tests](http://goo.gl/m6bXcJ)\n* **Part 2:** [Functional Tests](http://goo.gl/KXHZMg)\n* **Part 3:** [Other Testing Tools](http://goo.gl/X49RoP)\n* **Part 4:** [Testing Services](http://goo.gl/60Xnf7)\n* **Spreadsheet:**&nbsp;[Android Testing](http://goo.gl/XSUxoJ)Let's start with unit testing.\n\n**<span style=\"font-size: large;\">Unit Tests</span>**\n\nThere's no reason you can't use normal JUnit 4 testing for Android applications... as long as you stay away from anything Android.\n\nNormally you compile against the SDK's android.jar, which contains nothing but stubbed methods that throw exceptions when run. &nbsp;When you actually upload your APK to a device, it uses the device's implementations of all those stubs. &nbsp;As a result, when running normal unit tests in your IDE, you get no access to those framework implementations (instead receiving mountains of exceptions). &nbsp;This is not a big deal if you're testing some simple functionality that doesn't touch Android itself.\n\n**Pros:**\n\n* Fast and easy**Cons:**\n\n* Cannot use any Android framework classes**<span style=\"font-size: large;\">The Android Testing Framework</span>**\n\n[The Android testing framework](http://developer.android.com/tools/testing/testing_android.html) is the official method of unit testing on Android. &nbsp;It loads your application onto a device, then runs JUnit-based test suites. &nbsp;Since it runs on the actual OS you can use the Android framework as you normally would in your application and can conduct a series of realistic tests that way.\n\nOstensibly the testing framework is unit testing, but the slowness of having to fully compile and upload your app onto a device before executing any tests makes testing slow. &nbsp;Plus, you have to make sure you've got a device attached or an emulator running. &nbsp;As a result, I might consider the testing framework for semi-regular tests (e.g., whenever you push a new commit, or nightly tests) but I would have trouble using them while actively developing.\n\n**Pros:**\n\n* Access to the Android framework**Cons:**\n\n* Slow\n* Requires attached device or running emulator\n* Uses JUnit 3 (instead of the newer JUnit 4)**<span style=\"font-size: large;\">Robolectric</span>**\n\n[Robolectric](http://robolectric.org/) is a project that unifies the speed of unit testing with the ability to access the Android framework. &nbsp;It does this by implementing all those stubs with mocked classes.\n\nHaving tried it out, it is lightning fast and works as expected. &nbsp;I'm also impressed with the amount of active development on it - this is a rapidly improving framework. &nbsp;However, the active development does take a toll; documentation is a bit lacking, plus some new versions of Robolectric break things in previous versions. &nbsp;Plus, it can't mock everything - for example, inter-app communication - since it's not on an actual Android OS. &nbsp;That said, the benefits here far outweigh the negatives when it comes to unit testing Android.\n\n**Pros:**\n\n* Fast\n* Can access mocked Android framework\n* Actively developed**Cons:**\n\n* Not the true Android framework\n* Not everything is mocked\n* Lacking documentation**<span style=\"font-size: large;\">Conclusion</span>**\n\nI'm a fan of what [Jason Sankey said on StackOverflow about tiered unit testing](http://stackoverflow.com/a/15020781/60261):&nbsp;Prefer pure unit tests, then Robolectric, then the Android testing framework. &nbsp;The tests get harder/slower the higher the tier, but sometimes you need it.",
"html": "I've recently been doing research on Android testing. &nbsp;I'm quite new to this business; automated testing has (for the longest time) felt unnecessary. &nbsp;But I've been slowly convinced that the benefits outweigh the time costs - as long as you do it in an efficient manner. &nbsp;To that end, I set out to evaluate the many, many Android testing frameworks to see which ones seemed to save the most time.<br /><br />I began by summarizing all the tools/services I could find in&nbsp;<a href=\"http://goo.gl/XSUxoJ\">a spreadsheet</a>&nbsp;(let me know if I'm missing anything). &nbsp;Beyond that, I am going to do a series of posts going into more detail about different parts of Android testing:<br /><ul><li><b>Part 1:&nbsp;</b><a href=\"http://goo.gl/m6bXcJ\">Unit Tests</a></li><li><b>Part 2:</b> <a href=\"http://goo.gl/KXHZMg\">Functional Tests</a></li><li><b>Part 3:</b> <a href=\"http://goo.gl/X49RoP\">Other Testing Tools</a></li><li><b>Part 4:</b> <a href=\"http://goo.gl/60Xnf7\">Testing Services</a></li><li><b>Spreadsheet:</b>&nbsp;<a href=\"http://goo.gl/XSUxoJ\">Android Testing</a></li></ul>Let's start with unit testing.<br /><br /><b><span style=\"font-size: large;\">Unit Tests</span></b><br /><br />There's no reason you can't use normal JUnit 4 testing for Android applications... as long as you stay away from anything Android.<br /><br />Normally you compile against the SDK's android.jar, which contains nothing but stubbed methods that throw exceptions when run. &nbsp;When you actually upload your APK to a device, it uses the device's implementations of all those stubs. &nbsp;As a result, when running normal unit tests in your IDE, you get no access to those framework implementations (instead receiving mountains of exceptions). &nbsp;This is not a big deal if you're testing some simple functionality that doesn't touch Android itself.<br /><br /><b>Pros:</b><br /><ul><li>Fast and easy</li></ul><b>Cons:</b><br /><ul><li>Cannot use any Android framework classes</li></ul><b><span style=\"font-size: large;\">The Android Testing Framework</span></b><br /><br /><a href=\"http://developer.android.com/tools/testing/testing_android.html\">The Android testing framework</a> is the official method of unit testing on Android. &nbsp;It loads your application onto a device, then runs JUnit-based test suites. &nbsp;Since it runs on the actual OS you can use the Android framework as you normally would in your application and can conduct a series of realistic tests that way.<br /><br />Ostensibly the testing framework is unit testing, but the slowness of having to fully compile and upload your app onto a device before executing any tests makes testing slow. &nbsp;Plus, you have to make sure you've got a device attached or an emulator running. &nbsp;As a result, I might consider the testing framework for semi-regular tests (e.g., whenever you push a new commit, or nightly tests) but I would have trouble using them while actively developing.<br /><br /><b>Pros:</b><br /><ul><li>Access to the Android framework</li></ul><b>Cons:</b><br /><ul><li>Slow</li><li>Requires attached device or running emulator</li><li>Uses JUnit 3 (instead of the newer JUnit 4)</li></ul><b><span style=\"font-size: large;\">Robolectric</span></b><br /><br /><a href=\"http://robolectric.org/\">Robolectric</a> is a project that unifies the speed of unit testing with the ability to access the Android framework. &nbsp;It does this by implementing all those stubs with mocked classes.<br /><br />Having tried it out, it is lightning fast and works as expected. &nbsp;I'm also impressed with the amount of active development on it - this is a rapidly improving framework. &nbsp;However, the active development does take a toll; documentation is a bit lacking, plus some new versions of Robolectric break things in previous versions. &nbsp;Plus, it can't mock everything - for example, inter-app communication - since it's not on an actual Android OS. &nbsp;That said, the benefits here far outweigh the negatives when it comes to unit testing Android.<br /><br /><b>Pros:</b><br /><ul><li>Fast</li><li>Can access mocked Android framework</li><li>Actively developed</li></ul><b>Cons:</b><br /><ul><li>Not the true Android framework</li><li>Not everything is mocked</li><li>Lacking documentation</li></ul><b><span style=\"font-size: large;\">Conclusion</span></b><br /><br />I'm a fan of what <a href=\"http://stackoverflow.com/a/15020781/60261\">Jason Sankey said on StackOverflow about tiered unit testing</a>:&nbsp;Prefer pure unit tests, then Robolectric, then the Android testing framework. &nbsp;The tests get harder/slower the higher the tier, but sometimes you need it.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1387206000000,
"created_by": 1,
"updated_at": 1392042350713,
"updated_by": 1,
"published_at": 1387206000000,
"published_by": 1
},
{
"id": 4,
"title": "Thoughts on the Current State of Android IDEs",
"slug": "thoughts_on_the_current_state_of_android_ides",
"markdown": "I've repeatedly been getting the question \"which IDE should I use for Android?\" recently so I'm writing up a brief summary. &nbsp;Here's my current thoughts on the state of Android IDEs (circa December 2013):\n\n**Eclipse + ADT**\n\nThe original Android IDE, officially supported by Google.\n\n* Supports the most features for creating/building Android apps.\n* Abundant documentation, both from Google and from years of people asking questions about it on StackOverflow.\n* Many 3rd party tools, since it's been the main player for years.\n* Relatively stable; your project won't suddenly stop building when you update your sources.\n**IntelliJ IDEA + Android Plugin**\n\nA Java IDE that has an Android plugin built for it by IntelliJ. &nbsp;This is the one IDE I haven't used extensively, so take my comments with a grain of salt.\n\n* A fan favorite; people rave about IntelliJ (especially those who were burned in one way or another by Eclipse).\n* As stable (if not more so) than Eclipse, because it lacks some of the built-in instabilities in Eclipse (aka, randomly crashing every once in a while).\n* Does not support NDK.\n**Android Studio + Gradle**\n\nAndroid Studio is a fork of IntelliJ IDEA with gradle-based build support.\n\n* Gradle is the future of Android build processes, so using it you'll be one step ahead of the curve.\n* Since it's still heavily in development Android Studio is quite unstable. &nbsp;It's gone from rarely working to only stabbing you in the back every once in a while, but use of it requires extra maintenance work.\n* Does not support all features, like NDK or lint. &nbsp;(There are workarounds, though.)\n* Improves weekly because that's about how often they push out updates. &nbsp;If you love cutting edge technology that's a pro, if you like stability that's a con. &nbsp;(You can switch off of the \"canary\" update channel if you're more conservative.)**Conclusion**\n\n* If you need all Android features (like NDK support), use Eclipse.\n* If you hate Eclipse, use IntelliJ IDEA.\n* If you love gradle builds or want to plan for the future and are willing to put in some extra effort, use Android Studio.<div>Also, if you've got anything to add let me know - I'd be curious if there's some important pieces I'm leaving out, as I am far from an IDE expert.</div>",
"html": "I've repeatedly been getting the question \"which IDE should I use for Android?\" recently so I'm writing up a brief summary. &nbsp;Here's my current thoughts on the state of Android IDEs (circa December 2013):<br /><br /><b>Eclipse + ADT</b><br /><br />The original Android IDE, officially supported by Google.<br /><br /><ul><li>Supports the most features for creating/building Android apps.</li><li>Abundant documentation, both from Google and from years of people asking questions about it on StackOverflow.</li><li>Many 3rd party tools, since it's been the main player for years.</li><li>Relatively stable; your project won't suddenly stop building when you update your sources.</li></ul><br /><b>IntelliJ IDEA + Android Plugin</b><br /><br />A Java IDE that has an Android plugin built for it by IntelliJ. &nbsp;This is the one IDE I haven't used extensively, so take my comments with a grain of salt.<br /><br /><ul><li>A fan favorite; people rave about IntelliJ (especially those who were burned in one way or another by Eclipse).</li><li>As stable (if not more so) than Eclipse, because it lacks some of the built-in instabilities in Eclipse (aka, randomly crashing every once in a while).</li><li>Does not support NDK.</li></ul><br /><b>Android Studio + Gradle</b><br /><br />Android Studio is a fork of IntelliJ IDEA with gradle-based build support.<br /><br /><ul><li>Gradle is the future of Android build processes, so using it you'll be one step ahead of the curve.</li><li>Since it's still heavily in development Android Studio is quite unstable. &nbsp;It's gone from rarely working to only stabbing you in the back every once in a while, but use of it requires extra maintenance work.</li><li>Does not support all features, like NDK or lint. &nbsp;(There are workarounds, though.)</li><li>Improves weekly because that's about how often they push out updates. &nbsp;If you love cutting edge technology that's a pro, if you like stability that's a con. &nbsp;(You can switch off of the \"canary\" update channel if you're more conservative.)</li></ul><b>Conclusion</b><br /><br /><ul><li>If you need all Android features (like NDK support), use Eclipse.</li><li>If you hate Eclipse, use IntelliJ IDEA.</li><li>If you love gradle builds or want to plan for the future and are willing to put in some extra effort, use Android Studio.</li></ul><div>Also, if you've got anything to add let me know - I'd be curious if there's some important pieces I'm leaving out, as I am far from an IDE expert.</div>",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1386255600000,
"created_by": 1,
"updated_at": 1386255600985,
"updated_by": 1,
"published_at": 1386255600000,
"published_by": 1
},
{
"id": 5,
"title": "Streaming JSON Parsing Performance Test: Jackson vs. GSON",
"slug": "streaming_json_parsing_performance_test_jackson_vs_gson",
"markdown": "A few years ago, when speed and memory became a concern in one of my Android apps, I implemented some streaming JSON parsing using [Jackson](http://wiki.fasterxml.com/JacksonHome). &nbsp;At the time I chose Jackson over [Gson](https://code.google.com/p/google-gson/) because the benchmarks seemed to show it was significantly faster*; however, I've heard that recent versions of Gson rival Jackson for speed. &nbsp;I want to re-examine the benchmarks again to make sure I'm choosing the right library.\n\nThe best benchmark I found is at [json-benchmark](https://code.google.com/p/json-benchmark/). &nbsp;There were a number of other benchmarks out there but they didn't appeal to me for various reasons, either because [they didn't provide source](http://geek.amindstretched.com/2012/07/gson-vs-jackson-which-library-is-faster.html), [the benchmark didn't seem very fair](https://github.com/martinadamek/json-android-compare), or [it didn't test on the Dalvik VM](https://github.com/eishay/jvm-serializers/wiki).\n\nUnfortunately, [json-benchmark's last documented test](https://code.google.com/p/json-benchmark/wiki/AndroidBenchmarks) is from two and a half years ago. &nbsp;I decided to try to reproduce these&nbsp;tests against the latest libraries, Jackson 2.3 and Gson 2.2.4\\. &nbsp;There were a few trials getting the test to run again:\n\n* The JSON benchmarking code has moved to [libcore](https://android.googlesource.com/platform/libcore/), so I checked out and referenced the latest benchmarks from there.\n* The ParseBenchmarks code to test Jackson and GSON directly [was removed](https://code.google.com/p/dalvik/source/detail?r=107), so I had to re-add it (using the same old code, but with some package names updated).\n* vogar uses old assumptions about where \"dx\" (and related tools) are located; it still thinks they are in $ANDROID_HOME/platform-tools. &nbsp;Rather than fix and recompile I just made my files match its assumptions for a bit.Once I got it running, I ran the tests on a Nexus 7 (2nd generation), running Android 4.4\\. &nbsp;Here's the results:\n\n<pre> document api ms linear runtime\n TWEETS ANDROID_STREAM 19.82 ===\n TWEETS JACKSON_STREAM 11.47 ==\n TWEETS GSON_STREAM 17.98 ===\n TWEETS GSON_DOM 39.00 =======\n TWEETS ORG_JSON 30.86 =====\n TWEETS XML_PULL 26.08 ====\n TWEETS XML_DOM 85.32 ===============\n TWEETS XML_SAX 33.83 ======\n READER_SHORT ANDROID_STREAM 4.60 =\n READER_SHORT JACKSON_STREAM 2.99 =\n READER_SHORT GSON_STREAM 4.36 =\n READER_SHORT GSON_DOM 8.07 =\n READER_SHORT ORG_JSON 6.42 =\n READER_SHORT XML_PULL 6.75 =\n READER_SHORT XML_DOM 14.84 ==\n READER_SHORT XML_SAX 5.54 =\n READER_LONG ANDROID_STREAM 38.24 =======\n READER_LONG JACKSON_STREAM 18.12 ===\n READER_LONG GSON_STREAM 43.81 ========\n READER_LONG GSON_DOM 72.34 =============\n READER_LONG ORG_JSON 52.47 =========\n READER_LONG XML_PULL 65.53 ============\n READER_LONG XML_DOM 160.02 ==============================\n READER_LONG XML_SAX 47.37 ========</pre>\nOf course your mileage may vary depending on what exactly you're parsing, but with somewhere between 1.5-2x the speed I think I'll stick Jackson when I need my JSON parsing to be fast.\n\n_* Speed isn't everything; if Gson was only marginally slower than Jackson I still would have preferred it; I find their streaming parsing paradigm easier to use._",
"html": "A few years ago, when speed and memory became a concern in one of my Android apps, I implemented some streaming JSON parsing using <a href=\"http://wiki.fasterxml.com/JacksonHome\">Jackson</a>. &nbsp;At the time I chose Jackson over <a href=\"https://code.google.com/p/google-gson/\">Gson</a> because the benchmarks seemed to show it was significantly faster*; however, I've heard that recent versions of Gson rival Jackson for speed. &nbsp;I want to re-examine the benchmarks again to make sure I'm choosing the right library.<br /><br />The best benchmark I found is at <a href=\"https://code.google.com/p/json-benchmark/\">json-benchmark</a>. &nbsp;There were a number of other benchmarks out there but they didn't appeal to me for various reasons, either because <a href=\"http://geek.amindstretched.com/2012/07/gson-vs-jackson-which-library-is-faster.html\">they didn't provide source</a>, <a href=\"https://github.com/martinadamek/json-android-compare\">the benchmark didn't seem very fair</a>, or <a href=\"https://github.com/eishay/jvm-serializers/wiki\">it didn't test on the Dalvik VM</a>.<br /><br />Unfortunately, <a href=\"https://code.google.com/p/json-benchmark/wiki/AndroidBenchmarks\">json-benchmark's last documented test</a> is from two and a half years ago. &nbsp;I decided to try to reproduce these&nbsp;tests against the latest libraries, Jackson 2.3 and Gson 2.2.4. &nbsp;There were a few trials getting the test to run again:<br /><ul><li>The JSON benchmarking code has moved to <a href=\"https://android.googlesource.com/platform/libcore/\">libcore</a>, so I checked out and referenced the latest benchmarks from there.</li><li>The ParseBenchmarks code to test Jackson and GSON directly <a href=\"https://code.google.com/p/dalvik/source/detail?r=107\">was removed</a>, so I had to re-add it (using the same old code, but with some package names updated).</li><li>vogar uses old assumptions about where \"dx\" (and related tools) are located; it still thinks they are in $ANDROID_HOME/platform-tools. &nbsp;Rather than fix and recompile I just made my files match its assumptions for a bit.</li></ul>Once I got it running, I ran the tests on a Nexus 7 (2nd generation), running Android 4.4. &nbsp;Here's the results:<br /><br /><pre> document api ms linear runtime<br /> TWEETS ANDROID_STREAM 19.82 ===<br /> TWEETS JACKSON_STREAM 11.47 ==<br /> TWEETS GSON_STREAM 17.98 ===<br /> TWEETS GSON_DOM 39.00 =======<br /> TWEETS ORG_JSON 30.86 =====<br /> TWEETS XML_PULL 26.08 ====<br /> TWEETS XML_DOM 85.32 ===============<br /> TWEETS XML_SAX 33.83 ======<br /> READER_SHORT ANDROID_STREAM 4.60 =<br /> READER_SHORT JACKSON_STREAM 2.99 =<br /> READER_SHORT GSON_STREAM 4.36 =<br /> READER_SHORT GSON_DOM 8.07 =<br /> READER_SHORT ORG_JSON 6.42 =<br /> READER_SHORT XML_PULL 6.75 =<br /> READER_SHORT XML_DOM 14.84 ==<br /> READER_SHORT XML_SAX 5.54 =<br /> READER_LONG ANDROID_STREAM 38.24 =======<br /> READER_LONG JACKSON_STREAM 18.12 ===<br /> READER_LONG GSON_STREAM 43.81 ========<br /> READER_LONG GSON_DOM 72.34 =============<br /> READER_LONG ORG_JSON 52.47 =========<br /> READER_LONG XML_PULL 65.53 ============<br /> READER_LONG XML_DOM 160.02 ==============================<br /> READER_LONG XML_SAX 47.37 ========</pre><br />Of course your mileage may vary depending on what exactly you're parsing, but with somewhere between 1.5-2x the speed I think I'll stick Jackson when I need my JSON parsing to be fast.<br /><br /><i>* Speed isn't everything; if Gson was only marginally slower than Jackson I still would have preferred it; I find their streaming parsing paradigm easier to use.</i>",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1386082800000,
"created_by": 1,
"updated_at": 1386082807744,
"updated_by": 1,
"published_at": 1386082800000,
"published_by": 1
},
{
"id": 6,
"title": "Sample Android Project: Movies",
"slug": "sample_android_project_movies",
"markdown": "There's a sample application that I worked on recently with talented designer [Chris Arvin](http://chrisarv.in/) for [a talk we gave at DroidCon UK 2013](https://speakerdeck.com/dlew/crafting-unique-delightful-apps). &nbsp;I also repurposed part of it for [the talk about animations I gave at AnDevCon a few weeks later](https://speakerdeck.com/dlew/i-can-animate-and-so-can-you).\n\nThe app is open source and you can check it out here:&nbsp;[https://github.com/dlew/android-movies-demo](https://github.com/dlew/android-movies-demo)\n\nYou can get the APK here:&nbsp;[https://github.com/dlew/android-movies-demo/releases/](https://github.com/dlew/android-movies-demo/releases/)\n\n<iframe allowfullscreen=\"\" frameborder=\"0\" height=\"360\" src=\"//www.youtube.com/embed/nchbp6pr2tg\" width=\"480\"></iframe> \n\nThe interactions required a bit of interesting engineering so I wanted to discuss some of it here.\n\n**ViewPager and Decor**\n\nOne of the key interactions we wanted was the app to feel like a ViewPager so that it was an interaction users were familiar with except that the result isn't quite the same - instead of paging, content would slide out from underneath other content. &nbsp;This is not something ViewPager is inherently designed to do.\n\nThere were two options open to me. &nbsp;One was to rip out all of ViewPager's event handling code and make my own custom View, which was not an appealing prospect. &nbsp;The other was to find some way to manipulate ViewPager itself.\n\nIt turns out there is an interface ViewPager finds special called Decor. &nbsp;If a View implements Decor, then ViewPager treats it as a special View that can remain on top of it the ViewPager. &nbsp;This is normally for implementing your own tabs, but in this case I imported my own copy of ViewPager (since Decor is hidden normally) and made my entire UI a Decor View.\n\nIt's a neat trick that would work for any app that wants ViewPager event handling without paging Views, though I think if you wanted a less hacky solution you'd write your own event code.\n\n**Custom Views Everywhere**\n\nI've gone from avoiding custom Views like the plague to fully embracing them.\n\nThe key realization is that custom Views do not need to handle every situation. &nbsp;If you're looking at framework custom Views as reference you will be overwhelmed quickly. &nbsp;For example, during measurement framework Views have to handle WRAP_CONTENT, MATCH_PARENT, and everything in between; but if you know your View is always going to be MATCH_PARENT you can greatly simplify all your code.\n\nThe movies sample app is a pile of custom Views. &nbsp;First there's SlidingRevealViewGroup, which generically shows one View slide out from another. &nbsp;On top of that is built MovieRowView, which has the specific Views that we want to display. &nbsp;Then there's SlidingPairView, which is a set of two SlidingRevealViewGroups that creates the side-by-side effect seen in the app.\n\nI also needed a few other custom Views to shore up some other issues. &nbsp;CenteringRelativeLayout just adjusts the film cover so that, as it shrinks in size, it still looks centered. &nbsp;SlidingListView was required for performance; we needed to manipulate the rows directly when sliding, instead of constantly notifying of data changed.\n\n**Performance Tricks**\n\nThe coolest part of the whole app is the slide: how the cover becomes smaller and the content slides out from underneath. &nbsp;All of this was achieved through translation of Views. &nbsp;I took advantage of the fact that ViewGroups don't render their children outside of their own bounds. &nbsp;By translating content I could hide them outside the clip bounds.\n\nWhen a slide starts, it throws practically everything into hardware layers then just slides Views left/right. &nbsp;Moving around pre-rendered content is fast and as a result the paging is silky smooth.\n\nNowadays I'm a huge fan of those basic properties of Views (translation, scale, rotation and alpha). &nbsp;They're the core reason to support ICS+ only; with these properties you can take your interactions to the next level.\n\n**Drawbacks**\n\nThe drawback of the solution I came up with is that it creates a ton of overdraw. &nbsp;This hurts performance, especially (as far as I can tell) when rendering a new row while scrolling up/down. &nbsp;I sacrificed scrolling performance for paging performance. &nbsp;Perhaps there is a way to achieve both, but I'm pretty much done with this sample for now.\n\nThe rounded corners could've been implemented in a much better fashion than an overlaid Drawable, but with the limited time before the presentation I had, I could not come up with a better solution.",
"html": "There's a sample application that I worked on recently with talented designer <a href=\"http://chrisarv.in/\">Chris Arvin</a> for <a href=\"https://speakerdeck.com/dlew/crafting-unique-delightful-apps\">a talk we gave at DroidCon UK 2013</a>. &nbsp;I also repurposed part of it for <a href=\"https://speakerdeck.com/dlew/i-can-animate-and-so-can-you\">the talk about animations I gave at AnDevCon a few weeks later</a>.<br /><br />The app is open source and you can check it out here:&nbsp;<a href=\"https://github.com/dlew/android-movies-demo\">https://github.com/dlew/android-movies-demo</a><br /><br />You can get the APK here:&nbsp;<a href=\"https://github.com/dlew/android-movies-demo/releases/\">https://github.com/dlew/android-movies-demo/releases/</a><br /><br /><iframe allowfullscreen=\"\" frameborder=\"0\" height=\"360\" src=\"//www.youtube.com/embed/nchbp6pr2tg\" width=\"480\"></iframe> <br /><br />The interactions required a bit of interesting engineering so I wanted to discuss some of it here.<br /><br /><b>ViewPager and Decor</b><br /><br />One of the key interactions we wanted was the app to feel like a ViewPager so that it was an interaction users were familiar with except that the result isn't quite the same - instead of paging, content would slide out from underneath other content. &nbsp;This is not something ViewPager is inherently designed to do.<br /><br />There were two options open to me. &nbsp;One was to rip out all of ViewPager's event handling code and make my own custom View, which was not an appealing prospect. &nbsp;The other was to find some way to manipulate ViewPager itself.<br /><br />It turns out there is an interface ViewPager finds special called Decor. &nbsp;If a View implements Decor, then ViewPager treats it as a special View that can remain on top of it the ViewPager. &nbsp;This is normally for implementing your own tabs, but in this case I imported my own copy of ViewPager (since Decor is hidden normally) and made my entire UI a Decor View.<br /><br />It's a neat trick that would work for any app that wants ViewPager event handling without paging Views, though I think if you wanted a less hacky solution you'd write your own event code.<br /><br /><b>Custom Views Everywhere</b><br /><br />I've gone from avoiding custom Views like the plague to fully embracing them.<br /><br />The key realization is that custom Views do not need to handle every situation. &nbsp;If you're looking at framework custom Views as reference you will be overwhelmed quickly. &nbsp;For example, during measurement framework Views have to handle WRAP_CONTENT, MATCH_PARENT, and everything in between; but if you know your View is always going to be MATCH_PARENT you can greatly simplify all your code.<br /><br />The movies sample app is a pile of custom Views. &nbsp;First there's SlidingRevealViewGroup, which generically shows one View slide out from another. &nbsp;On top of that is built MovieRowView, which has the specific Views that we want to display. &nbsp;Then there's SlidingPairView, which is a set of two SlidingRevealViewGroups that creates the side-by-side effect seen in the app.<br /><br />I also needed a few other custom Views to shore up some other issues. &nbsp;CenteringRelativeLayout just adjusts the film cover so that, as it shrinks in size, it still looks centered. &nbsp;SlidingListView was required for performance; we needed to manipulate the rows directly when sliding, instead of constantly notifying of data changed.<br /><br /><b>Performance Tricks</b><br /><br />The coolest part of the whole app is the slide: how the cover becomes smaller and the content slides out from underneath. &nbsp;All of this was achieved through translation of Views. &nbsp;I took advantage of the fact that ViewGroups don't render their children outside of their own bounds. &nbsp;By translating content I could hide them outside the clip bounds.<br /><br />When a slide starts, it throws practically everything into hardware layers then just slides Views left/right. &nbsp;Moving around pre-rendered content is fast and as a result the paging is silky smooth.<br /><br />Nowadays I'm a huge fan of those basic properties of Views (translation, scale, rotation and alpha). &nbsp;They're the core reason to support ICS+ only; with these properties you can take your interactions to the next level.<br /><br /><b>Drawbacks</b><br /><br />The drawback of the solution I came up with is that it creates a ton of overdraw. &nbsp;This hurts performance, especially (as far as I can tell) when rendering a new row while scrolling up/down. &nbsp;I sacrificed scrolling performance for paging performance. &nbsp;Perhaps there is a way to achieve both, but I'm pretty much done with this sample for now.<br /><br />The rounded corners could've been implemented in a much better fashion than an overlaid Drawable, but with the limited time before the presentation I had, I could not come up with a better solution.<br /><br />",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1385391600000,
"created_by": 1,
"updated_at": 1386865971649,
"updated_by": 1,
"published_at": 1385391600000,
"published_by": 1
},
{
"id": 7,
"title": "Is findViewById() Slow?",
"slug": "is_find_view_by_id_slow_",
"markdown": "One of the presenters at [Droidcon UK 2013](http://uk.droidcon.com/2013/) made the point that [View.findViewById()](http://developer.android.com/reference/android/view/View.html#findViewById(int)) has been unjustly villainized and that [the ViewHolder pattern](http://developer.android.com/training/improving-layouts/smooth-scrolling.html#ViewHolder) recommended by Google is unnecessary. &nbsp;After hearing that I studied the code (in&nbsp;[View](https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/View.java)&nbsp;and&nbsp;[ViewGroup](https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/ViewGroup.java)) and did not observe any heinous performance issues contained therein. &nbsp;It's a pretty simple recursive lookup that walks the View hierarchy for an id.\n\nAs [this article](http://www.blackmoonit.com/2011/06/proof-findviewbyid-slower-than-viewholder/) points out, findViewById() is necessarily&nbsp;slower than ViewHolder because it's O(n) vs. O(1). &nbsp;**But that doesn't mean findViewById() is slow**. &nbsp;If the operation is sufficiently fast and n is low then it doesn't matter if it's O(n). &nbsp;Who cares if I have to do a 1 nanosecond operation a thousand times?\n\nMy hypothesis is that findViewById() is fast enough as to be negligible. &nbsp;With that in mind, I cooked up a sample application that tests findViewById(): [https://github.com/dlew/android-findviewbyid](https://github.com/dlew/android-findviewbyid)\n\n<div class=\"separator\" style=\"clear: both; text-align: center;\">[![](http://3.bp.blogspot.com/-YL92FMQUD5k/UouY7o5X-5I/AAAAAAAAByc/_vFUPrNDFTA/s320/device-2013-11-19-105853.png)](http://3.bp.blogspot.com/-YL92FMQUD5k/UouY7o5X-5I/AAAAAAAAByc/_vFUPrNDFTA/s1600/device-2013-11-19-105853.png)</div>\nYou can dynamically create a hierarchy of Views, either adding to the depth or the number of children at each node. &nbsp;When you hit \"run\" it searches for the furthest away id a number of times, then averages the time taken. &nbsp;I ran the test on my Nexus 1, to somewhat recreate the situation described&nbsp;[when Google explicitly recommended the ViewHolder pattern](http://www.google.com/events/io/2010/sessions/world-of-listview-android.html)&nbsp;three years ago.\n\nHere's the results from a test of many possible depth/views per node values:&nbsp;[http://goo.gl/dK2vo3](http://goo.gl/dK2vo3)\n\n<div class=\"separator\" style=\"clear: both; text-align: center;\">[![](http://4.bp.blogspot.com/-f36r2EKglZQ/UoyobpUUIpI/AAAAAAAABys/ss23Y0EwjmA/s1600/chart_1.png)](http://4.bp.blogspot.com/-f36r2EKglZQ/UoyobpUUIpI/AAAAAAAABys/ss23Y0EwjmA/s1600/chart_1.png)</div>\nAs &nbsp;can be seen from the chart, the time taken to use findViewById() is roughly linear with the number of Views in the hierarchy. &nbsp;What's key here, though, is that for a low number of Views it barely takes any time at all - usually a matter of several microseconds. &nbsp;And remember, this is on a rather old phone, the Nexus 1.\n\nThat said, if you were to call findViewById() many, many times it could cause a problem. &nbsp;Admittedly this part of the post is going to be a bit more hand-wavy than the rest, but: I tried out scrolling on a ListView on my Nexus 1 - there is an upper bound to how fast I can scroll and I can't seem to break 60 getViews() per second. &nbsp;That means that getView() is called once per 16ms frame. &nbsp;Given that we're measuring findViewById() in microseconds, even calling it a dozen times (with a reasonable number of Views) shouldn't cause performance issues.\n\nSo my conclusion is that **findViewById() is harmless in most practical circumstances**. &nbsp;I'll probably still use ViewHolder to avoid casting Views all the time, but performance will not be the main purpose anymore.\n\n_Disclaimer: I'm not a performance expert so I suspect there's something I'm missing (especially since I'm going directly against Google advice here). &nbsp;If someone knows of a missing link let me know!_",
"html": "One of the presenters at <a href=\"http://uk.droidcon.com/2013/\">Droidcon UK 2013</a> made the point that <a href=\"http://developer.android.com/reference/android/view/View.html#findViewById(int)\">View.findViewById()</a> has been unjustly villainized and that <a href=\"http://developer.android.com/training/improving-layouts/smooth-scrolling.html#ViewHolder\">the ViewHolder pattern</a> recommended by Google is unnecessary. &nbsp;After hearing that I studied the code (in&nbsp;<a href=\"https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/View.java\">View</a>&nbsp;and&nbsp;<a href=\"https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/ViewGroup.java\">ViewGroup</a>) and did not observe any heinous performance issues contained therein. &nbsp;It's a pretty simple recursive lookup that walks the View hierarchy for an id.<br /><br />As <a href=\"http://www.blackmoonit.com/2011/06/proof-findviewbyid-slower-than-viewholder/\">this article</a> points out, findViewById() is necessarily&nbsp;slower than ViewHolder because it's O(n) vs. O(1). &nbsp;<b>But that doesn't mean findViewById() is slow</b>. &nbsp;If the operation is sufficiently fast and n is low then it doesn't matter if it's O(n). &nbsp;Who cares if I have to do a 1 nanosecond operation a thousand times?<br /><br />My hypothesis is that findViewById() is fast enough as to be negligible. &nbsp;With that in mind, I cooked up a sample application that tests findViewById(): <a href=\"https://github.com/dlew/android-findviewbyid\">https://github.com/dlew/android-findviewbyid</a><br /><br /><div class=\"separator\" style=\"clear: both; text-align: center;\"><a href=\"http://3.bp.blogspot.com/-YL92FMQUD5k/UouY7o5X-5I/AAAAAAAAByc/_vFUPrNDFTA/s1600/device-2013-11-19-105853.png\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"><img border=\"0\" height=\"320\" src=\"http://3.bp.blogspot.com/-YL92FMQUD5k/UouY7o5X-5I/AAAAAAAAByc/_vFUPrNDFTA/s320/device-2013-11-19-105853.png\" width=\"192\" /></a></div><br />You can dynamically create a hierarchy of Views, either adding to the depth or the number of children at each node. &nbsp;When you hit \"run\" it searches for the furthest away id a number of times, then averages the time taken. &nbsp;I ran the test on my Nexus 1, to somewhat recreate the situation described&nbsp;<a href=\"http://www.google.com/events/io/2010/sessions/world-of-listview-android.html\">when Google explicitly recommended the ViewHolder pattern</a>&nbsp;three years ago.<br /><br />Here's the results from a test of many possible depth/views per node values:&nbsp;<a href=\"http://goo.gl/dK2vo3\">http://goo.gl/dK2vo3</a><br /><br /><div class=\"separator\" style=\"clear: both; text-align: center;\"><a href=\"http://4.bp.blogspot.com/-f36r2EKglZQ/UoyobpUUIpI/AAAAAAAABys/ss23Y0EwjmA/s1600/chart_1.png\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"><img border=\"0\" src=\"http://4.bp.blogspot.com/-f36r2EKglZQ/UoyobpUUIpI/AAAAAAAABys/ss23Y0EwjmA/s1600/chart_1.png\" /></a></div><br />As &nbsp;can be seen from the chart, the time taken to use findViewById() is roughly linear with the number of Views in the hierarchy. &nbsp;What's key here, though, is that for a low number of Views it barely takes any time at all - usually a matter of several microseconds. &nbsp;And remember, this is on a rather old phone, the Nexus 1.<br /><br />That said, if you were to call findViewById() many, many times it could cause a problem. &nbsp;Admittedly this part of the post is going to be a bit more hand-wavy than the rest, but: I tried out scrolling on a ListView on my Nexus 1 - there is an upper bound to how fast I can scroll and I can't seem to break 60 getViews() per second. &nbsp;That means that getView() is called once per 16ms frame. &nbsp;Given that we're measuring findViewById() in microseconds, even calling it a dozen times (with a reasonable number of Views) shouldn't cause performance issues.<br /><br />So my conclusion is that <b>findViewById() is harmless in most practical circumstances</b>. &nbsp;I'll probably still use ViewHolder to avoid casting Views all the time, but performance will not be the main purpose anymore.<br /><br /><i>Disclaimer: I'm not a performance expert so I suspect there's something I'm missing (especially since I'm going directly against Google advice here). &nbsp;If someone knows of a missing link let me know!</i>",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1385046000000,
"created_by": 1,
"updated_at": 1386865983793,
"updated_by": 1,
"published_at": 1385046000000,
"published_by": 1
},
{
"id": 8,
"title": "Android Talk Slides from 2013",
"slug": "android_talk_slides_from_2013",
"markdown": "I'm done with talk season! &nbsp;In case you missed them, here's the slides:\n\n[Crafting Unique, Delightful Apps](https://speakerdeck.com/dlew/crafting-unique-delightful-apps)\n\n[I Can Animate and So Can You](https://speakerdeck.com/dlew/i-can-animate-and-so-can-you)\n\nI suggest downloading the Keynote files for the presentations. &nbsp;They animate!",
"html": "I'm done with talk season! &nbsp;In case you missed them, here's the slides:<br /><br /><a href=\"https://speakerdeck.com/dlew/crafting-unique-delightful-apps\">Crafting Unique, Delightful Apps</a><br /><br /><a href=\"https://speakerdeck.com/dlew/i-can-animate-and-so-can-you\">I Can Animate and So Can You</a><br /><br />I suggest downloading the Keynote files for the presentations. &nbsp;They animate!",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1384786800000,
"created_by": 1,
"updated_at": 1384786811260,
"updated_by": 1,
"published_at": 1384786800000,
"published_by": 1
},
{
"id": 9,
"title": "DateUtils.getRelativeTimeSpanString() and Timezones",
"slug": "date_utils_get_relative_time_span_string_and_timezones",
"markdown": "If you're thinking about [DateUtils.getRelativeTimeSpanString()](http://developer.android.com/reference/android/text/format/DateUtils.html#getRelativeTimeSpanString(long, long, long, int)): **don't**.\n\nAfter a long struggle I've finally given up on the method. &nbsp;It seems so tempting - an easy way of showing the user how far away an event will be (or was). &nbsp;But without being able to pass a timezone you run into an intractable situation which makes it unusable.\n\nThe critical problem relates to how it calculates a number of days. &nbsp;It relies on [Time.getJulianDay()](http://developer.android.com/reference/android/text/format/Time.html#getJulianDay(long, long)), which would work - except you have no control over the timezone parameter. &nbsp;Instead, it uses the default device timezone. &nbsp;This can cause day calculations to be incorrect as you might shift a Julian day when applying the device timezone to the milliseconds provided from another timezone.\n\nBefore 4.3, the situation was even worse: the internal Time used in DateUtils (for calls to getJulianDay()) is&nbsp;**cached**. &nbsp;That meant if your app uses&nbsp;getRelativeTimeSpanString(), then the device's timezone changes, you're now calculating the # of days based on the previous device timezone!\n\nThe only comprehensive solution I can come up with is to implement my own version of getRelativeTimeSpanString() that adds the timezone element. &nbsp;You just need to account for timezones when you're dealing with any period of time greater than hours.",
"html": "If you're thinking about <a href=\"http://developer.android.com/reference/android/text/format/DateUtils.html#getRelativeTimeSpanString(long, long, long, int)\">DateUtils.getRelativeTimeSpanString()</a>: <b>don't</b>.<br /><br />After a long struggle I've finally given up on the method. &nbsp;It seems so tempting - an easy way of showing the user how far away an event will be (or was). &nbsp;But without being able to pass a timezone you run into an intractable situation which makes it unusable.<br /><br />The critical problem relates to how it calculates a number of days. &nbsp;It relies on <a href=\"http://developer.android.com/reference/android/text/format/Time.html#getJulianDay(long, long)\">Time.getJulianDay()</a>, which would work - except you have no control over the timezone parameter. &nbsp;Instead, it uses the default device timezone. &nbsp;This can cause day calculations to be incorrect as you might shift a Julian day when applying the device timezone to the milliseconds provided from another timezone.<br /><br />Before 4.3, the situation was even worse: the internal Time used in DateUtils (for calls to getJulianDay()) is&nbsp;<b>cached</b>. &nbsp;That meant if your app uses&nbsp;getRelativeTimeSpanString(), then the device's timezone changes, you're now calculating the # of days based on the previous device timezone!<br /><br />The only comprehensive solution I can come up with is to implement my own version of getRelativeTimeSpanString() that adds the timezone element. &nbsp;You just need to account for timezones when you're dealing with any period of time greater than hours.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1382533200000,
"created_by": 1,
"updated_at": 1382533200430,
"updated_by": 1,
"published_at": 1382533200000,
"published_by": 1
},
{
"id": 10,
"title": "Centering Single-Line Text in a Canvas",
"slug": "centering_single_line_text_in_a_canvas",
"markdown": "Suppose I want a custom View that draws a circle, then a number centered inside of it. &nbsp;Your first attempt will probably look something like this:\n\n<div class=\"separator\" style=\"clear: both; text-align: center;\">[![](http://1.bp.blogspot.com/-jqcdEFeTqj8/Uk1_6nYwGoI/AAAAAAAABu0/pUvh_Gz7yIY/s1600/bad-align.png)](http://1.bp.blogspot.com/-jqcdEFeTqj8/Uk1_6nYwGoI/AAAAAAAABu0/pUvh_Gz7yIY/s1600/bad-align.png)</div>\nThe problem is that while you can easily set a horizontal alignment for your TextPaint (via [Paint.Align](http://developer.android.com/reference/android/graphics/Paint.Align.html)), the vertical alignment is tricky. &nbsp;That's because [Canvas.drawText()](http://developer.android.com/reference/android/graphics/Canvas.html#drawText(java.lang.String, float, float, android.graphics.Paint))&nbsp;starts drawing at the **baseline** of your set Y-coordinate, instead of the center.\n\nIf you only knew the height of the text, then you could center it yourself - but getting the height is tricky! &nbsp;[TextPaint.getTextBounds()](http://developer.android.com/reference/android/graphics/Paint.html#getTextBounds(java.lang.String, int, int, android.graphics.Rect)) doesn't work quite right because it gives you the minimal bounding rectangle, not the height that the TextPaint draws. &nbsp;For example, if your text has no ascenders/descenders, then the measured height is smaller than it will draw (since it will still account for the **possibility** of them).\n\nThe way I've found to get the height of the TextPaint is to use [ascent()](http://developer.android.com/reference/android/graphics/Paint.html#ascent()) and [descent()](http://developer.android.com/reference/android/graphics/Paint.html#descent()). &nbsp;These measure the size above/below the text's baseline. &nbsp;Combined, they add up to the total height of the drawn text. &nbsp;You can then use some math to center the draw on the baseline - here's a version of onDraw() that does it correctly*:\n\n<pre>protected void onDraw(Canvas canvas) {\n super.onDraw(canvas);\n\n Paint paint = new Paint();\n paint.setColor(Color.BLACK);\n\n TextPaint textPaint = new TextPaint();\n textPaint.setColor(Color.WHITE);\n textPaint.setTextAlign(Paint.Align.CENTER);\n float textHeight = textPaint.descent() - textPaint.ascent();\n float textOffset = (textHeight / 2) - textPaint.descent();\n\n RectF bounds = new RectF(0, 0, getWidth(), getHeight());\n canvas.drawOval(bounds, paint);\n canvas.drawText(\"42\", bounds.centerX(), bounds.centerY() + textOffset, textPaint);\n}</pre>\nAnd the finished product is here:\n\n<div class=\"separator\" style=\"clear: both; text-align: center;\">[![](http://3.bp.blogspot.com/-BWBjb21mt1Q/Uk2DqmtJZLI/AAAAAAAABvA/ovFA21XUlGc/s1600/align.png)](http://3.bp.blogspot.com/-BWBjb21mt1Q/Uk2DqmtJZLI/AAAAAAAABvA/ovFA21XUlGc/s1600/align.png)</div>\nNote that all advice in this post is about a single line of text. &nbsp;If you're handling multi-line text then the solution is more complex because you have to handle how many lines the text will render onto. &nbsp;If I ever try to tackle that I'll write that up as well.\n_\n__* In a real-world example, you wouldn't want to instantiate your Paints in onDraw(); this is done for brevity's sake._",
"html": "Suppose I want a custom View that draws a circle, then a number centered inside of it. &nbsp;Your first attempt will probably look something like this:<br /><br /><div class=\"separator\" style=\"clear: both; text-align: center;\"><a href=\"http://1.bp.blogspot.com/-jqcdEFeTqj8/Uk1_6nYwGoI/AAAAAAAABu0/pUvh_Gz7yIY/s1600/bad-align.png\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"><img border=\"0\" src=\"http://1.bp.blogspot.com/-jqcdEFeTqj8/Uk1_6nYwGoI/AAAAAAAABu0/pUvh_Gz7yIY/s1600/bad-align.png\" /></a></div><br />The problem is that while you can easily set a horizontal alignment for your TextPaint (via <a href=\"http://developer.android.com/reference/android/graphics/Paint.Align.html\">Paint.Align</a>), the vertical alignment is tricky. &nbsp;That's because <a href=\"http://developer.android.com/reference/android/graphics/Canvas.html#drawText(java.lang.String, float, float, android.graphics.Paint)\">Canvas.drawText()</a>&nbsp;starts drawing at the <b>baseline</b> of your set Y-coordinate, instead of the center.<br /><br />If you only knew the height of the text, then you could center it yourself - but getting the height is tricky! &nbsp;<a href=\"http://developer.android.com/reference/android/graphics/Paint.html#getTextBounds(java.lang.String, int, int, android.graphics.Rect)\">TextPaint.getTextBounds()</a> doesn't work quite right because it gives you the minimal bounding rectangle, not the height that the TextPaint draws. &nbsp;For example, if your text has no ascenders/descenders, then the measured height is smaller than it will draw (since it will still account for the <b>possibility</b> of them).<br /><br />The way I've found to get the height of the TextPaint is to use <a href=\"http://developer.android.com/reference/android/graphics/Paint.html#ascent()\">ascent()</a> and <a href=\"http://developer.android.com/reference/android/graphics/Paint.html#descent()\">descent()</a>. &nbsp;These measure the size above/below the text's baseline. &nbsp;Combined, they add up to the total height of the drawn text. &nbsp;You can then use some math to center the draw on the baseline - here's a version of onDraw() that does it correctly*:<br /><br /><pre>protected void onDraw(Canvas canvas) {<br /> super.onDraw(canvas);<br /><br /> Paint paint = new Paint();<br /> paint.setColor(Color.BLACK);<br /><br /> TextPaint textPaint = new TextPaint();<br /> textPaint.setColor(Color.WHITE);<br /> textPaint.setTextAlign(Paint.Align.CENTER);<br /> float textHeight = textPaint.descent() - textPaint.ascent();<br /> float textOffset = (textHeight / 2) - textPaint.descent();<br /><br /> RectF bounds = new RectF(0, 0, getWidth(), getHeight());<br /> canvas.drawOval(bounds, paint);<br /> canvas.drawText(\"42\", bounds.centerX(), bounds.centerY() + textOffset, textPaint);<br />}</pre><br />And the finished product is here:<br /><br /><div class=\"separator\" style=\"clear: both; text-align: center;\"><a href=\"http://3.bp.blogspot.com/-BWBjb21mt1Q/Uk2DqmtJZLI/AAAAAAAABvA/ovFA21XUlGc/s1600/align.png\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"><img border=\"0\" src=\"http://3.bp.blogspot.com/-BWBjb21mt1Q/Uk2DqmtJZLI/AAAAAAAABvA/ovFA21XUlGc/s1600/align.png\" /></a></div><br />Note that all advice in this post is about a single line of text. &nbsp;If you're handling multi-line text then the solution is more complex because you have to handle how many lines the text will render onto. &nbsp;If I ever try to tackle that I'll write that up as well.<br /><i><br /></i><i>* In a real-world example, you wouldn't want to instantiate your Paints in onDraw(); this is done for brevity's sake.</i>",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1380816000000,
"created_by": 1,
"updated_at": 1380816002374,
"updated_by": 1,
"published_at": 1380816000000,
"published_by": 1
},
{
"id": 11,
"title": "Upcoming Conferences",
"slug": "upcoming_conferences",
"markdown": "I just wanted to let anyone interested know about some upcoming conferences I'll be speaking at...\n\n**Droidcon London**\n London, October 24-27th\n<div>[Crafting Unique, Delightful Apps](http://uk.droidcon.com/2013/sessions/crafting-unique-delightful-apps/)&nbsp;(9:45 AM, Thursday, October 24th)</div>\nI'll be giving this talk in conjunction with our awesome designer, Chris Arvin. &nbsp;To be honest, 45 minutes is hardly enough time to talk about all the things we could, but I'll be around all week long to talk more.\n\nI'm also planning on attending the [hackathon](http://uk.droidcon.com/2013/hackathon/) that weekend. &nbsp;I've never done a hackathon before so it should be fun. &nbsp;My only concern is that I have zero interest in staying up all night coding. &nbsp;I think 8 hours of sleep (and some mental rest) is far more valuable than being drained all Sunday.\n\n**AnDevCon**\nSan Francisco, November 12-15th\n[I Can Animate and So Can You](http://tsn2.bzmedia.com/tradeshows/classinfo.aspx?id=12117&amp;showid=29) (8:30 AM, Friday, November 15th)\n\nI've started embracing animations in the last year in a way I never had before. &nbsp;I regarded them as chunky and painful, which was true back in the days of 1.x and 2.x, but that's no longer the case. &nbsp;It's possible to make really awesome animations now but it's still difficult to fit them into your app's structure. &nbsp;This talk is designed to get you to think about how to do advanced animations in your app.\n\nI also have a discount code for AnDevCon. &nbsp;It'll knock $200 off registration. &nbsp;Just use the code **\"LEW\"**.",
"html": "I just wanted to let anyone interested know about some upcoming conferences I'll be speaking at...<br /><br /><b>Droidcon London</b><br /> London, October 24-27th<br /><div><a href=\"http://uk.droidcon.com/2013/sessions/crafting-unique-delightful-apps/\">Crafting Unique, Delightful Apps</a>&nbsp;(9:45 AM, Thursday, October 24th)</div><br />I'll be giving this talk in conjunction with our awesome designer, Chris Arvin. &nbsp;To be honest, 45 minutes is hardly enough time to talk about all the things we could, but I'll be around all week long to talk more.<br /><br />I'm also planning on attending the <a href=\"http://uk.droidcon.com/2013/hackathon/\">hackathon</a> that weekend. &nbsp;I've never done a hackathon before so it should be fun. &nbsp;My only concern is that I have zero interest in staying up all night coding. &nbsp;I think 8 hours of sleep (and some mental rest) is far more valuable than being drained all Sunday.<br /><br /><b>AnDevCon</b><br />San Francisco, November 12-15th<br /><a href=\"http://tsn2.bzmedia.com/tradeshows/classinfo.aspx?id=12117&amp;showid=29\">I Can Animate and So Can You</a> (8:30 AM, Friday, November 15th)<br /><br />I've started embracing animations in the last year in a way I never had before. &nbsp;I regarded them as chunky and painful, which was true back in the days of 1.x and 2.x, but that's no longer the case. &nbsp;It's possible to make really awesome animations now but it's still difficult to fit them into your app's structure. &nbsp;This talk is designed to get you to think about how to do advanced animations in your app.<br /><br />I also have a discount code for AnDevCon. &nbsp;It'll knock $200 off registration. &nbsp;Just use the code <b>\"LEW\"</b>.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1379433600000,
"created_by": 1,
"updated_at": 1379433606122,
"updated_by": 1,
"published_at": 1379433600000,
"published_by": 1
},
{
"id": 12,
"title": "Smoothing performance on Fragment transitions",
"slug": "smoothing_performance_on_fragment_transitions",
"markdown": "Suppose you're doing a pretty standard Fragment replacement with a custom animation:\n\n<pre>getSupportFragmentManager()\n .beginTransaction()\n .setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)\n .replace(android.R.id.content, new MyFragment())\n .commit();\n</pre>\nYou may notice that the performance can be a bit rough, not as smooth as you'd like. A common way to improve Android animation performance is to use hardware layers. &nbsp;Normally you'd add it to the animation directly but with fragments you don't get access to it unless you take advantage of Fragment.onCreateAnimation()*. &nbsp;Here's how it looks:\n\n<pre>public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {\n Animation animation = super.onCreateAnimation(transit, enter, nextAnim);\n\n // HW layer support only exists on API 11+\n if (Build.VERSION.SDK_INT &gt;= 11) {\n if (animation == null &amp;&amp; nextAnim != 0) {\n animation = AnimationUtils.loadAnimation(getActivity(), nextAnim);\n }\n\n if (animation != null) {\n getView().setLayerType(View.LAYER_TYPE_HARDWARE, null);\n\n animation.setAnimationListener(new AnimationListener() {\n public void onAnimationEnd(Animation animation) {\n getView().setLayerType(View.LAYER_TYPE_NONE, null);\n }\n\n // ...other AnimationListener methods go here...\n });\n }\n }\n\n return animation;\n}</pre>\nNow the animation should be a lot more smooth! &nbsp;In my own code, I've overridden this method in a base Fragment from which all others extend so that I always get this feature (though if you're more particular you could only apply it to certain Fragments).\n\n* If you're not using [the support library](http://developer.android.com/tools/support-library/index.html), then you'll be overriding Fragment.onCreateAnimator() and using animator-based classes.",
"html": "Suppose you're doing a pretty standard Fragment replacement with a custom animation:<br /><br /><pre>getSupportFragmentManager()<br /> .beginTransaction()<br /> .setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)<br /> .replace(android.R.id.content, new MyFragment())<br /> .commit();<br /></pre><br />You may notice that the performance can be a bit rough, not as smooth as you'd like. A common way to improve Android animation performance is to use hardware layers. &nbsp;Normally you'd add it to the animation directly but with fragments you don't get access to it unless you take advantage of Fragment.onCreateAnimation()*. &nbsp;Here's how it looks:<br /><br /><pre>public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {<br /> Animation animation = super.onCreateAnimation(transit, enter, nextAnim);<br /><br /> // HW layer support only exists on API 11+<br /> if (Build.VERSION.SDK_INT &gt;= 11) {<br /> if (animation == null &amp;&amp; nextAnim != 0) {<br /> animation = AnimationUtils.loadAnimation(getActivity(), nextAnim);<br /> }<br /><br /> if (animation != null) {<br /> getView().setLayerType(View.LAYER_TYPE_HARDWARE, null);<br /><br /> animation.setAnimationListener(new AnimationListener() {<br /> public void onAnimationEnd(Animation animation) {<br /> getView().setLayerType(View.LAYER_TYPE_NONE, null);<br /> }<br /><br /> // ...other AnimationListener methods go here...<br /> });<br /> }<br /> }<br /><br /> return animation;<br />}</pre><br />Now the animation should be a lot more smooth! &nbsp;In my own code, I've overridden this method in a base Fragment from which all others extend so that I always get this feature (though if you're more particular you could only apply it to certain Fragments).<br /><br />* If you're not using <a href=\"http://developer.android.com/tools/support-library/index.html\">the support library</a>, then you'll be overriding Fragment.onCreateAnimator() and using animator-based classes.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1378216800000,
"created_by": 1,
"updated_at": 1378216804155,
"updated_by": 1,
"published_at": 1378216800000,
"published_by": 1
},
{
"id": 13,
"title": "Joda Time's Memory Issue in Android",
"slug": "joda_time_s_memory_issue_in_android",
"markdown": "I've recently gotten fed up with how nuts the built-in calendar library is for Java/Android. &nbsp;It's incredibly easy to make mistakes and it's unintuitive at best, so I've finally decided to take the plunge and switch to Joda time.\n\nJoda is like a dream come true* except for one fairly extreme memory issue that I ran into. &nbsp;After adding it to the app we started to see two huge memory sinks show up in [MAT](http://www.eclipse.org/mat/): a JarFile and a ZipFile that in our app took up a combined 4MB!\n\n<div class=\"separator\" style=\"clear: both; text-align: center;\">[![](http://2.bp.blogspot.com/--Mo2iMk-E34/UhN-jHzerDI/AAAAAAAABt4/JV2-9vsQTpk/s320/MAT.png)](http://2.bp.blogspot.com/--Mo2iMk-E34/UhN-jHzerDI/AAAAAAAABt4/JV2-9vsQTpk/s1600/MAT.png)</div>\n\nJoda's JAR is only half a meg, so how come these things took up so much space? &nbsp;Why didn't any other JARs take up this space? &nbsp;What's even stranger is that the amount of memory used seemed to scale based on the number of resources I had in the application; a simple test app only used up an extra 700kb, but Expedia's resource-heavy app took up the above.\n\nIt turns out the problem is [ClassLoader.getResourceAsStream()](http://developer.android.com/reference/java/lang/ClassLoader.html#getResourceAsStream(java.lang.String)). &nbsp;Joda time includes [the olson timezone database](http://en.wikipedia.org/wiki/Tz_database) in the JAR itself and loads the TZ data dynamically through getResourceAsStream(). &nbsp;For some reason getResourceAsStream() does some rather extreme caching and takes up a ton of memory if you use it**.\n\nThankfully there's a fairly simple solution. &nbsp;You can actually implement any timezone&nbsp;[Provider](http://www.joda.org/joda-time/apidocs/org/joda/time/tz/Provider.html) you want, circumventing the normal JAR-based [ZoneInfoProvider](http://www.joda.org/joda-time/apidocs/org/joda/time/tz/ZoneInfoProvider.html). &nbsp;Just make sure that your implementation has a default constructor and setup your system properties thus:\n\n<pre>System.setProperty(\"org.joda.time.DateTimeZone.Provider\",\n AssetZoneInfoProvider.class.getCanonicalName());</pre>\nAs such, I imported all of the TZ data (compiled, from the JAR) into my project's /assets/ directory. &nbsp;Then I took [the source for ZoneInfoProvider](https://github.com/JodaOrg/joda-time/blob/master/src/main/java/org/joda/time/tz/ZoneInfoProvider.java) and reworked it so that openResource() uses the AssetManager to retrieve data. &nbsp;I hooked it up and voila - no more excessive memory usage! &nbsp;As an added bonus, this makes it a lot easier to update your TZ data without relying on a new version of Joda time.\n\nAs an epilogue, if someone can explain why getResourceAsStream() causes the sadness it does I'd be interested to know. &nbsp;I tried looking into it for a bit but gave up because it wasn't like I would be able to change the system code anyways.\n\n_* Seriously: if you deal with dates, times, or some combination thereof at all, you will be doing yourself a favor by switching to Joda time._\n_\n__** What initially tipped me off was a Jackson XML post about the same problem:&nbsp;https://github.com/FasterXML/jackson-core/pull/49_",
"html": "I've recently gotten fed up with how nuts the built-in calendar library is for Java/Android. &nbsp;It's incredibly easy to make mistakes and it's unintuitive at best, so I've finally decided to take the plunge and switch to Joda time.<br /><br />Joda is like a dream come true* except for one fairly extreme memory issue that I ran into. &nbsp;After adding it to the app we started to see two huge memory sinks show up in <a href=\"http://www.eclipse.org/mat/\">MAT</a>: a JarFile and a ZipFile that in our app took up a combined 4MB!<br /><br /><div class=\"separator\" style=\"clear: both; text-align: center;\"><a href=\"http://2.bp.blogspot.com/--Mo2iMk-E34/UhN-jHzerDI/AAAAAAAABt4/JV2-9vsQTpk/s1600/MAT.png\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"><img border=\"0\" height=\"260\" src=\"http://2.bp.blogspot.com/--Mo2iMk-E34/UhN-jHzerDI/AAAAAAAABt4/JV2-9vsQTpk/s320/MAT.png\" width=\"320\" /></a></div><br /><br />Joda's JAR is only half a meg, so how come these things took up so much space? &nbsp;Why didn't any other JARs take up this space? &nbsp;What's even stranger is that the amount of memory used seemed to scale based on the number of resources I had in the application; a simple test app only used up an extra 700kb, but Expedia's resource-heavy app took up the above.<br /><br />It turns out the problem is <a href=\"http://developer.android.com/reference/java/lang/ClassLoader.html#getResourceAsStream(java.lang.String)\">ClassLoader.getResourceAsStream()</a>. &nbsp;Joda time includes <a href=\"http://en.wikipedia.org/wiki/Tz_database\">the olson timezone database</a> in the JAR itself and loads the TZ data dynamically through getResourceAsStream(). &nbsp;For some reason getResourceAsStream() does some rather extreme caching and takes up a ton of memory if you use it**.<br /><br />Thankfully there's a fairly simple solution. &nbsp;You can actually implement any timezone&nbsp;<a href=\"http://www.joda.org/joda-time/apidocs/org/joda/time/tz/Provider.html\">Provider</a> you want, circumventing the normal JAR-based <a href=\"http://www.joda.org/joda-time/apidocs/org/joda/time/tz/ZoneInfoProvider.html\">ZoneInfoProvider</a>. &nbsp;Just make sure that your implementation has a default constructor and setup your system properties thus:<br /><br /><pre>System.setProperty(\"org.joda.time.DateTimeZone.Provider\",<br /> AssetZoneInfoProvider.class.getCanonicalName());</pre><br />As such, I imported all of the TZ data (compiled, from the JAR) into my project's /assets/ directory. &nbsp;Then I took <a href=\"https://github.com/JodaOrg/joda-time/blob/master/src/main/java/org/joda/time/tz/ZoneInfoProvider.java\">the source for ZoneInfoProvider</a> and reworked it so that openResource() uses the AssetManager to retrieve data. &nbsp;I hooked it up and voila - no more excessive memory usage! &nbsp;As an added bonus, this makes it a lot easier to update your TZ data without relying on a new version of Joda time.<br /><br />As an epilogue, if someone can explain why getResourceAsStream() causes the sadness it does I'd be interested to know. &nbsp;I tried looking into it for a bit but gave up because it wasn't like I would be able to change the system code anyways.<br /><br /><i>* Seriously: if you deal with dates, times, or some combination thereof at all, you will be doing yourself a favor by switching to Joda time.</i><br /><i><br /></i><i>** What initially tipped me off was a Jackson XML post about the same problem:&nbsp;https://github.com/FasterXML/jackson-core/pull/49</i>",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1377007200000,
"created_by": 1,
"updated_at": 1377009467008,
"updated_by": 1,
"published_at": 1377007200000,
"published_by": 1
},
{
"id": 14,
"title": "Don't Override ListView.getAdapter()",
"slug": "don_t_override_list_view_get_adapter_",
"markdown": "A few days we ran into a bug. &nbsp;When we were updating the underlying data for the particular Adapter, the ListView would blow up with this exception:\n\n<pre>E/AndroidRuntime(1809): java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(16908298, class com.expedia.bookings.widget.ItinListView) with Adapter(class android.widget.HeaderViewListAdapter)]</pre>\nThe thing is, we weren't updating from a background thread. &nbsp;That exception is thrown when the # of items the ListView thinks the adapter has and the # it actually has are out of sync, but I couldn't see how that was happening. &nbsp;What was going on?\n\nIt turned out to be me overriding ListView.getAdapter(). &nbsp;There's some code I've been working with recently which has a custom ListView; inside of it is a custom Adapter. &nbsp;I wanted access to that Adapter (but not the ListAdapter wrappers that are sometimes added in the case of header/footer views), so I overrided ListView.getAdapter() and had it return the custom Adapter.\n<div>\n</div><div>However, the ListView uses getAdapter() sometimes to get the count for the # of items it has. &nbsp;By bypassing the wrapper ListAdapter, the count was sometimes wrong (since it wasn't accounting for header/footer Views).</div><div>\n</div><div>The moral of the story is: don't override ListView.getAdapter().</div>",
"html": "A few days we ran into a bug. &nbsp;When we were updating the underlying data for the particular Adapter, the ListView would blow up with this exception:<br /><br /><pre>E/AndroidRuntime(1809): java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(16908298, class com.expedia.bookings.widget.ItinListView) with Adapter(class android.widget.HeaderViewListAdapter)]</pre><br />The thing is, we weren't updating from a background thread. &nbsp;That exception is thrown when the # of items the ListView thinks the adapter has and the # it actually has are out of sync, but I couldn't see how that was happening. &nbsp;What was going on?<br /><br />It turned out to be me overriding ListView.getAdapter(). &nbsp;There's some code I've been working with recently which has a custom ListView; inside of it is a custom Adapter. &nbsp;I wanted access to that Adapter (but not the ListAdapter wrappers that are sometimes added in the case of header/footer views), so I overrided ListView.getAdapter() and had it return the custom Adapter.<br /><div><br /></div><div>However, the ListView uses getAdapter() sometimes to get the count for the # of items it has. &nbsp;By bypassing the wrapper ListAdapter, the count was sometimes wrong (since it wasn't accounting for header/footer Views).</div><div><br /></div><div>The moral of the story is: don't override ListView.getAdapter().</div>",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1372860000000,
"created_by": 1,
"updated_at": 1372860006748,
"updated_by": 1,
"published_at": 1372860000000,
"published_by": 1
},
{
"id": 15,
"title": "How to Correctly Format Date/Time Strings on Android",
"slug": "how_to_correctly_format_date_time_strings_on_android",
"markdown": "One aspect of internationalization is to correctly format your date/time strings. &nbsp;Different countries use very different formats and it's easy to incorrectly format your strings for your international users.\n\nYour first foray into formatting date/times is probably through&nbsp;[java.text.DateFormat](http://developer.android.com/reference/java/text/DateFormat.html) (via [SimpleDateFormat](http://developer.android.com/reference/java/text/SimpleDateFormat.html)):\n\n<pre>Calendar cal = new GregorianCalendar(2013, 11, 20);\nDateFormat df = new SimpleDateFormat(\"yyyy-MM-dd\");\nString date = df.format(cal.getTime());\n// date == \"2013-12-20\"</pre>\nWhile this works great for formatting parameters (for, say, a web service), it's terrible for localization. &nbsp;Your international users won't be using the same date/time format you're using and it won't pick up user preferences (e.g., date order or 12-hour vs 24-hour).\n\nA more correct way of doing it is to use&nbsp;[android.text.format.DateFormat](http://android.text.format.dateformat/) (not to be confused with the previous DateFormat). &nbsp;There are some methods here that return formatters defined by the system's locale, like&nbsp;[getDateFormat()](http://developer.android.com/reference/android/text/format/DateFormat.html#getDateFormat(android.content.Context)) and&nbsp;[getTimeFormat()](http://developer.android.com/reference/android/text/format/DateFormat.html#getTimeFormat(android.content.Context))&nbsp;(among others):\n\n<pre>Calendar cal = new GregorianCalendar(2013, 11, 20);\nDateFormat df = android.text.format.DateFormat.getDateFormat(this); \nString date = df.format(cal.getTime());\n// date == \"12/20/2013\"</pre>\nThe problem with these formatters is that they are inflexible; what if you don't want to show a year on a date? &nbsp;What if you want to include the day of the week? &nbsp;There are only limited circumstances where these formatters are good enough.\n\n**The best solution is to use [DateUtils](http://developer.android.com/reference/android/text/format/DateUtils.html).** &nbsp;It has two powerful methods - [formatDateTime()](http://developer.android.com/reference/android/text/format/DateUtils.html#formatDateTime(android.content.Context, long, int)) and [formatDateRange()](http://developer.android.com/reference/android/text/format/DateUtils.html#formatDateRange(android.content.Context, long, long, int)) - which take in flags to determine which fields to include. &nbsp;It automatically formats to the user's locale and preferences without you having to worry about it.\n\n**DateUtils.formatDateTime() formats a single point in time.** &nbsp;Here's a few examples:\n\n<pre>Calendar cal = new GregorianCalendar(2013, 11, 20);\nString date = DateUtils.formatDateTime(this, cal.getTimeInMillis(), DateUtils.FORMAT_SHOW_DATE);\n// date == \"December 20\"\ndate = DateUtils.formatDateTime(this, cal.getTimeInMillis(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE | DateUtils.FORMAT_SHOW_YEAR);\n// date == \"12/20/2013\"\ndate = DateUtils.formatDateTime(this, cal.getTimeInMillis(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE | DateUtils.FORMAT_SHOW_TIME);\n// date == \"00:00, 12/20/2013\"</pre>\n**DateUtils.formatDateRange() formats a range**, like \"Jan 5 - Feb 12\". &nbsp;Why might you want to use this instead of just concatenating two calls to formatDateTime()? &nbsp;Besides being easier, it can optimize output in certain circumstances by reducing redundant field usage, like months/years when they don't change throughout the range:\n\n<pre>Calendar cal1 = new GregorianCalendar(2013, 11, 20);\nCalendar cal2 = new GregorianCalendar(2013, 11, 25);\nCalendar cal3 = new GregorianCalendar(2014, 0, 5);\nString date = DateUtils.formatDateRange(this, cal1.getTimeInMillis(), cal2.getTimeInMillis(), DateUtils.FORMAT_SHOW_DATE);\n// date == \"December 20 - 24\"\ndate = DateUtils.formatDateRange(this, cal1.getTimeInMillis(), cal3.getTimeInMillis(), DateUtils.FORMAT_SHOW_DATE);\n// date == \"December 20, 2013 - January 4, 2014\"</pre>\nOne thing to watch out for with formatDateRange() is where it cuts off the day. &nbsp;You may notice in the example above that the date ranges seem to be off by one day; that's because it cuts off at midnight. &nbsp;If you add a millisecond it should properly format the range.\n\nIf you want your application to abide by the locale's formatting rules while still having control over what information to show, DateUtils is your place to go. &nbsp;Be sure to read through all the different formatting flags so you can wield the most power with this tool.\n\n(One final note - the example code above shows output in my locale. &nbsp;In your locale it may differ - this is on purpose, of course!)",
"html": "One aspect of internationalization is to correctly format your date/time strings. &nbsp;Different countries use very different formats and it's easy to incorrectly format your strings for your international users.<br /><br />Your first foray into formatting date/times is probably through&nbsp;<a href=\"http://developer.android.com/reference/java/text/DateFormat.html\">java.text.DateFormat</a> (via <a href=\"http://developer.android.com/reference/java/text/SimpleDateFormat.html\">SimpleDateFormat</a>):<br /><br /><pre>Calendar cal = new GregorianCalendar(2013, 11, 20);<br />DateFormat df = new SimpleDateFormat(\"yyyy-MM-dd\");<br />String date = df.format(cal.getTime());<br />// date == \"2013-12-20\"</pre><br />While this works great for formatting parameters (for, say, a web service), it's terrible for localization. &nbsp;Your international users won't be using the same date/time format you're using and it won't pick up user preferences (e.g., date order or 12-hour vs 24-hour).<br /><br />A more correct way of doing it is to use&nbsp;<a href=\"http://android.text.format.dateformat/\">android.text.format.DateFormat</a> (not to be confused with the previous DateFormat). &nbsp;There are some methods here that return formatters defined by the system's locale, like&nbsp;<a href=\"http://developer.android.com/reference/android/text/format/DateFormat.html#getDateFormat(android.content.Context)\">getDateFormat()</a> and&nbsp;<a href=\"http://developer.android.com/reference/android/text/format/DateFormat.html#getTimeFormat(android.content.Context)\">getTimeFormat()</a>&nbsp;(among others):<br /><br /><pre>Calendar cal = new GregorianCalendar(2013, 11, 20);<br />DateFormat df = android.text.format.DateFormat.getDateFormat(this); <br />String date = df.format(cal.getTime());<br />// date == \"12/20/2013\"</pre><br />The problem with these formatters is that they are inflexible; what if you don't want to show a year on a date? &nbsp;What if you want to include the day of the week? &nbsp;There are only limited circumstances where these formatters are good enough.<br /><br /><b>The best solution is to use <a href=\"http://developer.android.com/reference/android/text/format/DateUtils.html\">DateUtils</a>.</b> &nbsp;It has two powerful methods - <a href=\"http://developer.android.com/reference/android/text/format/DateUtils.html#formatDateTime(android.content.Context, long, int)\">formatDateTime()</a> and <a href=\"http://developer.android.com/reference/android/text/format/DateUtils.html#formatDateRange(android.content.Context, long, long, int)\">formatDateRange()</a> - which take in flags to determine which fields to include. &nbsp;It automatically formats to the user's locale and preferences without you having to worry about it.<br /><br /><b>DateUtils.formatDateTime() formats a single point in time.</b> &nbsp;Here's a few examples:<br /><br /><pre>Calendar cal = new GregorianCalendar(2013, 11, 20);<br />String date = DateUtils.formatDateTime(this, cal.getTimeInMillis(), DateUtils.FORMAT_SHOW_DATE);<br />// date == \"December 20\"<br />date = DateUtils.formatDateTime(this, cal.getTimeInMillis(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE | DateUtils.FORMAT_SHOW_YEAR);<br />// date == \"12/20/2013\"<br />date = DateUtils.formatDateTime(this, cal.getTimeInMillis(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE | DateUtils.FORMAT_SHOW_TIME);<br />// date == \"00:00, 12/20/2013\"</pre><br /><b>DateUtils.formatDateRange() formats a range</b>, like \"Jan 5 - Feb 12\". &nbsp;Why might you want to use this instead of just concatenating two calls to formatDateTime()? &nbsp;Besides being easier, it can optimize output in certain circumstances by reducing redundant field usage, like months/years when they don't change throughout the range:<br /><br /><pre>Calendar cal1 = new GregorianCalendar(2013, 11, 20);<br />Calendar cal2 = new GregorianCalendar(2013, 11, 25);<br />Calendar cal3 = new GregorianCalendar(2014, 0, 5);<br />String date = DateUtils.formatDateRange(this, cal1.getTimeInMillis(), cal2.getTimeInMillis(), DateUtils.FORMAT_SHOW_DATE);<br />// date == \"December 20 - 24\"<br />date = DateUtils.formatDateRange(this, cal1.getTimeInMillis(), cal3.getTimeInMillis(), DateUtils.FORMAT_SHOW_DATE);<br />// date == \"December 20, 2013 - January 4, 2014\"</pre><br />One thing to watch out for with formatDateRange() is where it cuts off the day. &nbsp;You may notice in the example above that the date ranges seem to be off by one day; that's because it cuts off at midnight. &nbsp;If you add a millisecond it should properly format the range.<br /><br />If you want your application to abide by the locale's formatting rules while still having control over what information to show, DateUtils is your place to go. &nbsp;Be sure to read through all the different formatting flags so you can wield the most power with this tool.<br /><br />(One final note - the example code above shows output in my locale. &nbsp;In your locale it may differ - this is on purpose, of course!)",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1372345200000,
"created_by": 1,
"updated_at": 1372345200015,
"updated_by": 1,
"published_at": 1372345200000,
"published_by": 1
},
{
"id": 16,
"title": "Sentinels of the Multiverse Randomizer App",
"slug": "sentinels_of_the_multiverse_randomizer_app",
"markdown": "My latest side project is a randomizer application for the board game [Sentinels of the Multiverse](http://sentinelsofthemultiverse.com/).\n\nYou can grab the app here: [https://play.google.com/store/apps/details?id=com.idunnolol.sotm](https://play.google.com/store/apps/details?id=com.idunnolol.sotm)\n\nYou can check out the source here:&nbsp;[https://github.com/dlew/android-sotm](https://github.com/dlew/android-sotm)\n\nI have to admit that writing it was a gigantic waste of time (the benefit is&nbsp;minuscule&nbsp;in comparison to the time it took to write). &nbsp;However, it was a &nbsp;ton of fun to make; there's something very liberating about writing an app from scratch with no baggage to worry about. &nbsp;It was also liberating to write an app that uses modern APIs with complete disregard to backwards compatibility. &nbsp;As such, it's only available on ICS+.\n\nIn other news, I will be at Google I/O again this week. &nbsp;In particular I will be helping man Expedia's booth in the Android sandbox; feel free to come by and say hello.",
"html": "My latest side project is a randomizer application for the board game <a href=\"http://sentinelsofthemultiverse.com/\">Sentinels of the Multiverse</a>.<br /><br />You can grab the app here: <a href=\"https://play.google.com/store/apps/details?id=com.idunnolol.sotm\">https://play.google.com/store/apps/details?id=com.idunnolol.sotm</a><br /><br />You can check out the source here:&nbsp;<a href=\"https://github.com/dlew/android-sotm\">https://github.com/dlew/android-sotm</a><br /><br />I have to admit that writing it was a gigantic waste of time (the benefit is&nbsp;minuscule&nbsp;in comparison to the time it took to write). &nbsp;However, it was a &nbsp;ton of fun to make; there's something very liberating about writing an app from scratch with no baggage to worry about. &nbsp;It was also liberating to write an app that uses modern APIs with complete disregard to backwards compatibility. &nbsp;As such, it's only available on ICS+.<br /><br />In other news, I will be at Google I/O again this week. &nbsp;In particular I will be helping man Expedia's booth in the Android sandbox; feel free to come by and say hello.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1368536400000,
"created_by": 1,
"updated_at": 1386865995327,
"updated_by": 1,
"published_at": 1368536400000,
"published_by": 1
},
{
"id": 17,
"title": "Before & After",
"slug": "before_after",
"markdown": "I attend weekly trivia nights with friends. &nbsp;One of the categories, Before &amp; After, has piqued my interest. &nbsp;It works like this: two movies are described, and you have to name both movies. &nbsp;What makes it a bit easier is that the two movies share a common combining word. &nbsp;Here are a few examples:\n\n<div style=\"background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 13px;\">\n\n* Men in Black Swan\n* Sling Blade Runner\n* Law Abiding Citizen Kane\n* My Fair Lady and the Tramp\n* Batman &amp; Robin Hood\n* A Walk to Remember the Titans<div>\nI find the answers to be fairly amusing, so I wrote a program that generates before &amp; afters.\n\nYou can find [the source code here](https://github.com/dlew/python-before-and-after).\n\nI've pumped out [a spreadsheet of results (for movies) here](https://docs.google.com/spreadsheet/ccc?key=0Akr7dePVHYBNdHB3OU1hVzhObWNaZXVPX1ZXRVRteXc&amp;usp=sharing).</div></div>\nI used a word list to discover words in common between the start/end of movie names. &nbsp;For finding the common word, I generated both [a forwards and a backwards trie](http://en.wikipedia.org/wiki/Trie) of the first/last word of each movie name. &nbsp;Tries are pretty much the best for simple text searches.\n\nUltimately, the program is general enough that it could work on anything. &nbsp;The main reason I focused on movies was because IMDB is good enough to dump their ratings data, which helped immensely for sussing out good vs. bad results. &nbsp;I found the best way to rank results was a combination of the # of voters (showing popularity of both items) and the difference in their rating (in that combining two items with vastly different ratings is hilarious).\n\nThere was one problem I could not overcome (since I was putting relatively minimal effort into this venture), which is determining when a word was part of a compound word or not. &nbsp;For example, I would want to match \"ball\" in \"basketball\" because \"basketball\" is a compound word, but I wouldn't want to match \"all\" in \"hall\". &nbsp;Solving this problem would a word list with more data than the word itself, so I just skipped it.",
"html": "I attend weekly trivia nights with friends. &nbsp;One of the categories, Before &amp; After, has piqued my interest. &nbsp;It works like this: two movies are described, and you have to name both movies. &nbsp;What makes it a bit easier is that the two movies share a common combining word. &nbsp;Here are a few examples:<br /><br /><div style=\"background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 13px;\"><ul><li>Men in Black Swan</li><li>Sling Blade Runner</li><li>Law Abiding Citizen Kane</li><li>My Fair Lady and the Tramp</li><li>Batman &amp; Robin Hood</li><li>A Walk to Remember the Titans</li></ul><div><br />I find the answers to be fairly amusing, so I wrote a program that generates before &amp; afters.<br /><br />You can find <a href=\"https://github.com/dlew/python-before-and-after\">the source code here</a>.<br /><br />I've pumped out <a href=\"https://docs.google.com/spreadsheet/ccc?key=0Akr7dePVHYBNdHB3OU1hVzhObWNaZXVPX1ZXRVRteXc&amp;usp=sharing\">a spreadsheet of results (for movies) here</a>.</div></div><br />I used a word list to discover words in common between the start/end of movie names. &nbsp;For finding the common word, I generated both <a href=\"http://en.wikipedia.org/wiki/Trie\">a forwards and a backwards trie</a> of the first/last word of each movie name. &nbsp;Tries are pretty much the best for simple text searches.<br /><br />Ultimately, the program is general enough that it could work on anything. &nbsp;The main reason I focused on movies was because IMDB is good enough to dump their ratings data, which helped immensely for sussing out good vs. bad results. &nbsp;I found the best way to rank results was a combination of the # of voters (showing popularity of both items) and the difference in their rating (in that combining two items with vastly different ratings is hilarious).<br /><br />There was one problem I could not overcome (since I was putting relatively minimal effort into this venture), which is determining when a word was part of a compound word or not. &nbsp;For example, I would want to match \"ball\" in \"basketball\" because \"basketball\" is a compound word, but I wouldn't want to match \"all\" in \"hall\". &nbsp;Solving this problem would a word list with more data than the word itself, so I just skipped it.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1367330400000,
"created_by": 1,
"updated_at": 1367330403429,
"updated_by": 1,
"published_at": 1367330400000,
"published_by": 1
},
{
"id": 18,
"title": "Memory Management: A Case Study",
"slug": "memory_management_a_case_study",
"markdown": "During the development of the most recent version of&nbsp;[Expedia's Android app](https://play.google.com/store/apps/details?id=com.expedia.bookings)&nbsp;we&nbsp;ran into a variety of memory problems. &nbsp;I thought I'd share some details about the problems we ran into and how we solved them.\n\n**Memory Analyzer Tool (MAT)**\n\nIf you're not familiar with&nbsp;[Eclipse's MAT](http://android-developers.blogspot.com/2011/03/memory-analysis-for-android.html)&nbsp;you should be. &nbsp;MAT should be your first stop for dealing with memory problems. &nbsp;Not only is it useful for finding out what's hogging memory, it can also be used to find memory leaks.\n\nAn important note about using MAT - almost all memory problems I've run into relate to Bitmaps. &nbsp;In versions of Android previous to 3.x, Bitmaps were stored in native memory (rather than the heap) and thus not viewable in MAT. &nbsp;This makes it much harder to debug memory problems on 2.x devices, so you might want to stick to 4.x devices for investigating memory issues.\n<div class=\"p1\">\n</div><div class=\"p1\">**High-Resolution Bitmaps**\n\nBitmaps in memory are uncompressed (even if they were compressed in your APK). &nbsp;This can cause serious issues if you have high-resolution assets. &nbsp;For example, we had tablet backgrounds which were the full resolution of the N10 (2560x1600). &nbsp;That's fine with the N10's beefy heap size, but when scaled down to smaller devices (like the N7) the scaled image would take up 1/8th of the app's memory! &nbsp;Imagine doing that multiple times and you can see why we ran into memory issues.</div><div class=\"p1\">\n</div><div class=\"p1\">We solved this problem one of two ways: first, we reduced the resolution of the asset. &nbsp;Some of these backgrounds were blurred, meaning we could lower the resolution greatly without losing quality. &nbsp;When we couldn't lower the resolution without quality suffering greatly, we would sometimes replace the normal asset with a backup color (when we detected low memory situations).</div><div class=\"p1\">\n</div><div class=\"p1\">**BitmapFactory.decodeResource()**\n\nWhen you're decoding resources yourself (rather than using something like ImageView.setImageResource()), there are a couple things to look out for.\n\nIf you're decoding the _same_ resource over and over again, you might want to cache it. &nbsp;This problem hit us because we had an ImageView in a list show a default asset before we load an image from the network. &nbsp;If you scrolled through a list quickly, and each one is loading its own default asset, you could create a burst of memory usage that runs you out of memory. &nbsp;By caching this default, we not only saved memory but also improved performance.</div><div class=\"p1\">\n</div><div class=\"p1\">Another issue we ran into with decodeResource() involves device density and BitmapFactory.Options. &nbsp;If you are using them you should know that the default is to not auto-scale the asset at all. &nbsp;So if you've only got an xhdpi version of the asset on an mdpi device, you're going to load them in at xhdpi size, taking up more memory than you expected. &nbsp;So make sure to set that if you're manually loading assets with Options. &nbsp;(If you're not passing BitmapFactory.Options you don't need to worry, as the default decodeResources() handles density for you.)</div><div class=\"p1\">\n</div><div class=\"p1\">**LruCache**\n\nHaving [an in-memory LruCache of Bitmap](http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html#memory-cache)s loaded from the network is all the rage these days. However, it can easily lull you into a false sense of security. &nbsp;Just because you've limited your Bitmap cache doesn't mean you'll never run out of memory! &nbsp;If your LruCache is 1/4th the size of available memory, but your app (at one point) needs all of it not to crash... well, you've got a problem.</div><div class=\"p1\">\n</div><div class=\"p1\">Things got better for us once we started manually clearing the LruCache at key moments. &nbsp;Having a [DiskLruCache](https://github.com/JakeWharton/DiskLruCache) helps a lot if you do this, as you can clear the memory cache but then quickly reload images if you need to without going to the network.</div><div class=\"p1\">\n</div><div class=\"p1\">**Resources and sPreloadedDrawables**\n_\n__This is a red herring!_ &nbsp;You may see in MAT that Resources is taking up a whole ton of memory with a variable called sPreloadedDrawables. &nbsp;Unfortunately, you can't avoid sPreloadedDrawables; it's a pre-defined set of system resources that are preloaded into memory for every app. &nbsp;Don't spend any time thinking about them.</div><div class=\"p1\">\n</div><div class=\"p1\">**Recommendation**</div><div class=\"p1\">\n</div><div class=\"p1\">Overall, **what you should do is find an old phone and use it as your primary development device**. &nbsp;That way you know from the start that your app runs on all phones. &nbsp;It's much harder to discover these limitations later on.</div><div class=\"p1\">\n</div><div class=\"p1\">For example, the Nexus 4 (my primary device) has a whopping 192MB of memory. &nbsp;Even with all xhdpi assets that thing is difficult to run out of memory on a standard app. &nbsp;Compare that to what QA was using - devices with 24MB to 32MB. &nbsp;It's a very different game when you're trying to design a beautiful app to run in 24MB on hdpi!</div>",
"html": "During the development of the most recent version of&nbsp;<a href=\"https://play.google.com/store/apps/details?id=com.expedia.bookings\">Expedia's Android app</a>&nbsp;we&nbsp;ran into a variety of memory problems. &nbsp;I thought I'd share some details about the problems we ran into and how we solved them.<br /><br /><b>Memory Analyzer Tool (MAT)</b><br /><br />If you're not familiar with&nbsp;<a href=\"http://android-developers.blogspot.com/2011/03/memory-analysis-for-android.html\">Eclipse's MAT</a>&nbsp;you should be. &nbsp;MAT should be your first stop for dealing with memory problems. &nbsp;Not only is it useful for finding out what's hogging memory, it can also be used to find memory leaks.<br /><br />An important note about using MAT - almost all memory problems I've run into relate to Bitmaps. &nbsp;In versions of Android previous to 3.x, Bitmaps were stored in native memory (rather than the heap) and thus not viewable in MAT. &nbsp;This makes it much harder to debug memory problems on 2.x devices, so you might want to stick to 4.x devices for investigating memory issues.<br /><div class=\"p1\"><br /></div><div class=\"p1\"><b>High-Resolution Bitmaps</b><br /><br />Bitmaps in memory are uncompressed (even if they were compressed in your APK). &nbsp;This can cause serious issues if you have high-resolution assets. &nbsp;For example, we had tablet backgrounds which were the full resolution of the N10 (2560x1600). &nbsp;That's fine with the N10's beefy heap size, but when scaled down to smaller devices (like the N7) the scaled image would take up 1/8th of the app's memory! &nbsp;Imagine doing that multiple times and you can see why we ran into memory issues.</div><div class=\"p1\"><br /></div><div class=\"p1\">We solved this problem one of two ways: first, we reduced the resolution of the asset. &nbsp;Some of these backgrounds were blurred, meaning we could lower the resolution greatly without losing quality. &nbsp;When we couldn't lower the resolution without quality suffering greatly, we would sometimes replace the normal asset with a backup color (when we detected low memory situations).</div><div class=\"p1\"><br /></div><div class=\"p1\"><b>BitmapFactory.decodeResource()</b><br /><br />When you're decoding resources yourself (rather than using something like ImageView.setImageResource()), there are a couple things to look out for.<br /><br />If you're decoding the <i>same</i> resource over and over again, you might want to cache it. &nbsp;This problem hit us because we had an ImageView in a list show a default asset before we load an image from the network. &nbsp;If you scrolled through a list quickly, and each one is loading its own default asset, you could create a burst of memory usage that runs you out of memory. &nbsp;By caching this default, we not only saved memory but also improved performance.</div><div class=\"p1\"><br /></div><div class=\"p1\">Another issue we ran into with decodeResource() involves device density and BitmapFactory.Options. &nbsp;If you are using them you should know that the default is to not auto-scale the asset at all. &nbsp;So if you've only got an xhdpi version of the asset on an mdpi device, you're going to load them in at xhdpi size, taking up more memory than you expected. &nbsp;So make sure to set that if you're manually loading assets with Options. &nbsp;(If you're not passing BitmapFactory.Options you don't need to worry, as the default decodeResources() handles density for you.)</div><div class=\"p1\"><br /></div><div class=\"p1\"><b>LruCache</b><br /><br />Having <a href=\"http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html#memory-cache\">an in-memory LruCache of Bitmap</a>s loaded from the network is all the rage these days. However, it can easily lull you into a false sense of security. &nbsp;Just because you've limited your Bitmap cache doesn't mean you'll never run out of memory! &nbsp;If your LruCache is 1/4th the size of available memory, but your app (at one point) needs all of it not to crash... well, you've got a problem.</div><div class=\"p1\"><br /></div><div class=\"p1\">Things got better for us once we started manually clearing the LruCache at key moments. &nbsp;Having a <a href=\"https://github.com/JakeWharton/DiskLruCache\">DiskLruCache</a> helps a lot if you do this, as you can clear the memory cache but then quickly reload images if you need to without going to the network.</div><div class=\"p1\"><br /></div><div class=\"p1\"><b>Resources and sPreloadedDrawables</b><br /><i><br /></i><i>This is a red herring!</i> &nbsp;You may see in MAT that Resources is taking up a whole ton of memory with a variable called sPreloadedDrawables. &nbsp;Unfortunately, you can't avoid sPreloadedDrawables; it's a pre-defined set of system resources that are preloaded into memory for every app. &nbsp;Don't spend any time thinking about them.</div><div class=\"p1\"><br /></div><div class=\"p1\"><b>Recommendation</b></div><div class=\"p1\"><br /></div><div class=\"p1\">Overall, <b>what you should do is find an old phone and use it as your primary development device</b>. &nbsp;That way you know from the start that your app runs on all phones. &nbsp;It's much harder to discover these limitations later on.</div><div class=\"p1\"><br /></div><div class=\"p1\">For example, the Nexus 4 (my primary device) has a whopping 192MB of memory. &nbsp;Even with all xhdpi assets that thing is difficult to run out of memory on a standard app. &nbsp;Compare that to what QA was using - devices with 24MB to 32MB. &nbsp;It's a very different game when you're trying to design a beautiful app to run in 24MB on hdpi!</div>",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1365519600000,
"created_by": 1,
"updated_at": 1365519608689,
"updated_by": 1,
"published_at": 1365519600000,
"published_by": 1
},
{
"id": 19,
"title": "Automatically Managing Bitmaps from URLs via UrlBitmapDrawable",
"slug": "automatically_managing_bitmaps_from_urls_via_url_bitmap_drawable",
"markdown": "If you develop apps, you'll probably (at some point) need to load images from the internet. &nbsp;Sometimes you'll load many images at once, as in a ListView or Gallery. &nbsp;Your first foray will be easy, using BitmapFactory to decode a stream - then you run into the dreaded OutOfMemory error and are suddenly grounded back to the reality that is limited memory space. \n\nThere are two equally important problems to handle when using images: loading an image to view it, and unloading it later to save memory. &nbsp;Last time I looked there were plenty of libraries out there for solving the first problem, but I was unsatisfied with their solutions to the second. &nbsp;A lot of them simply blow away loaded Bitmaps at some point in time - but what if you still wanted to use it? &nbsp;Then you end up in this complex tightrope walk, where you're having to constantly check and re-check your Bitmaps for whether they still exist. &nbsp;It's a gigantic pain and I've been doing this dance forever.\n\nI set out to solve the problem in a better way, such that it would do three things:\n\n1\\. Load images from a URL into a View.\n\n2\\. Unload that image later (for memory's sake).\n\n3\\. Re-load that URL into the View if we ever see it again.\n\nI was able to accomplish all three with the help of a class I wrote, UrlBitmapDrawable.\n\n# **Introducing UrlBitmapDrawable**\n\nYou can check out the code here:&nbsp;[https://gist.github.com/dlew/69e6557604926d7e1513](https://gist.github.com/dlew/69e6557604926d7e1513)\n\nYou can use it just about anywhere as a Drawable. &nbsp;Just instantiate it then use it:\n\n<pre>UrlBitmapDrawable drawable = new UrlBitmapDrawable(res, myUrl, myFallback);\nmyView.setBackgroundDrawable(drawable);</pre>\nWith ImageViews there's a bit of a hack I needed to do (in order not to have to use a custom ImageView). &nbsp;So I setup another method for using UrlBitmapDrawable with ImageViews:\n\n<pre>UrlBitmapDrawable.loadImageView(myImageUrl, myImageView, myFallback);</pre><pre></pre>\n\n# **Highlights**\n\nThis solution has made my life easier in four ways:\n**\n****It's Simple**&nbsp;- All you need to is provide it a URL and it takes care of the rest. &nbsp;You don't ever have to worry about its state; if the underlying Bitmap is recycled, it will fallback to the default image and start reloading the URL.\n\n**It's a Drawable** - By making it a Drawable, it meant I could attach it to any View. &nbsp;Tying it to a custom View would have vastly limited its potential.\n\n**It's Compatible** - It's not tied to any particular implementation for loading images. &nbsp;Retrieving images could be a simple network call, or you could hook it up to a complex LRU memory/disk cache.\n\n**It's Extensible** - The version I've provided is simple; internally we've added some bells and whistles to it. &nbsp;See \"Areas for Improvement\" below.\n\n# **Disadvantages**\n\nIt's not all sunshine and daisies. &nbsp;There are two problems with UrlBitmapDrawable; however, I considered them minor in comparison to the larger problem I was trying to solve.\n\n**BitmapDrawable**&nbsp;- BitmapDrawable does not let you access the underlying Bitmap by default, so you'll have to import your own version that opens it up. &nbsp;[Here's the source code from github](https://github.com/android/platform_frameworks_base/blob/master/graphics/java/android/graphics/drawable/BitmapDrawable.java).\n\n**ImageView Hack** - In order to get ImageView to re-measure the Drawable's width/height after loading you have to trick it into thinking the Drawable has changed (by nulling it then resetting it back). &nbsp;To be honest, there might be a better solution here, but I haven't found it.\n\n# **Areas for Improvement**\n\nHere's ways that we've tricked out our UrlBitmapDrawable:\n\n**Default Resources via Id** - A default resource is important (so we can show the user something before we load the asset). &nbsp;In the sample code the UrlBitmapDrawable holds a Bitmap; this is a fine example, but if you're inflating a new default Bitmap per UrlBitmapDrawable, that can wreak its own memory havoc.\n\nInternally, we've gone a more complex route which uses Resources and resIds, and loads the Bitmap automatically from an in-memory cache. &nbsp;It keeps us from spending a lot of time (and memory) reloading the same default bitmaps.\n\n**Fallback URLs** - We are sometimes given a list of URLs at differing quality levels. &nbsp;It's pretty easy to hook that into this system; each time a download fails, try the next URL.\n\n**Recycling Bitmaps**&nbsp;- If you read the code carefully you may notice that I never actually dealt with the second step - unloading Bitmaps from memory. &nbsp;We use an LruCache to handle this; as a result of UrlBitmapDrawable it can recycle Bitmaps with impunity. &nbsp;It also means you can evict the entire cache at any time if you need the memory.",
"html": "If you develop apps, you'll probably (at some point) need to load images from the internet. &nbsp;Sometimes you'll load many images at once, as in a ListView or Gallery. &nbsp;Your first foray will be easy, using BitmapFactory to decode a stream - then you run into the dreaded OutOfMemory error and are suddenly grounded back to the reality that is limited memory space. <br /><br />There are two equally important problems to handle when using images: loading an image to view it, and unloading it later to save memory. &nbsp;Last time I looked there were plenty of libraries out there for solving the first problem, but I was unsatisfied with their solutions to the second. &nbsp;A lot of them simply blow away loaded Bitmaps at some point in time - but what if you still wanted to use it? &nbsp;Then you end up in this complex tightrope walk, where you're having to constantly check and re-check your Bitmaps for whether they still exist. &nbsp;It's a gigantic pain and I've been doing this dance forever.<br /><br />I set out to solve the problem in a better way, such that it would do three things:<br /><br />1. Load images from a URL into a View.<br /><br />2. Unload that image later (for memory's sake).<br /><br />3. Re-load that URL into the View if we ever see it again.<br /><br />I was able to accomplish all three with the help of a class I wrote, UrlBitmapDrawable.<br /><br /><h1><b>Introducing UrlBitmapDrawable</b></h1><br />You can check out the code here:&nbsp;<a href=\"https://gist.github.com/dlew/69e6557604926d7e1513\">https://gist.github.com/dlew/69e6557604926d7e1513</a><br /><br />You can use it just about anywhere as a Drawable. &nbsp;Just instantiate it then use it:<br /><br /><pre>UrlBitmapDrawable drawable = new UrlBitmapDrawable(res, myUrl, myFallback);<br />myView.setBackgroundDrawable(drawable);</pre><br />With ImageViews there's a bit of a hack I needed to do (in order not to have to use a custom ImageView). &nbsp;So I setup another method for using UrlBitmapDrawable with ImageViews:<br /><br /><pre>UrlBitmapDrawable.loadImageView(myImageUrl, myImageView, myFallback);</pre><pre></pre><h1><b>Highlights</b></h1><br />This solution has made my life easier in four ways:<br /><b><br /></b><b>It's Simple</b>&nbsp;- All you need to is provide it a URL and it takes care of the rest. &nbsp;You don't ever have to worry about its state; if the underlying Bitmap is recycled, it will fallback to the default image and start reloading the URL.<br /><br /><b>It's a Drawable</b> - By making it a Drawable, it meant I could attach it to any View. &nbsp;Tying it to a custom View would have vastly limited its potential.<br /><br /><b>It's Compatible</b> - It's not tied to any particular implementation for loading images. &nbsp;Retrieving images could be a simple network call, or you could hook it up to a complex LRU memory/disk cache.<br /><br /><b>It's Extensible</b> - The version I've provided is simple; internally we've added some bells and whistles to it. &nbsp;See \"Areas for Improvement\" below.<br /><br /><h1><b>Disadvantages</b></h1><br />It's not all sunshine and daisies. &nbsp;There are two problems with UrlBitmapDrawable; however, I considered them minor in comparison to the larger problem I was trying to solve.<br /><br /><b>BitmapDrawable</b>&nbsp;- BitmapDrawable does not let you access the underlying Bitmap by default, so you'll have to import your own version that opens it up. &nbsp;<a href=\"https://github.com/android/platform_frameworks_base/blob/master/graphics/java/android/graphics/drawable/BitmapDrawable.java\">Here's the source code from github</a>.<br /><br /><b>ImageView Hack</b> - In order to get ImageView to re-measure the Drawable's width/height after loading you have to trick it into thinking the Drawable has changed (by nulling it then resetting it back). &nbsp;To be honest, there might be a better solution here, but I haven't found it.<br /><br /><h1><b>Areas for Improvement</b></h1><br />Here's ways that we've tricked out our UrlBitmapDrawable:<br /><br /><b>Default Resources via Id</b> - A default resource is important (so we can show the user something before we load the asset). &nbsp;In the sample code the UrlBitmapDrawable holds a Bitmap; this is a fine example, but if you're inflating a new default Bitmap per UrlBitmapDrawable, that can wreak its own memory havoc.<br /><br />Internally, we've gone a more complex route which uses Resources and resIds, and loads the Bitmap automatically from an in-memory cache. &nbsp;It keeps us from spending a lot of time (and memory) reloading the same default bitmaps.<br /><br /><b>Fallback URLs</b> - We are sometimes given a list of URLs at differing quality levels. &nbsp;It's pretty easy to hook that into this system; each time a download fails, try the next URL.<br /><br /><b>Recycling Bitmaps</b>&nbsp;- If you read the code carefully you may notice that I never actually dealt with the second step - unloading Bitmaps from memory. &nbsp;We use an LruCache to handle this; as a result of UrlBitmapDrawable it can recycle Bitmaps with impunity. &nbsp;It also means you can evict the entire cache at any time if you need the memory.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1364918400000,
"created_by": 1,
"updated_at": 1364918935457,
"updated_by": 1,
"published_at": 1364918400000,
"published_by": 1
},
{
"id": 20,
"title": "Is Your AsyncTask Running?",
"slug": "is_your_async_task_running_",
"markdown": "A short note about AsyncTask: Prior to 4.0 (and maybe prior to 3.0, but I haven't tested), [AsyncTask.getStatus()](http://developer.android.com/reference/android/os/AsyncTask.html#getStatus()) might lie to you. If the AsyncTask is canceled, it won't set the status correctly; instead, it will remain RUNNING far after AsyncTask.onCancelled() finishes.\n\nMy initial thought was to use [AsyncTask.isCancelled()](http://developer.android.com/reference/android/os/AsyncTask.html#isCancelled()), but you can run into some concurrency issues there if you're trying to gauge whether the AsyncTask is done from another thread. &nbsp;A cancelled AsyncTask doesn't necessarily end the moment you cancel it; in fact, if you're not checking isCancelled() regularly in doInBackground() then you can end up having the AsyncTask run for a while after you cancel.\n\nMy solution is to set a boolean at the end of onCancelled() that will indicate to the system that you got to the end of execution. &nbsp;Here's an example of writing an AsyncTask where you can properly know when it's been finished:\n\n<pre>private class MyAsyncTask extends AsyncTask<void void=\"\"> {\n private boolean mFinishedCancel = false;\n\n protected Void doInBackground(Void... params) {\n return null; // You'd normally do something here\n }\n\n protected void onCancelled() {\n mFinishedCancel = true;\n }\n\n public boolean isFinished() {\n return getStatus() == Status.FINISHED || mFinishedCancel;\n }\n}</void></pre>",
"html": "A short note about AsyncTask: Prior to 4.0 (and maybe prior to 3.0, but I haven't tested), <a href=\"http://developer.android.com/reference/android/os/AsyncTask.html#getStatus()\">AsyncTask.getStatus()</a> might lie to you. If the AsyncTask is canceled, it won't set the status correctly; instead, it will remain RUNNING far after AsyncTask.onCancelled() finishes.<br /><br />My initial thought was to use <a href=\"http://developer.android.com/reference/android/os/AsyncTask.html#isCancelled()\">AsyncTask.isCancelled()</a>, but you can run into some concurrency issues there if you're trying to gauge whether the AsyncTask is done from another thread. &nbsp;A cancelled AsyncTask doesn't necessarily end the moment you cancel it; in fact, if you're not checking isCancelled() regularly in doInBackground() then you can end up having the AsyncTask run for a while after you cancel.<br /><br />My solution is to set a boolean at the end of onCancelled() that will indicate to the system that you got to the end of execution. &nbsp;Here's an example of writing an AsyncTask where you can properly know when it's been finished:<br /><br /><pre>private class MyAsyncTask extends AsyncTask<void void=\"\"> {<br /> private boolean mFinishedCancel = false;<br /><br /> protected Void doInBackground(Void... params) {<br /> return null; // You'd normally do something here<br /> }<br /><br /> protected void onCancelled() {<br /> mFinishedCancel = true;<br /> }<br /><br /> public boolean isFinished() {<br /> return getStatus() == Status.FINISHED || mFinishedCancel;<br /> }<br />}</void></pre>",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1363788000000,
"created_by": 1,
"updated_at": 1363788464515,
"updated_by": 1,
"published_at": 1363788000000,
"published_by": 1
},
{
"id": 21,
"title": "Easier View State Saving",
"slug": "easier_view_state_saving",
"markdown": "If you write your own custom Views you may eventually want to leverage [onSaveInstanceState()](http://developer.android.com/reference/android/view/View.html#onSaveInstanceState()) and [onRestoreInstanceState()](http://developer.android.com/reference/android/view/View.html#onRestoreInstanceState(android.os.Parcelable)) to store some data relating to the View. &nbsp;Unlike Activity/Fragment, which use Bundle to pass around the instance state, Views use Parcelables for their instance state.\n\nParcelable is fast, efficient, and kind of a pain in the ass to setup. &nbsp;It's doubly painful for custom Views as you have to ensure that you're properly saving the superclass' state as well in your own Parcelable. &nbsp;The boilerplate code is excessive.\n\nIt turns out there's a much easier way which leverages these two points:\n\n1. **Bundles implement Parcelable.** &nbsp;This means you can use a Bundle instead of a custom Parcelable as your instance state.\n2. **Bundles can store Parcelables.** &nbsp;This means you can preserve the superclass' state in your Bundle.\nHere's a simple implementation of the concept:\n<pre>public class CustomView extends View {\n public CustomView(Context context) {\n super(context);\n }\n\n @Override\n protected Parcelable onSaveInstanceState() {\n Bundle bundle = new Bundle();\n bundle.putParcelable(\"superState\", super.onSaveInstanceState());\n // Put whatever you want into the Bundle here\n return bundle;\n }\n\n @Override\n protected void onRestoreInstanceState(Parcelable state) {\n Bundle bundle = (Bundle) state;\n super.onRestoreInstanceState(bundle.getParcelable(\"superState\"));\n // Restore what you put into the bundle here\n }\n}</pre>\nAt this point you can store any primitives in a Bundle as you normally would in an Activity/Fragment. &nbsp;Plus, if you use this trick many times you could even wrap it in a subclass of View (and simply replace the default instance state with a Bundle version of it).",
"html": "If you write your own custom Views you may eventually want to leverage <a href=\"http://developer.android.com/reference/android/view/View.html#onSaveInstanceState()\">onSaveInstanceState()</a> and <a href=\"http://developer.android.com/reference/android/view/View.html#onRestoreInstanceState(android.os.Parcelable)\">onRestoreInstanceState()</a> to store some data relating to the View. &nbsp;Unlike Activity/Fragment, which use Bundle to pass around the instance state, Views use Parcelables for their instance state.<br /><br />Parcelable is fast, efficient, and kind of a pain in the ass to setup. &nbsp;It's doubly painful for custom Views as you have to ensure that you're properly saving the superclass' state as well in your own Parcelable. &nbsp;The boilerplate code is excessive.<br /><br />It turns out there's a much easier way which leverages these two points:<br /><br /><ol><li><b>Bundles implement Parcelable.</b> &nbsp;This means you can use a Bundle instead of a custom Parcelable as your instance state.</li><li><b>Bundles can store Parcelables.</b> &nbsp;This means you can preserve the superclass' state in your Bundle.</li></ol><br />Here's a simple implementation of the concept:<br /><pre>public class CustomView extends View {<br /> public CustomView(Context context) {<br /> super(context);<br /> }<br /><br /> @Override<br /> protected Parcelable onSaveInstanceState() {<br /> Bundle bundle = new Bundle();<br /> bundle.putParcelable(\"superState\", super.onSaveInstanceState());<br /> // Put whatever you want into the Bundle here<br /> return bundle;<br /> }<br /><br /> @Override<br /> protected void onRestoreInstanceState(Parcelable state) {<br /> Bundle bundle = (Bundle) state;<br /> super.onRestoreInstanceState(bundle.getParcelable(\"superState\"));<br /> // Restore what you put into the bundle here<br /> }<br />}</pre><br />At this point you can store any primitives in a Bundle as you normally would in an Activity/Fragment. &nbsp;Plus, if you use this trick many times you could even wrap it in a subclass of View (and simply replace the default instance state with a Bundle version of it).",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1363100400000,
"created_by": 1,
"updated_at": 1363100400952,
"updated_by": 1,
"published_at": 1363100400000,
"published_by": 1
},
{
"id": 22,
"title": "Resistance/Avalon App",
"slug": "resistance_avalon_app",
"markdown": "I've once again taken a detour from my more serious Android development to do some silly side projects.\n\nThe first of them is an app for the board game [The Resistance](http://boardgamegeek.com/boardgame/41114/the-resistance) and [The Resistance: Avalon](http://boardgamegeek.com/boardgame/128882/the-resistance-avalon). &nbsp;I've recently become obsessed with this game because it's just a ton of fun. &nbsp;The game involves a lot of hidden roles, so there's a lengthy boot-up sequence where each person's allegiances are determined. &nbsp;When you use all the roles available, it gets to be a bit of chore. &nbsp;So I've written a dumb app that uses Android's TTS to speak the setup out loud, making the process a tiny bit easier.\n\nThe application can be found here:&nbsp;[https://play.google.com/store/apps/details?id=com.idunnolol.resistance](https://play.google.com/store/apps/details?id=com.idunnolol.resistance)\n\nOpen source code here:&nbsp;[https://github.com/dlew/android-resistance](https://github.com/dlew/android-resistance)\n\nAs is usually the case with side projects, the time I put into the project vastly outweighs the time I'll ever save by using the app. &nbsp;As such, I took this as an opportunity to try out two things: Android's TextToSpeech capabilities, and Maven Android builds.\n\n**TextToSpeech**\n\nI found [TextToSpeech](http://developer.android.com/reference/android/speech/tts/TextToSpeech.html) to be far easier to use than I expected. &nbsp;It took me almost no time to get it up and running. &nbsp;The only snag I ran into was using the [OnUtteranceCompletedListener](http://developer.android.com/reference/android/speech/tts/TextToSpeech.OnUtteranceCompletedListener.html). &nbsp;You need to give an utterance id to something you play before the listener will fire:\n\n<pre>HashMap&lt;String, String&gt; params = new HashMap&lt;String, String&gt;();\nendParams.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, \"myUtteranceId\");\nmTTS.speak(\"Say Something\", TextToSpeech.QUEUE_ADD, params);</pre>\n**Maven Android Builds**\n**\n**I've been woefully behind the times with regards to Android build technology. &nbsp;For years I've seen open source github projects using Maven but I've always ignored it because I'm scared of the big angry pom.xml files. &nbsp;So I determined that I would use this simple app to teach myself Maven (via [maven-android-plugin](https://code.google.com/p/maven-android-plugin/)).\n\nI found the initial setup of Maven to be pretty simple. &nbsp;I had the samples up and running in no time using the \"getting started\" section of the site. &nbsp;I even got Eclipse building the application using Maven using [m2e-android](http://rgladwell.github.com/m2e-android/). &nbsp;So far so good.\n\nI ran into a brick wall when I tried to add a library (in particular,&nbsp;[ActionBarSherlock](http://actionbarsherlock.com/)). &nbsp;The command line Maven worked just fine when I added the library dependency, but I happen to enjoy the amenities of a modern IDE so it must work in Eclipse. &nbsp;But in Eclipse, it wouldn't build - it complained about a missing dependency. &nbsp;[It turns out that you need to still manually do stuff for each library anyways if you're using Eclipse + Maven](https://github.com/rgladwell/m2e-android/issues/106)&nbsp;(unless I'm mis-reading the state of apklib, which is entirely possible). &nbsp;Wasn't that the whole reason I started to use Maven in the first place? &nbsp;To simplify my build process?\n\nI think I'll keep making pom.xml for command line building/testing, but for actual dev in Eclipse it actually sets me back to use Maven. &nbsp;Perhaps it integrates better with IntelliJ? &nbsp;That alone may be reason to switch. &nbsp;But at this point I'm far more excited for [the upcoming Gradle builds](http://tools.android.com/tech-docs/new-build-system).\n\n**One More Thing**\n\nIf there was one cool thing I did with the code, it was the setup of Config.java. &nbsp;Originally I had it with a bunch of booleans, one for each option; but this led to a lot of switch-like code that just felt repetitive. By converting it to an enum keyed-boolean store, I was able to automate a lot of app. &nbsp;I always love it when you can greatly simplify and condense the code at the same time.",
"html": "I've once again taken a detour from my more serious Android development to do some silly side projects.<br /><br />The first of them is an app for the board game <a href=\"http://boardgamegeek.com/boardgame/41114/the-resistance\">The Resistance</a> and <a href=\"http://boardgamegeek.com/boardgame/128882/the-resistance-avalon\">The Resistance: Avalon</a>. &nbsp;I've recently become obsessed with this game because it's just a ton of fun. &nbsp;The game involves a lot of hidden roles, so there's a lengthy boot-up sequence where each person's allegiances are determined. &nbsp;When you use all the roles available, it gets to be a bit of chore. &nbsp;So I've written a dumb app that uses Android's TTS to speak the setup out loud, making the process a tiny bit easier.<br /><br />The application can be found here:&nbsp;<a href=\"https://play.google.com/store/apps/details?id=com.idunnolol.resistance\">https://play.google.com/store/apps/details?id=com.idunnolol.resistance</a><br /><br />Open source code here:&nbsp;<a href=\"https://github.com/dlew/android-resistance\">https://github.com/dlew/android-resistance</a><br /><br />As is usually the case with side projects, the time I put into the project vastly outweighs the time I'll ever save by using the app. &nbsp;As such, I took this as an opportunity to try out two things: Android's TextToSpeech capabilities, and Maven Android builds.<br /><br /><b>TextToSpeech</b><br /><br />I found <a href=\"http://developer.android.com/reference/android/speech/tts/TextToSpeech.html\">TextToSpeech</a> to be far easier to use than I expected. &nbsp;It took me almost no time to get it up and running. &nbsp;The only snag I ran into was using the <a href=\"http://developer.android.com/reference/android/speech/tts/TextToSpeech.OnUtteranceCompletedListener.html\">OnUtteranceCompletedListener</a>. &nbsp;You need to give an utterance id to something you play before the listener will fire:<br /><br /><pre>HashMap&lt;String, String&gt; params = new HashMap&lt;String, String&gt;();<br />endParams.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, \"myUtteranceId\");<br />mTTS.speak(\"Say Something\", TextToSpeech.QUEUE_ADD, params);</pre><br /><b>Maven Android Builds</b><br /><b><br /></b>I've been woefully behind the times with regards to Android build technology. &nbsp;For years I've seen open source github projects using Maven but I've always ignored it because I'm scared of the big angry pom.xml files. &nbsp;So I determined that I would use this simple app to teach myself Maven (via <a href=\"https://code.google.com/p/maven-android-plugin/\">maven-android-plugin</a>).<br /><br />I found the initial setup of Maven to be pretty simple. &nbsp;I had the samples up and running in no time using the \"getting started\" section of the site. &nbsp;I even got Eclipse building the application using Maven using <a href=\"http://rgladwell.github.com/m2e-android/\">m2e-android</a>. &nbsp;So far so good.<br /><br />I ran into a brick wall when I tried to add a library (in particular,&nbsp;<a href=\"http://actionbarsherlock.com/\">ActionBarSherlock</a>). &nbsp;The command line Maven worked just fine when I added the library dependency, but I happen to enjoy the amenities of a modern IDE so it must work in Eclipse. &nbsp;But in Eclipse, it wouldn't build - it complained about a missing dependency. &nbsp;<a href=\"https://github.com/rgladwell/m2e-android/issues/106\">It turns out that you need to still manually do stuff for each library anyways if you're using Eclipse + Maven</a>&nbsp;(unless I'm mis-reading the state of apklib, which is entirely possible). &nbsp;Wasn't that the whole reason I started to use Maven in the first place? &nbsp;To simplify my build process?<br /><br />I think I'll keep making pom.xml for command line building/testing, but for actual dev in Eclipse it actually sets me back to use Maven. &nbsp;Perhaps it integrates better with IntelliJ? &nbsp;That alone may be reason to switch. &nbsp;But at this point I'm far more excited for <a href=\"http://tools.android.com/tech-docs/new-build-system\">the upcoming Gradle builds</a>.<br /><br /><b>One More Thing</b><br /><br />If there was one cool thing I did with the code, it was the setup of Config.java. &nbsp;Originally I had it with a bunch of booleans, one for each option; but this led to a lot of switch-like code that just felt repetitive. By converting it to an enum keyed-boolean store, I was able to automate a lot of app. &nbsp;I always love it when you can greatly simplify and condense the code at the same time.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1361894400000,
"created_by": 1,
"updated_at": 1386865965021,
"updated_by": 1,
"published_at": 1361894400000,
"published_by": 1
},
{
"id": 23,
"title": "Why Do Motorola's ListViews Look Different",
"slug": "why_do_motorola_s_list_views_look_different",
"markdown": "There was a helpful article \"[Why Does My ListView Look Different?](http://community.developer.motorola.com/t5/MOTODEV-Blog/Why-Does-My-ListView-Look-Different/bc-p/18521)\" that Motorola posted a few years ago. &nbsp;Unfortunately it has disappeared from the internet, as you might tell by clicking on the link. &nbsp;It had some crucial information on fixing a weirdness for Motorola devices that I wanted to preserve for posterity (in case anyone else starts looking for it).\n\nEssentially, when you're on some Motorola devices, the bottom of the ListView has a shadow on it by default. &nbsp;In addition to that, if the ListView is supposed to take up the entire screen (even if it's not full), it doesn't. &nbsp;Here's a screenshot of the bug in action:\n<span id=\"goog_1973239922\"></span><span id=\"goog_1973239923\"></span>\n<div class=\"separator\" style=\"clear: both; text-align: center;\">[![](http://2.bp.blogspot.com/-d1DoEWw9drs/UKKbWTZggpI/AAAAAAAAArg/B7qZ4cUxLR4/s320/38_PM-2.png)](http://2.bp.blogspot.com/-d1DoEWw9drs/UKKbWTZggpI/AAAAAAAAArg/B7qZ4cUxLR4/s1600/38_PM-2.png)</div>\nThe problem is android:overScrollFooter. &nbsp;Motorola has a default one set and it causes sadness. &nbsp;To get rid of it, set android:overScrollFooter=\"@null\" in your ListView. &nbsp;For bonus points, set it in a style and set that as your theme's default ListView so you never have to deal with this problem again.",
"html": "There was a helpful article \"<a href=\"http://community.developer.motorola.com/t5/MOTODEV-Blog/Why-Does-My-ListView-Look-Different/bc-p/18521\">Why Does My ListView Look Different?</a>\" that Motorola posted a few years ago. &nbsp;Unfortunately it has disappeared from the internet, as you might tell by clicking on the link. &nbsp;It had some crucial information on fixing a weirdness for Motorola devices that I wanted to preserve for posterity (in case anyone else starts looking for it).<br /><br />Essentially, when you're on some Motorola devices, the bottom of the ListView has a shadow on it by default. &nbsp;In addition to that, if the ListView is supposed to take up the entire screen (even if it's not full), it doesn't. &nbsp;Here's a screenshot of the bug in action:<br /><span id=\"goog_1973239922\"></span><span id=\"goog_1973239923\"></span><br /><div class=\"separator\" style=\"clear: both; text-align: center;\"><a href=\"http://2.bp.blogspot.com/-d1DoEWw9drs/UKKbWTZggpI/AAAAAAAAArg/B7qZ4cUxLR4/s1600/38_PM-2.png\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"><img border=\"0\" height=\"320\" src=\"http://2.bp.blogspot.com/-d1DoEWw9drs/UKKbWTZggpI/AAAAAAAAArg/B7qZ4cUxLR4/s320/38_PM-2.png\" width=\"187\" /></a></div><br />The problem is android:overScrollFooter. &nbsp;Motorola has a default one set and it causes sadness. &nbsp;To get rid of it, set android:overScrollFooter=\"@null\" in your ListView. &nbsp;For bonus points, set it in a style and set that as your theme's default ListView so you never have to deal with this problem again.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1353423600000,
"created_by": 1,
"updated_at": 1353423600621,
"updated_by": 1,
"published_at": 1353423600000,
"published_by": 1
},
{
"id": 24,
"title": "The Unknown Style: actionBarWidgetTheme",
"slug": "the_unknown_style_action_bar_widget_theme",
"markdown": "One of the cooler features I've found in the Android Action Bar is grouped menu items. &nbsp;If you group together a series of menu items in a submenu, you get a pretty popup of those items. &nbsp;For example, if you set a submenu with&nbsp;android:checkableBehavior<span class=\"s1\">=</span><span class=\"s2\">\"single\" then it'll have a radio button next to each item in the popup menu:</span>\n<span class=\"s2\">\n</span>\n<div class=\"separator\" style=\"clear: both; text-align: center;\">[![](http://1.bp.blogspot.com/-xUR9UcGGvME/UJ0vjoWLfAI/AAAAAAAAAo0/sEGyb1Bg6lI/s320/device-2012-11-09-102933.png)](http://1.bp.blogspot.com/-xUR9UcGGvME/UJ0vjoWLfAI/AAAAAAAAAo0/sEGyb1Bg6lI/s1600/device-2012-11-09-102933.png)</div><span class=\"s2\">\n</span><span class=\"s2\">I wanted to reskin the RadioButton so that they all looked Holo, even on versions using ActionBarSherlock. &nbsp;Naturally, I turned to my theme and set the radioButtonStyle. &nbsp;However, the code below did not work:</span>\n<pre>&lt;style name=\"MyTheme\" parent=\"@android:style/Theme.Holo.Light.DarkActionBar\"&gt;\n &lt;item name=\"android:radioButtonStyle\"&gt;@style/MyRadioButtonStyle&lt;/item&gt;\n&lt;/style&gt;\n\n&lt;style name=\"MyRadioButtonStyle\" parent=\"@android:style/Widget.CompoundButton.RadioButton\"&gt;\n &lt;item name=\"android:button\"&gt;@drawable/my_radio_button&lt;/item&gt;\n&lt;/style&gt;</pre>\nI was fairly lost for a few hours because radioButtonStyle was clearly working on everything _except_ for the widget popup. &nbsp;I could insert RadioButtons into my Activity and they'd pick up the new style, but the old style would remain for the action bar. &nbsp;What was going on?\n\n**The culprit is android:actionBarWidgetTheme.**\n\nIntroduced in API 14, what it does is let you style Views inflated by the action bar separately from the rest of your Application or Activity. &nbsp;This is a neat trick, but if you don't know it exists, you could easily get lost on why your styles aren't applying to action bar Views.\n\nIf android:actionBarWidgetTheme is undefined, it falls back to the current theme's values. &nbsp;For most Android themes, that means you're fine. &nbsp;But in the case of&nbsp;Theme.Holo.Light.DarkActionBar, it does set the actionBarWidgetTheme to \"@android:style/Theme.Holo\". &nbsp;As a result, it will not fallback to your theme's default value.\n\nI solved the problem by setting my own actionBarWidgetTheme that is a sub-style of the original actionBarWidgetTheme:\n\n<pre>&lt;style name=\"MyTheme\" parent=\"@android:style/Theme.Holo.Light.DarkActionBar\"&gt;\n &lt;item name=\"android:actionBarWidgetTheme\"&gt;@style/MyActionBarWidgetTheme&lt;/item&gt;\n&lt;/style&gt;\n\n&lt;style name=\"MyActionBarWidgetTheme\" parent=\"@android:style/Theme.Holo\"&gt;\n &lt;item name=\"android:radioButtonStyle\"&gt;@style/MyRadioButtonStyle&lt;/item&gt;\n&lt;/style&gt;</pre>\nIt's important to properly parent the actionBarWidgetTheme with whatever the theme was previously setting as its parent; otherwise you may miss out on some styling elsewhere.",
"html": "One of the cooler features I've found in the Android Action Bar is grouped menu items. &nbsp;If you group together a series of menu items in a submenu, you get a pretty popup of those items. &nbsp;For example, if you set a submenu with&nbsp;android:checkableBehavior<span class=\"s1\">=</span><span class=\"s2\">\"single\" then it'll have a radio button next to each item in the popup menu:</span><br /><span class=\"s2\"><br /></span><br /><div class=\"separator\" style=\"clear: both; text-align: center;\"><a href=\"http://1.bp.blogspot.com/-xUR9UcGGvME/UJ0vjoWLfAI/AAAAAAAAAo0/sEGyb1Bg6lI/s1600/device-2012-11-09-102933.png\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"><img border=\"0\" height=\"177\" src=\"http://1.bp.blogspot.com/-xUR9UcGGvME/UJ0vjoWLfAI/AAAAAAAAAo0/sEGyb1Bg6lI/s320/device-2012-11-09-102933.png\" width=\"320\" /></a></div><span class=\"s2\"><br /></span><span class=\"s2\">I wanted to reskin the RadioButton so that they all looked Holo, even on versions using ActionBarSherlock. &nbsp;Naturally, I turned to my theme and set the radioButtonStyle. &nbsp;However, the code below did not work:</span><br /><pre>&lt;style name=\"MyTheme\" parent=\"@android:style/Theme.Holo.Light.DarkActionBar\"&gt;<br /> &lt;item name=\"android:radioButtonStyle\"&gt;@style/MyRadioButtonStyle&lt;/item&gt;<br />&lt;/style&gt;<br /><br />&lt;style name=\"MyRadioButtonStyle\" parent=\"@android:style/Widget.CompoundButton.RadioButton\"&gt;<br /> &lt;item name=\"android:button\"&gt;@drawable/my_radio_button&lt;/item&gt;<br />&lt;/style&gt;</pre><br />I was fairly lost for a few hours because radioButtonStyle was clearly working on everything <i>except</i> for the widget popup. &nbsp;I could insert RadioButtons into my Activity and they'd pick up the new style, but the old style would remain for the action bar. &nbsp;What was going on?<br /><br /><b>The culprit is android:actionBarWidgetTheme.</b><br /><br />Introduced in API 14, what it does is let you style Views inflated by the action bar separately from the rest of your Application or Activity. &nbsp;This is a neat trick, but if you don't know it exists, you could easily get lost on why your styles aren't applying to action bar Views.<br /><br />If android:actionBarWidgetTheme is undefined, it falls back to the current theme's values. &nbsp;For most Android themes, that means you're fine. &nbsp;But in the case of&nbsp;Theme.Holo.Light.DarkActionBar, it does set the actionBarWidgetTheme to \"@android:style/Theme.Holo\". &nbsp;As a result, it will not fallback to your theme's default value.<br /><br />I solved the problem by setting my own actionBarWidgetTheme that is a sub-style of the original actionBarWidgetTheme:<br /><br /><pre>&lt;style name=\"MyTheme\" parent=\"@android:style/Theme.Holo.Light.DarkActionBar\"&gt;<br /> &lt;item name=\"android:actionBarWidgetTheme\"&gt;@style/MyActionBarWidgetTheme&lt;/item&gt;<br />&lt;/style&gt;<br /><br />&lt;style name=\"MyActionBarWidgetTheme\" parent=\"@android:style/Theme.Holo\"&gt;<br /> &lt;item name=\"android:radioButtonStyle\"&gt;@style/MyRadioButtonStyle&lt;/item&gt;<br />&lt;/style&gt;</pre><br />It's important to properly parent the actionBarWidgetTheme with whatever the theme was previously setting as its parent; otherwise you may miss out on some styling elsewhere.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1352736000000,
"created_by": 1,
"updated_at": 1352736001273,
"updated_by": 1,
"published_at": 1352736000000,
"published_by": 1
},
{
"id": 25,
"title": "Styling an AutoCompleteTextView",
"slug": "styling_an_auto_complete_text_view",
"markdown": "I ran into some confusion recently styling some AutoCompleteTextViews. &nbsp;An AutoCompleteTextView is a compound View - it's got both an EditText component and a floating dropdown component. &nbsp;The former is rather straightforward to style, by the dropdown is difficult because it's a mixture of attributes on the AutoCompleteTextView itself and styles set in the theme via android:dropDownListViewStyle.\n\nFor example, if you want to setup a custom background on the dropdown, you do it in the AutoCompleteTextView:\n\n<pre>&lt;AutoCompleteTextView\n android:layout_width=\"match_parent\"\n android:layout_height=\"wrap_content\"\n android:popupBackground=\"@drawable/bg_autocomplete\" /&gt;</pre>\nBut if you want to change the dividers, you have to create a theme and point that to a style, which isn't an immediately obvious solution:\n\n<pre>&lt;style name=\"MyTheme\"&gt;\n &lt;item name=\"android:dropDownListViewStyle\"&gt;@style/DropDownListViewStyle&lt;/item&gt;\n&lt;/style&gt;\n\n&lt;style name=\"DropDownListViewStyle\"&gt;\n &lt;item name=\"android:divider\"&gt;#4F4F4F&lt;/item&gt;\n &lt;item name=\"android:dividerHeight\"&gt;1dp&lt;/item&gt;\n&lt;/style&gt;</pre>\nThe worst is when attributes in the AutoCompleteTextView and normal ListView styles collide. &nbsp;I made the mistake of assuming that since it adopts a ListView-like style, it would adopt all ListView attributes - like android:listSelector. &nbsp;The below, however, **does not work**:\n\n<pre>&lt;style name=\"DropDownListViewStyle\"&gt;\n &lt;item name=\"android:listSelector\"&gt;@drawable/list_selector&lt;/item&gt;\n&lt;/style&gt;</pre>\nInstead, AutoCompleteTextView has its own attribute, android:dropDownSelector. &nbsp;You have to set it like this:\n\n<pre>&lt;AutoCompleteTextView\n android:layout_width=\"match_parent\"\n android:layout_height=\"wrap_content\"\n android:dropDownSelector=\"@drawable/list_selector\" /&gt;</pre>",
"html": "I ran into some confusion recently styling some AutoCompleteTextViews. &nbsp;An AutoCompleteTextView is a compound View - it's got both an EditText component and a floating dropdown component. &nbsp;The former is rather straightforward to style, by the dropdown is difficult because it's a mixture of attributes on the AutoCompleteTextView itself and styles set in the theme via android:dropDownListViewStyle.<br /><br />For example, if you want to setup a custom background on the dropdown, you do it in the AutoCompleteTextView:<br /><br /><pre>&lt;AutoCompleteTextView<br /> android:layout_width=\"match_parent\"<br /> android:layout_height=\"wrap_content\"<br /> android:popupBackground=\"@drawable/bg_autocomplete\" /&gt;</pre><br />But if you want to change the dividers, you have to create a theme and point that to a style, which isn't an immediately obvious solution:<br /><br /><pre>&lt;style name=\"MyTheme\"&gt;<br /> &lt;item name=\"android:dropDownListViewStyle\"&gt;@style/DropDownListViewStyle&lt;/item&gt;<br />&lt;/style&gt;<br /><br />&lt;style name=\"DropDownListViewStyle\"&gt;<br /> &lt;item name=\"android:divider\"&gt;#4F4F4F&lt;/item&gt;<br /> &lt;item name=\"android:dividerHeight\"&gt;1dp&lt;/item&gt;<br />&lt;/style&gt;</pre><br />The worst is when attributes in the AutoCompleteTextView and normal ListView styles collide. &nbsp;I made the mistake of assuming that since it adopts a ListView-like style, it would adopt all ListView attributes - like android:listSelector. &nbsp;The below, however, <b>does not work</b>:<br /><br /><pre>&lt;style name=\"DropDownListViewStyle\"&gt;<br /> &lt;item name=\"android:listSelector\"&gt;@drawable/list_selector&lt;/item&gt;<br />&lt;/style&gt;</pre><br />Instead, AutoCompleteTextView has its own attribute, android:dropDownSelector. &nbsp;You have to set it like this:<br /><br /><pre>&lt;AutoCompleteTextView<br /> android:layout_width=\"match_parent\"<br /> android:layout_height=\"wrap_content\"<br /> android:dropDownSelector=\"@drawable/list_selector\" /&gt;</pre>",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1352476800000,
"created_by": 1,
"updated_at": 1352476805251,
"updated_by": 1,
"published_at": 1352476800000,
"published_by": 1
},
{
"id": 26,
"title": "The Case of the Twin onSurfaceChanged() and the Split Action Bar",
"slug": "the_case_of_the_twin_on_surface_changed_and_the_split_action_bar",
"markdown": "There's a funny little timing problem I ran into recently I'd like to share regarding window size and split action bars.\n\nIn an app I've got a loading screen that displays as we're making network requests. &nbsp;It's a cute SurfaceView with some animation to keep users amused. &nbsp;I'd written most of the initialization of assets inside of onSurfaceChanged() because I wanted to pre-scale everything to the exact size of the surface.\n\nBut a problem arose - for some reason onSurfaceChanged() was being called twice (and only when in portrait, not in landscape). &nbsp;This was troublesome because it's somewhat a substantial method due to all the initialization. &nbsp;What was happening?\n\nIt turns out that the split action bar was the culprit. &nbsp;Here's how things went down:\n\n1\\. In onCreate(), add the SurfaceView to the view hierarchy.\n\n2\\. SurfaceView.onSurfaceChanged() would be called.\n\n3\\. onCreateOptionsMenu() would then be called. &nbsp;Since I had&nbsp;splitActionBarWhenNarrow set for the Activity, this would create the split action bar.\n\n4\\. Due to the split action bar, the window size would change. &nbsp;SurfaceView.onSurfaceChanged() would be called a second time.\n\nThe solution was to move the addition of the Fragment with the SurfaceView somewhere after onCreateOptionsMenu(). &nbsp;I put it in onPostResume() (but make sure to call it only once on initialization).\n\nThere is one alternative solution, which is to call invalidateOptionsMenu() (or supportInvalidateOptionsMenu(), if you're using the [support library](http://developer.android.com/tools/extras/support-library.html)) during onCreate(). &nbsp;This will force onCreateOptionsMenu() to be called early. &nbsp;I dislike this answer because it screws up the normal lifecycle for menu creation and can therefore readily cause confusing issues down the line.\n ",
"html": "There's a funny little timing problem I ran into recently I'd like to share regarding window size and split action bars.<br /><br />In an app I've got a loading screen that displays as we're making network requests. &nbsp;It's a cute SurfaceView with some animation to keep users amused. &nbsp;I'd written most of the initialization of assets inside of onSurfaceChanged() because I wanted to pre-scale everything to the exact size of the surface.<br /><br />But a problem arose - for some reason onSurfaceChanged() was being called twice (and only when in portrait, not in landscape). &nbsp;This was troublesome because it's somewhat a substantial method due to all the initialization. &nbsp;What was happening?<br /><br />It turns out that the split action bar was the culprit. &nbsp;Here's how things went down:<br /><br />1. In onCreate(), add the SurfaceView to the view hierarchy.<br /><br />2. SurfaceView.onSurfaceChanged() would be called.<br /><br />3. onCreateOptionsMenu() would then be called. &nbsp;Since I had&nbsp;splitActionBarWhenNarrow set for the Activity, this would create the split action bar.<br /><br />4. Due to the split action bar, the window size would change. &nbsp;SurfaceView.onSurfaceChanged() would be called a second time.<br /><br />The solution was to move the addition of the Fragment with the SurfaceView somewhere after onCreateOptionsMenu(). &nbsp;I put it in onPostResume() (but make sure to call it only once on initialization).<br /><br />There is one alternative solution, which is to call invalidateOptionsMenu() (or supportInvalidateOptionsMenu(), if you're using the <a href=\"http://developer.android.com/tools/extras/support-library.html\">support library</a>) during onCreate(). &nbsp;This will force onCreateOptionsMenu() to be called early. &nbsp;I dislike this answer because it screws up the normal lifecycle for menu creation and can therefore readily cause confusing issues down the line.<br /> ",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1347289200000,
"created_by": 1,
"updated_at": 1347289201705,
"updated_by": 1,
"published_at": 1347289200000,
"published_by": 1
},
{
"id": 27,
"title": "Manually Adding the Legacy Overflow Button when targetSdkVersion >= 14",
"slug": "manually_adding_the_legacy_overflow_button_when_target_sdk_version_14",
"markdown": "My company is in the process of converting our apps to use action bars, but we're not quite there yet. &nbsp;In the meantime, we've depended on the legacy overflow button on devices without a dedicated menu button:\n\n<div class=\"separator\" style=\"clear: both; text-align: center;\">[![](http://1.bp.blogspot.com/-u-3KNfy5n9M/TyG235X2rGI/AAAAAAAABHM/g_qGEXBdJW8/s320/image00.png)](http://1.bp.blogspot.com/-u-3KNfy5n9M/TyG235X2rGI/AAAAAAAABHM/g_qGEXBdJW8/s1600/image00.png)</div>\n\nA problem has arisen because we've bumped our [targetSdkVersion](http://developer.android.com/guide/topics/manifest/uses-sdk-element.html) up to 16 (Jelly Bean). &nbsp;It turns out&nbsp;[there is a specific set of rules for when the legacy overflow button appears](http://android-developers.blogspot.com/2012/01/say-goodbye-to-menu-button.html). &nbsp;Our app was depending on the fact that our minSdkVersion was less than 10 and that our targetSdkVersion was between 11 and 13\\. &nbsp;By bumping our targetSdkVersion up to 16, we no longer got the legacy overflow button.\n\nThis situation wouldn't be a problem if we showed an action bar, since the overflow menu would just appear there. &nbsp;However, we're using a theme that disables the title, so our menu items disappeared completely.\n\nI want to emphasize that **the correct solution is to use an action bar with an overflow button**. &nbsp;But we're not done with the conversion to action bars yet and during development we'll want that menu to be accessible (all of our debug options go in there). &nbsp;So I came up with a small hack that lets us enable the legacy overflow button manually.\n\nIt turns out there is a hidden Window flag - WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY - that determines whether the legacy overflow button is shown or not. &nbsp;By using reflection, we can retrieve this field and add it to the Window's flags:\n\n<pre>public static void addLegacyOverflowButton(Window window) {\n if (window.peekDecorView() == null) {\n throw new RuntimeException(\"Must call addLegacyOverflowButton() after setContentView()\");\n }\n\n try {\n window.addFlags(WindowManager.LayoutParams.class.getField(\"FLAG_NEEDS_MENU_KEY\").getInt(null));\n }\n catch (NoSuchFieldException e) {\n // Ignore since this field won't exist in most versions of Android\n }\n catch (IllegalAccessException e) {\n Log.w(TAG, \"Could not access FLAG_NEEDS_MENU_KEY in addLegacyOverflowButton()\", e);\n }\n}</pre>\nI added the RuntimeException above because you need to call this after the decor View is set (or else it does nothing).",
"html": "My company is in the process of converting our apps to use action bars, but we're not quite there yet. &nbsp;In the meantime, we've depended on the legacy overflow button on devices without a dedicated menu button:<br /><br /><div class=\"separator\" style=\"clear: both; text-align: center;\"><a href=\"http://1.bp.blogspot.com/-u-3KNfy5n9M/TyG235X2rGI/AAAAAAAABHM/g_qGEXBdJW8/s1600/image00.png\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"><img border=\"0\" height=\"39\" src=\"http://1.bp.blogspot.com/-u-3KNfy5n9M/TyG235X2rGI/AAAAAAAABHM/g_qGEXBdJW8/s320/image00.png\" width=\"320\" /></a></div><br /><br />A problem has arisen because we've bumped our <a href=\"http://developer.android.com/guide/topics/manifest/uses-sdk-element.html\">targetSdkVersion</a> up to 16 (Jelly Bean). &nbsp;It turns out&nbsp;<a href=\"http://android-developers.blogspot.com/2012/01/say-goodbye-to-menu-button.html\">there is a specific set of rules for when the legacy overflow button appears</a>. &nbsp;Our app was depending on the fact that our minSdkVersion was less than 10 and that our targetSdkVersion was between 11 and 13. &nbsp;By bumping our targetSdkVersion up to 16, we no longer got the legacy overflow button.<br /><br />This situation wouldn't be a problem if we showed an action bar, since the overflow menu would just appear there. &nbsp;However, we're using a theme that disables the title, so our menu items disappeared completely.<br /><br />I want to emphasize that <b>the correct solution is to use an action bar with an overflow button</b>. &nbsp;But we're not done with the conversion to action bars yet and during development we'll want that menu to be accessible (all of our debug options go in there). &nbsp;So I came up with a small hack that lets us enable the legacy overflow button manually.<br /><br />It turns out there is a hidden Window flag - WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY - that determines whether the legacy overflow button is shown or not. &nbsp;By using reflection, we can retrieve this field and add it to the Window's flags:<br /><br /><pre>public static void addLegacyOverflowButton(Window window) {<br /> if (window.peekDecorView() == null) {<br /> throw new RuntimeException(\"Must call addLegacyOverflowButton() after setContentView()\");<br /> }<br /><br /> try {<br /> window.addFlags(WindowManager.LayoutParams.class.getField(\"FLAG_NEEDS_MENU_KEY\").getInt(null));<br /> }<br /> catch (NoSuchFieldException e) {<br /> // Ignore since this field won't exist in most versions of Android<br /> }<br /> catch (IllegalAccessException e) {<br /> Log.w(TAG, \"Could not access FLAG_NEEDS_MENU_KEY in addLegacyOverflowButton()\", e);<br /> }<br />}</pre><br />I added the RuntimeException above because you need to call this after the decor View is set (or else it does nothing).",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1346256000000,
"created_by": 1,
"updated_at": 1346256006512,
"updated_by": 1,
"published_at": 1346256000000,
"published_by": 1
},
{
"id": 28,
"title": "Android Emulator Keyboard Support in ADT 20+",
"slug": "android_emulator_keyboard_support_in_adt_20_",
"markdown": "<span style=\"background-color: white;\">If you've upgraded to ADT 20, you may have noticed that your keyboard no longer works on inputs on your emulator. &nbsp;That is, when you have an EditText on the screen, typing characters into your physical keyboard doesn't register anything in the emulator; you need to open the soft keyboard to do anything.</span>\n\nThe problem is that the emulator no longer assumes you have keyboard support by default. &nbsp;You'll need to add it yourself to the emulator and your keyboard will work again:\n\n<div class=\"separator\" style=\"clear: both; text-align: center;\">[![](http://1.bp.blogspot.com/-in0QZgHy1Uc/UAmPgQziLwI/AAAAAAAAAgM/5IYdg-Y2uEw/s320/Untitled.png)](http://1.bp.blogspot.com/-in0QZgHy1Uc/UAmPgQziLwI/AAAAAAAAAgM/5IYdg-Y2uEw/s1600/Untitled.png)</div>",
"html": "<span style=\"background-color: white;\">If you've upgraded to ADT 20, you may have noticed that your keyboard no longer works on inputs on your emulator. &nbsp;That is, when you have an EditText on the screen, typing characters into your physical keyboard doesn't register anything in the emulator; you need to open the soft keyboard to do anything.</span><br /><br />The problem is that the emulator no longer assumes you have keyboard support by default. &nbsp;You'll need to add it yourself to the emulator and your keyboard will work again:<br /><br /><div class=\"separator\" style=\"clear: both; text-align: center;\"><a href=\"http://1.bp.blogspot.com/-in0QZgHy1Uc/UAmPgQziLwI/AAAAAAAAAgM/5IYdg-Y2uEw/s1600/Untitled.png\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"><img border=\"0\" height=\"320\" src=\"http://1.bp.blogspot.com/-in0QZgHy1Uc/UAmPgQziLwI/AAAAAAAAAgM/5IYdg-Y2uEw/s320/Untitled.png\" width=\"286\" /></a></div><br />",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1342803900002,
"created_by": 1,
"updated_at": 1342804043651,
"updated_by": 1,
"published_at": 1342803900002,
"published_by": 1
},
{
"id": 29,
"title": "Fragment Transactions Reference",
"slug": "fragment_transactions_reference",
"markdown": "I recently found myself looking at Fragment transactions and wondering precisely what each Fragment state meant. &nbsp;I vaguely had an idea of what added, attached, shown, hidden, detached and removed meant, but not the specific behaviors of each. &nbsp;I spent a morning looking through Android's code to better understand what happens to Fragments.\n\nHere's a reference manual for what I learned. &nbsp;I looked into two aspects of Fragments: fragment states, and animations in transactions. &nbsp;This research was done primarily on [the compatibility library](http://developer.android.com/sdk/compatibility-library.html). &nbsp;It's possible that some of the details below will differ for the 3.x+ implementation of Fragments.\n\n**Fragment States**\n\nAll of the below support animations. &nbsp;Terminology note: when I say \"configuration change\", I mean when the device changes configuration (for example, from portrait to landscape) and the Activity must be destroyed/recreated.\n\n_FragmentTransaction.[add()](http://developer.android.com/intl/fr/reference/android/app/FragmentTransaction.html#add(int, android.app.Fragment, java.lang.String))/[remove()](http://developer.android.com/intl/fr/reference/android/app/FragmentTransaction.html#remove(android.app.Fragment))_ - These add and remove a Fragment from the FragmentManager. &nbsp;By default, it will begin showing the Fragment as well. &nbsp;During the transaction the returns of Fragment.isAdded() and Fragment.isRemoved() will be modified. &nbsp;These states are preserved on configuration change, so a Fragment that's added will remain added and can be retrieved again from the FragmentManager. &nbsp;Since a removed Fragment is no longer part of the FragmentManager, it will not be retrievable after a configuration change either.\n\n_FragmentTransaction.[attach()](http://developer.android.com/intl/fr/reference/android/app/FragmentTransaction.html#attach(android.app.Fragment))/[detach()](http://developer.android.com/intl/fr/reference/android/app/FragmentTransaction.html#detach(android.app.Fragment)) _- These attach/detach a Fragment from the Activity (e.g., make it an active Fragment that can be seen). &nbsp;During the transaction the returns of&nbsp;Fragment.isAdded() and&nbsp;Fragment.isDetached() will be changed. &nbsp;These states are preserved on configuration change, which means that (unlike removing a Fragment) it is possible to detach a Fragment but then retrieve it later after configuration change (even if it's not actively being displayed). &nbsp;Even in a detached state, the Fragment runs through all lifecycle methods (except the ones that are related to being attached to an Activity) - for example, onSaveInstanceState() will still be called even if the Fragment is detached (which is quite useful for maintaining state).\n\n_FragmentTransaction.[show()](http://developer.android.com/intl/fr/reference/android/app/FragmentTransaction.html#show(android.app.Fragment))/[hide()](http://developer.android.com/intl/fr/reference/android/app/FragmentTransaction.html#hide(android.app.Fragment))_ - These show or hide a Fragment (in particular, it calls View.setVisibility() on the Fragment's root View). &nbsp;During the transaction the returns of&nbsp;Fragment.isHidden() will be modified. &nbsp;Showing/hiding Fragments states are NOT maintained on configuration change, meaning that if you hide a Fragment it will reappear on config change (for example, if the user rotates the screen).\n\n_FragmentTransaction.[replace()](http://developer.android.com/intl/fr/reference/android/app/FragmentTransaction.html#replace(int, android.app.Fragment, java.lang.String))&nbsp;_- Theoretically it is the exact same as removing all Fragments associated with a particular View, then adding a new Fragment in its place. &nbsp;I did not research this much (since I'm more interested in manual control of which Fragments are shown).\n\n**Fragment Animations**\n\nThere are three different ways to animate Fragment transactions. &nbsp;These are ordered by precedence (in other words, the first method, if available, will be used; then the second, then the last).\n\nOne thing to note between the compatibility library and the standard Fragment library is that the standard library uses [property animators](http://developer.android.com/guide/topics/resources/animation-resource.html#Property), whereas the compatibility library uses [tween Animations](http://developer.android.com/guide/topics/resources/animation-resource.html#Tween).\n\n1.&nbsp;Override your Fragment's [onCreateAnimator()](http://developer.android.com/intl/fr/reference/android/app/Fragment.html#onCreateAnimator(int, boolean, int)) method and return an animation. &nbsp;This is the only way to dynamically generate an animation in code (the other two methods rely on pre-configured animations from your resources directory). &nbsp;In the compatibility library, the method is [onCreateAnimation()](http://developer.android.com/intl/fr/reference/android/support/v4/app/Fragment.html#onCreateAnimation(int, boolean, int)) (since the compatibility library uses animations instead of animators).\n\n2.&nbsp;Call [FragmentTransaction.setCustomAnimations()](http://developer.android.com/intl/fr/reference/android/app/FragmentTransaction.html#setCustomAnimations(int, int, int, int)), referencing either animators or animations (depending on whether you're using the compatibility library or not). &nbsp;What is interesting is that setCustomAnimations() affects all fragment transitions added to the transaction **after** it is called. &nbsp;So you need to call setCustomAnimations() before you want it used, and you can actually setup multiple different custom animations for each part of a transaction (with a call to setCustomAnimations() before each add()/remove()/attach()/detach()/show()/hide()/replace()).\n\n3\\. Setup a style that defines window animations ([from this style](http://developer.android.com/reference/android/R.styleable.html#FragmentAnimation)), then call [FragmentTransaction.setTransition()](http://developer.android.com/intl/fr/reference/android/app/FragmentTransaction.html#setTransition(int)) and [FragmentTransaction.setTransitionStyle()](http://developer.android.com/intl/fr/reference/android/app/FragmentTransaction.html#setTransitionStyle(int)) to specify that style and target the correct animation.\n\n#3 works different in the compatibility library. &nbsp;**FragmentTransaction.setTransitionStyle() is completely ignored.** &nbsp;Instead, it uses the specified transition to select a stock animation. &nbsp;So if you want custom animations in the compatibility library, you must use #1 or #2.",
"html": "I recently found myself looking at Fragment transactions and wondering precisely what each Fragment state meant. &nbsp;I vaguely had an idea of what added, attached, shown, hidden, detached and removed meant, but not the specific behaviors of each. &nbsp;I spent a morning looking through Android's code to better understand what happens to Fragments.<br /><br />Here's a reference manual for what I learned. &nbsp;I looked into two aspects of Fragments: fragment states, and animations in transactions. &nbsp;This research was done primarily on <a href=\"http://developer.android.com/sdk/compatibility-library.html\">the compatibility library</a>. &nbsp;It's possible that some of the details below will differ for the 3.x+ implementation of Fragments.<br /><br /><b>Fragment States</b><br /><br />All of the below support animations. &nbsp;Terminology note: when I say \"configuration change\", I mean when the device changes configuration (for example, from portrait to landscape) and the Activity must be destroyed/recreated.<br /><br /><i>FragmentTransaction.<a href=\"http://developer.android.com/intl/fr/reference/android/app/FragmentTransaction.html#add(int, android.app.Fragment, java.lang.String)\">add()</a>/<a href=\"http://developer.android.com/intl/fr/reference/android/app/FragmentTransaction.html#remove(android.app.Fragment)\">remove()</a></i> - These add and remove a Fragment from the FragmentManager. &nbsp;By default, it will begin showing the Fragment as well. &nbsp;During the transaction the returns of Fragment.isAdded() and Fragment.isRemoved() will be modified. &nbsp;These states are preserved on configuration change, so a Fragment that's added will remain added and can be retrieved again from the FragmentManager. &nbsp;Since a removed Fragment is no longer part of the FragmentManager, it will not be retrievable after a configuration change either.<br /><br /><i>FragmentTransaction.<a href=\"http://developer.android.com/intl/fr/reference/android/app/FragmentTransaction.html#attach(android.app.Fragment)\">attach()</a>/<a href=\"http://developer.android.com/intl/fr/reference/android/app/FragmentTransaction.html#detach(android.app.Fragment)\">detach()</a> </i>- These attach/detach a Fragment from the Activity (e.g., make it an active Fragment that can be seen). &nbsp;During the transaction the returns of&nbsp;Fragment.isAdded() and&nbsp;Fragment.isDetached() will be changed. &nbsp;These states are preserved on configuration change, which means that (unlike removing a Fragment) it is possible to detach a Fragment but then retrieve it later after configuration change (even if it's not actively being displayed). &nbsp;Even in a detached state, the Fragment runs through all lifecycle methods (except the ones that are related to being attached to an Activity) - for example, onSaveInstanceState() will still be called even if the Fragment is detached (which is quite useful for maintaining state).<br /><br /><i>FragmentTransaction.<a href=\"http://developer.android.com/intl/fr/reference/android/app/FragmentTransaction.html#show(android.app.Fragment)\">show()</a>/<a href=\"http://developer.android.com/intl/fr/reference/android/app/FragmentTransaction.html#hide(android.app.Fragment)\">hide()</a></i> - These show or hide a Fragment (in particular, it calls View.setVisibility() on the Fragment's root View). &nbsp;During the transaction the returns of&nbsp;Fragment.isHidden() will be modified. &nbsp;Showing/hiding Fragments states are NOT maintained on configuration change, meaning that if you hide a Fragment it will reappear on config change (for example, if the user rotates the screen).<br /><br /><i>FragmentTransaction.<a href=\"http://developer.android.com/intl/fr/reference/android/app/FragmentTransaction.html#replace(int, android.app.Fragment, java.lang.String)\">replace()</a>&nbsp;</i>- Theoretically it is the exact same as removing all Fragments associated with a particular View, then adding a new Fragment in its place. &nbsp;I did not research this much (since I'm more interested in manual control of which Fragments are shown).<br /><br /><b>Fragment Animations</b><br /><br />There are three different ways to animate Fragment transactions. &nbsp;These are ordered by precedence (in other words, the first method, if available, will be used; then the second, then the last).<br /><br />One thing to note between the compatibility library and the standard Fragment library is that the standard library uses <a href=\"http://developer.android.com/guide/topics/resources/animation-resource.html#Property\">property animators</a>, whereas the compatibility library uses <a href=\"http://developer.android.com/guide/topics/resources/animation-resource.html#Tween\">tween Animations</a>.<br /><br />1.&nbsp;Override your Fragment's <a href=\"http://developer.android.com/intl/fr/reference/android/app/Fragment.html#onCreateAnimator(int, boolean, int)\">onCreateAnimator()</a> method and return an animation. &nbsp;This is the only way to dynamically generate an animation in code (the other two methods rely on pre-configured animations from your resources directory). &nbsp;In the compatibility library, the method is <a href=\"http://developer.android.com/intl/fr/reference/android/support/v4/app/Fragment.html#onCreateAnimation(int, boolean, int)\">onCreateAnimation()</a> (since the compatibility library uses animations instead of animators).<br /><br />2.&nbsp;Call <a href=\"http://developer.android.com/intl/fr/reference/android/app/FragmentTransaction.html#setCustomAnimations(int, int, int, int)\">FragmentTransaction.setCustomAnimations()</a>, referencing either animators or animations (depending on whether you're using the compatibility library or not). &nbsp;What is interesting is that setCustomAnimations() affects all fragment transitions added to the transaction <b>after</b> it is called. &nbsp;So you need to call setCustomAnimations() before you want it used, and you can actually setup multiple different custom animations for each part of a transaction (with a call to setCustomAnimations() before each add()/remove()/attach()/detach()/show()/hide()/replace()).<br /><br />3. Setup a style that defines window animations (<a href=\"http://developer.android.com/reference/android/R.styleable.html#FragmentAnimation\">from this style</a>), then call <a href=\"http://developer.android.com/intl/fr/reference/android/app/FragmentTransaction.html#setTransition(int)\">FragmentTransaction.setTransition()</a> and <a href=\"http://developer.android.com/intl/fr/reference/android/app/FragmentTransaction.html#setTransitionStyle(int)\">FragmentTransaction.setTransitionStyle()</a> to specify that style and target the correct animation.<br /><br />#3 works different in the compatibility library. &nbsp;<b>FragmentTransaction.setTransitionStyle() is completely ignored.</b> &nbsp;Instead, it uses the specified transition to select a stock animation. &nbsp;So if you want custom animations in the compatibility library, you must use #1 or #2.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1339524000000,
"created_by": 1,
"updated_at": 1339524003326,
"updated_by": 1,
"published_at": 1339524000000,
"published_by": 1
},
{
"id": 30,
"title": "Obscure SimpleDateFormat Android Issue",
"slug": "obscure_simple_date_format_android_issue",
"markdown": "This bug should win an award for the most obscure bug I've ever run into this year.\n<div>\n</div><div>Check out this code below:</div><div>\n<pre>Calendar cal1 = new GregorianCalendar(2012, 5, 11);\n\ncal1.setTimeZone(TimeZone.getTimeZone(\"UTC\"));\n\nCalendar cal2 = new GregorianCalendar(2012, 5, 12);\n\ncal2.setTimeZone(TimeZone.getTimeZone(\"UTC\"));\n\nDateFormat df = new SimpleDateFormat(\"yyyy-MM-dd\");\n\ndf.setTimeZone(TimeZone.getTimeZone(\"UTC\"));\n\nLog.i(\"test\",&nbsp;\"cal1.format=\" + df.format(cal1.getTime()));\n\nLog.i(\"test\", \"cal2.format=\" + df.format(cal2.getTime()));</pre>\nYou might expect the two formats to be different (one for May 11, the other for May 12). &nbsp;You would be wrong on Android 2.2 and lower. &nbsp;It turns out in this one specific case, the SimpleDateFormat will spit out the same formatted date for the two Calendars.\n\nThe conditions seem to be thus:\n\n1. Two Calendar objects that are one day apart.\n2. One SimpleDateFormat that you want to use.\n3. Both the Calendars and the DateFormat are set to the same TimeZone.\n4. You format both Calendars using the DateFormat, one after another.\nIn this one situation, SimpleDateFormat gets into a state where it formats both Calendars to the same date (May 11). &nbsp;Change any of the above assumptions and the problem will not occur; if the Calendars are more than one day apart, or you use multiple SimpleDateFormats, or you don't set the TimeZone, or you don't immediately reuse the same SimpleDateFormat...\n\nThis problem does not occur on Android 2.3+. &nbsp;For Android 2.2 and lower, the solution is simple - create a new SimpleDateFormat when formatting two Calendars one after another.</div>",
"html": "This bug should win an award for the most obscure bug I've ever run into this year.<br /><div><br /></div><div>Check out this code below:</div><div><br /><pre>Calendar cal1 = new GregorianCalendar(2012, 5, 11);<br /><br />cal1.setTimeZone(TimeZone.getTimeZone(\"UTC\"));<br /><br />Calendar cal2 = new GregorianCalendar(2012, 5, 12);<br /><br />cal2.setTimeZone(TimeZone.getTimeZone(\"UTC\"));<br /><br />DateFormat df = new SimpleDateFormat(\"yyyy-MM-dd\");<br /><br />df.setTimeZone(TimeZone.getTimeZone(\"UTC\"));<br /><br />Log.i(\"test\",&nbsp;\"cal1.format=\" + df.format(cal1.getTime()));<br /><br />Log.i(\"test\", \"cal2.format=\" + df.format(cal2.getTime()));</pre><br />You might expect the two formats to be different (one for May 11, the other for May 12). &nbsp;You would be wrong on Android 2.2 and lower. &nbsp;It turns out in this one specific case, the SimpleDateFormat will spit out the same formatted date for the two Calendars.<br /><br />The conditions seem to be thus:<br /><br /><ol><li>Two Calendar objects that are one day apart.</li><li>One SimpleDateFormat that you want to use.</li><li>Both the Calendars and the DateFormat are set to the same TimeZone.</li><li>You format both Calendars using the DateFormat, one after another.</li></ol><br />In this one situation, SimpleDateFormat gets into a state where it formats both Calendars to the same date (May 11). &nbsp;Change any of the above assumptions and the problem will not occur; if the Calendars are more than one day apart, or you use multiple SimpleDateFormats, or you don't set the TimeZone, or you don't immediately reuse the same SimpleDateFormat...<br /><br />This problem does not occur on Android 2.3+. &nbsp;For Android 2.2 and lower, the solution is simple - create a new SimpleDateFormat when formatting two Calendars one after another.</div>",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1338912000000,
"created_by": 1,
"updated_at": 1338912005767,
"updated_by": 1,
"published_at": 1338912000000,
"published_by": 1
},
{
"id": 31,
"title": "Custom Fragment animations are different between the support library and vanilla",
"slug": "custom_fragment_animations_are_different_between_the_support_library_and_vanilla",
"markdown": "I've been converting a lot of my apps to [the support library](http://developer.android.com/sdk/compatibility-library.html) recently and ran into one issue worth mentioning. &nbsp;To be clear: I'm converting apps that use [android.app.Fragment](http://developer.android.com/reference/android/app/Fragment.html)&nbsp;to now use [support versions of Fragments](http://developer.android.com/reference/android/support/v4/app/Fragment.html).\n\nIf you do this and you're using FragmentTransaction.setCustomAnimations() you may be in for a shock. &nbsp;Your app will crash in the most glorious fashion:\n\n<pre>FATAL EXCEPTION: main\njava.lang.RuntimeException: Unknown animation name: objectAnimator\n at android.view.animation.AnimationUtils.createAnimationFromXml(AnimationUtils.java:124)\n at android.view.animation.AnimationUtils.createAnimationFromXml(AnimationUtils.java:91)\n at android.view.animation.AnimationUtils.loadAnimation(AnimationUtils.java:72)\n at android.support.v4.app.FragmentManagerImpl.loadAnimation(FragmentManager.java:710)\n at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:876)\n at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1080)\n at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:622)\n at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1416)\n at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:420)\n at android.os.Handler.handleCallback(Handler.java:587)\n at android.os.Handler.dispatchMessage(Handler.java:92)\n at android.os.Looper.loop(Looper.java:132)\n at android.app.ActivityThread.main(ActivityThread.java:4123)\n at java.lang.reflect.Method.invokeNative(Native Method)\n at java.lang.reflect.Method.invoke(Method.java:491)\n at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)\n at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)\n at dalvik.system.NativeStart.main(Native Method)</pre>\nThe reason is that setCustomAnimations() in vanilla use [object animators](http://developer.android.com/guide/topics/resources/animation-resource.html#Property), whereas setCustomAnimations() in the support package use [tween animations](http://developer.android.com/guide/topics/resources/animation-resource.html#View). &nbsp;It won't give you a compiler error because they're both referenced by resource id.\n\nThere's only one solution: convert your object animators to tween animations. &nbsp;The conversion&nbsp;wasn't difficult at all for me. &nbsp;In fact, it makes things a bit easier - object animators don't do percentages while tweens do, a problem I had struggled with before (\"how do I get a Fragment to slide in from left to center?\").",
"html": "I've been converting a lot of my apps to <a href=\"http://developer.android.com/sdk/compatibility-library.html\">the support library</a> recently and ran into one issue worth mentioning. &nbsp;To be clear: I'm converting apps that use <a href=\"http://developer.android.com/reference/android/app/Fragment.html\">android.app.Fragment</a>&nbsp;to now use <a href=\"http://developer.android.com/reference/android/support/v4/app/Fragment.html\">support versions of Fragments</a>.<br /><br />If you do this and you're using FragmentTransaction.setCustomAnimations() you may be in for a shock. &nbsp;Your app will crash in the most glorious fashion:<br /><br /><pre>FATAL EXCEPTION: main<br />java.lang.RuntimeException: Unknown animation name: objectAnimator<br /> at android.view.animation.AnimationUtils.createAnimationFromXml(AnimationUtils.java:124)<br /> at android.view.animation.AnimationUtils.createAnimationFromXml(AnimationUtils.java:91)<br /> at android.view.animation.AnimationUtils.loadAnimation(AnimationUtils.java:72)<br /> at android.support.v4.app.FragmentManagerImpl.loadAnimation(FragmentManager.java:710)<br /> at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:876)<br /> at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1080)<br /> at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:622)<br /> at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1416)<br /> at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:420)<br /> at android.os.Handler.handleCallback(Handler.java:587)<br /> at android.os.Handler.dispatchMessage(Handler.java:92)<br /> at android.os.Looper.loop(Looper.java:132)<br /> at android.app.ActivityThread.main(ActivityThread.java:4123)<br /> at java.lang.reflect.Method.invokeNative(Native Method)<br /> at java.lang.reflect.Method.invoke(Method.java:491)<br /> at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)<br /> at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)<br /> at dalvik.system.NativeStart.main(Native Method)</pre><br />The reason is that setCustomAnimations() in vanilla use <a href=\"http://developer.android.com/guide/topics/resources/animation-resource.html#Property\">object animators</a>, whereas setCustomAnimations() in the support package use <a href=\"http://developer.android.com/guide/topics/resources/animation-resource.html#View\">tween animations</a>. &nbsp;It won't give you a compiler error because they're both referenced by resource id.<br /><br />There's only one solution: convert your object animators to tween animations. &nbsp;The conversion&nbsp;wasn't difficult at all for me. &nbsp;In fact, it makes things a bit easier - object animators don't do percentages while tweens do, a problem I had struggled with before (\"how do I get a Fragment to slide in from left to center?\").",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1334678400000,
"created_by": 1,
"updated_at": 1334678403837,
"updated_by": 1,
"published_at": 1334678400000,
"published_by": 1
},
{
"id": 32,
"title": "Unicode Normalization and Android",
"slug": "unicode_normalization_and_android",
"markdown": "I ran into a Unicode rendering issue recently that I wanted to go over. &nbsp;Check out this screenshot from an application we've recently localized into Vietnamese:\n\n<div class=\"separator\" style=\"clear: both; text-align: center;\">[![](http://3.bp.blogspot.com/-8yzl8s4OkiE/T4MPnfNxXmI/AAAAAAAAAbk/gSxtr1MPZAo/s320/device-2012-04-09-113425.png)](http://3.bp.blogspot.com/-8yzl8s4OkiE/T4MPnfNxXmI/AAAAAAAAAbk/gSxtr1MPZAo/s1600/device-2012-04-09-113425.png)</div>\nNotice how a lot of the text looks cut off (especially those blue labels). &nbsp;What's going on?\n\nIt turns out that the TextViews are rendering diacritics improperly. &nbsp;Sometimes the diacritic ends up on the wrong character. &nbsp;Other times, it ends up on its own space. &nbsp;The layout system seems to figure out the width correctly but the renderer screws it up, causing the text to be cut off when layout_width is set to wrap_content. &nbsp;The root of the problem is that Android is messing up&nbsp;[combining characters (or combining diacritical marks)](http://en.wikipedia.org/wiki/Combining_character) in unicode.\n\nThe solution that we found was&nbsp;[unicode normalization](http://en.wikipedia.org/wiki/Unicode_equivalence#Normalization). &nbsp;A character with diacritics can always be represented by a combination of multiple code points, but sometimes there is also a single code point that represents the character. &nbsp;We found that by using unicode's normalization form C (NFC), we could normalize most of the combining diacritical characters out of text (and thus sidestep this problem altogether).\n\nThere's two steps we're taking to normalize our text:\n\n1\\. For all strings that are in our APK, we normalized them inside strings.xml. &nbsp;There are plenty of tools out there (like [charlint](http://www.w3.org/International/charlint/)) that can do the job.\n\n2\\. We run all strings delivered from servers through [Normalizer](http://developer.android.com/reference/java/text/Normalizer.Form.html) while parsing. &nbsp;It did not seem to degrade performance to do so.\n\nStep 2 may not be necessary if your app is self-contained and never gets any strings from the net. &nbsp;Also, you could just use Normalizer as your tool for step 1 (it's up to you).\n\nWe found this problem to only happen on ICS - it appears to work fine on honeycomb and below. &nbsp;Also, if you want to know more about unicode normalization, I highly recommend reading [this article](http://unicode.org/reports/tr15/).",
"html": "<br />I ran into a Unicode rendering issue recently that I wanted to go over. &nbsp;Check out this screenshot from an application we've recently localized into Vietnamese:<br /><br /><div class=\"separator\" style=\"clear: both; text-align: center;\"><a href=\"http://3.bp.blogspot.com/-8yzl8s4OkiE/T4MPnfNxXmI/AAAAAAAAAbk/gSxtr1MPZAo/s1600/device-2012-04-09-113425.png\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"><img border=\"0\" height=\"320\" src=\"http://3.bp.blogspot.com/-8yzl8s4OkiE/T4MPnfNxXmI/AAAAAAAAAbk/gSxtr1MPZAo/s320/device-2012-04-09-113425.png\" width=\"180\" /></a></div><br />Notice how a lot of the text looks cut off (especially those blue labels). &nbsp;What's going on?<br /><br />It turns out that the TextViews are rendering diacritics improperly. &nbsp;Sometimes the diacritic ends up on the wrong character. &nbsp;Other times, it ends up on its own space. &nbsp;The layout system seems to figure out the width correctly but the renderer screws it up, causing the text to be cut off when layout_width is set to wrap_content. &nbsp;The root of the problem is that Android is messing up&nbsp;<a href=\"http://en.wikipedia.org/wiki/Combining_character\">combining characters (or combining diacritical marks)</a> in unicode.<br /><br />The solution that we found was&nbsp;<a href=\"http://en.wikipedia.org/wiki/Unicode_equivalence#Normalization\">unicode normalization</a>. &nbsp;A character with diacritics can always be represented by a combination of multiple code points, but sometimes there is also a single code point that represents the character. &nbsp;We found that by using unicode's normalization form C (NFC), we could normalize most of the combining diacritical characters out of text (and thus sidestep this problem altogether).<br /><br />There's two steps we're taking to normalize our text:<br /><br />1. For all strings that are in our APK, we normalized them inside strings.xml. &nbsp;There are plenty of tools out there (like <a href=\"http://www.w3.org/International/charlint/\">charlint</a>) that can do the job.<br /><br />2. We run all strings delivered from servers through <a href=\"http://developer.android.com/reference/java/text/Normalizer.Form.html\">Normalizer</a> while parsing. &nbsp;It did not seem to degrade performance to do so.<br /><br />Step 2 may not be necessary if your app is self-contained and never gets any strings from the net. &nbsp;Also, you could just use Normalizer as your tool for step 1 (it's up to you).<br /><br />We found this problem to only happen on ICS - it appears to work fine on honeycomb and below. &nbsp;Also, if you want to know more about unicode normalization, I highly recommend reading <a href=\"http://unicode.org/reports/tr15/\">this article</a>.<br />",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1334073600000,
"created_by": 1,
"updated_at": 1334073601912,
"updated_by": 1,
"published_at": 1334073600000,
"published_by": 1
},
{
"id": 33,
"title": "Yet Another Dumb Widget Hiding Trick",
"slug": "yet_another_dumb_widget_hiding_trick",
"markdown": "I didn't mean to be writing [a series](http://daniel-codes.blogspot.com/2011/06/honeycomb-app-widget-and-backwards.html) of [these articles](http://daniel-codes.blogspot.com/2012/01/another-app-widget-compatibility-trick.html), but I keep getting backed into a corner...\n\nThe last two times, I was dealing solely with preventing app widgets from appearing on particular versions of Android. &nbsp;The problem is that this trick **only** works for platform version; all other resource qualifiers (like screen size) are ignored.\n\nThis becomes a problem when you have a widget that you only want to work on smaller screen sizes, or only in some locales, etc. &nbsp;In this situation, you can't use the AndroidManifest tricks because all those values can change at runtime.\n\nThe hackiest answer I found was to manually disable the widget provider on launch, based on whatever parameters you provide. &nbsp;In this case, I'm using a boolean I've defined as \"widgetEnabled\":\n\n<pre>public class ExpediaBookingApp extends Application {\n @Override\n public void onCreate() {\n super.onCreate();\n\n if (getResources().getBoolean(R.bool.widgetEnabled)) {\n PackageManager pm = getPackageManager();\n ComponentName cn = new ComponentName(this, AppWidgetProvider.class);\n pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);\n }\n }\n}</pre><div class=\"p1\">\n</div><div class=\"p1\">This will only disable the widget **after** the first launch of the application, so it's still possible for users to install the widget before the first launch. &nbsp;But it's way better than nothing. &nbsp;Also note that this doesn't seem to work on every version of Android (but it does work on ICS, which is what I was targeting).</div>\n**The true answer to this problem is to make sure your widget works on all platforms of Android**. &nbsp;But if you're squeezed this hack can save the day as well.",
"html": "I didn't mean to be writing <a href=\"http://daniel-codes.blogspot.com/2011/06/honeycomb-app-widget-and-backwards.html\">a series</a> of <a href=\"http://daniel-codes.blogspot.com/2012/01/another-app-widget-compatibility-trick.html\">these articles</a>, but I keep getting backed into a corner...<br /><br />The last two times, I was dealing solely with preventing app widgets from appearing on particular versions of Android. &nbsp;The problem is that this trick <b>only</b> works for platform version; all other resource qualifiers (like screen size) are ignored.<br /><br />This becomes a problem when you have a widget that you only want to work on smaller screen sizes, or only in some locales, etc. &nbsp;In this situation, you can't use the AndroidManifest tricks because all those values can change at runtime.<br /><br />The hackiest answer I found was to manually disable the widget provider on launch, based on whatever parameters you provide. &nbsp;In this case, I'm using a boolean I've defined as \"widgetEnabled\":<br /><br /><pre>public class ExpediaBookingApp extends Application {<br /> @Override<br /> public void onCreate() {<br /> super.onCreate();<br /><br /> if (getResources().getBoolean(R.bool.widgetEnabled)) {<br /> PackageManager pm = getPackageManager();<br /> ComponentName cn = new ComponentName(this, AppWidgetProvider.class);<br /> pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);<br /> }<br /> }<br />}</pre><div class=\"p1\"><br /></div><div class=\"p1\">This will only disable the widget <b>after</b> the first launch of the application, so it's still possible for users to install the widget before the first launch. &nbsp;But it's way better than nothing. &nbsp;Also note that this doesn't seem to work on every version of Android (but it does work on ICS, which is what I was targeting).</div><br /><b>The true answer to this problem is to make sure your widget works on all platforms of Android</b>. &nbsp;But if you're squeezed this hack can save the day as well.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1333555200000,
"created_by": 1,
"updated_at": 1333555206010,
"updated_by": 1,
"published_at": 1333555200000,
"published_by": 1
},
{
"id": 34,
"title": "Solving Initial Compilation Issues with Android",
"slug": "solving_initial_compilation_issues_with_android",
"markdown": "Two weeks ago I helped with a beginner's Android Workshop at [Mobile March](http://mobilemarchtc.com/). &nbsp;A lot of the people had problems getting their development environment up and running - but for reasons that weren't really any fault of their own, or were easily overlooked. &nbsp;Typically once you've got all the gears in place building is simple, but&nbsp;I'd forgotten how surprisingly difficult it can be to get a project up and running in Eclipse initially.\n\nHere's a few common problems I saw around the classroom:\n\n- **Installing the [Android SDK](http://developer.android.com/sdk/index.html) (the tools for Android) but not the [ADT plugin](http://developer.android.com/sdk/eclipse-adt.html) (how Eclipse interfaces with the SDK), or vice versa.** &nbsp;Make sure both are installed.\n\n-** Not installing any Android platforms (or not installing the correct one for the app you're trying to build).** &nbsp;The SDK is just a starter package - from there, [you need to run the Android SDK Manager and add SDK components](http://developer.android.com/sdk/adding-components.html). &nbsp;There's an SDK platform for each version of Android; I recommend just installing the whole lot (it takes time to download, but makes everything else easy).\n\n- **If you get compilation errors upon importing a project, do a full clean and rebuild.** &nbsp;Clean is found in Project --&gt; Clean. &nbsp;This can sometimes clear up import issues.\n\n- **Compilation issues with @Override.** &nbsp;If you're getting compilation error on @Override, that's because your JDK compliance level is set incorrectly. &nbsp;You either need to go into Eclipse --&gt; Preferences --&gt; Java --&gt; Compiler and set the compliance level to 1.6+, or you need to go into the individual project and change that setting (right-click the project --&gt; Properties --&gt; Java Compiler --&gt; Compiler compliance level).\n\n- **Using emulators that are not compatible with your sample app.** &nbsp;If your app targets 2.3, you must have a 2.3 (or higher) emulator. &nbsp;If your app uses Google Maps, your emulator must be a \"Google APIs\" emulator (and also conform to the previous version requirement as well).\n\n- **Did you try Android briefly more than a year ago and now it refuses to work?**&nbsp; Chances are the problem is an invalid debug.keystore. &nbsp;When you build in Eclipse, it creates your APK using an automatically generated debug keystore. &nbsp;Older versions of Android had these set to expire a year after creation, so if you dabbled in Android before it may have expired. &nbsp;You can find the path to your debug.keystore by going into Preferences --&gt; Android --&gt; Build. &nbsp;You can safely delete your old debug.keystore and the Android build process will automatically create a new, valid one for you.\n\n- **If none of the above helps, I found the most useful debugging tool for build errors was to turn on verbose output. &nbsp;**You can turn that on in Preferences --&gt; Android --&gt; Build --&gt; Build Output, then check the Console for any salient error messages.\n\nGood luck getting your first Android app building!",
"html": "Two weeks ago I helped with a beginner's Android Workshop at <a href=\"http://mobilemarchtc.com/\">Mobile March</a>. &nbsp;A lot of the people had problems getting their development environment up and running - but for reasons that weren't really any fault of their own, or were easily overlooked. &nbsp;Typically once you've got all the gears in place building is simple, but&nbsp;I'd forgotten how surprisingly difficult it can be to get a project up and running in Eclipse initially.<br /><br />Here's a few common problems I saw around the classroom:<br /><br />- <b>Installing the <a href=\"http://developer.android.com/sdk/index.html\">Android SDK</a> (the tools for Android) but not the <a href=\"http://developer.android.com/sdk/eclipse-adt.html\">ADT plugin</a> (how Eclipse interfaces with the SDK), or vice versa.</b> &nbsp;Make sure both are installed.<br /><br />-<b> Not installing any Android platforms (or not installing the correct one for the app you're trying to build).</b> &nbsp;The SDK is just a starter package - from there, <a href=\"http://developer.android.com/sdk/adding-components.html\">you need to run the Android SDK Manager and add SDK components</a>. &nbsp;There's an SDK platform for each version of Android; I recommend just installing the whole lot (it takes time to download, but makes everything else easy).<br /><br />- <b>If you get compilation errors upon importing a project, do a full clean and rebuild.</b> &nbsp;Clean is found in Project --&gt; Clean. &nbsp;This can sometimes clear up import issues.<br /><br />- <b>Compilation issues with @Override.</b> &nbsp;If you're getting compilation error on @Override, that's because your JDK compliance level is set incorrectly. &nbsp;You either need to go into Eclipse --&gt; Preferences --&gt; Java --&gt; Compiler and set the compliance level to 1.6+, or you need to go into the individual project and change that setting (right-click the project --&gt; Properties --&gt; Java Compiler --&gt; Compiler compliance level).<br /><br /><br />- <b>Using emulators that are not compatible with your sample app.</b> &nbsp;If your app targets 2.3, you must have a 2.3 (or higher) emulator. &nbsp;If your app uses Google Maps, your emulator must be a \"Google APIs\" emulator (and also conform to the previous version requirement as well).<br /><br /><br />- <b>Did you try Android briefly more than a year ago and now it refuses to work?</b>&nbsp; Chances are the problem is an invalid debug.keystore. &nbsp;When you build in Eclipse, it creates your APK using an automatically generated debug keystore. &nbsp;Older versions of Android had these set to expire a year after creation, so if you dabbled in Android before it may have expired. &nbsp;You can find the path to your debug.keystore by going into Preferences --&gt; Android --&gt; Build. &nbsp;You can safely delete your old debug.keystore and the Android build process will automatically create a new, valid one for you.<br /><br />- <b>If none of the above helps, I found the most useful debugging tool for build errors was to turn on verbose output. &nbsp;</b>You can turn that on in Preferences --&gt; Android --&gt; Build --&gt; Build Output, then check the Console for any salient error messages.<br /><br />Good luck getting your first Android app building!",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1332864000000,
"created_by": 1,
"updated_at": 1332865409401,
"updated_by": 1,
"published_at": 1332864000000,
"published_by": 1
},
{
"id": 35,
"title": "Upcoming Talks: AnDevCon III and Mobile March 3D",
"slug": "upcoming_talks_an_dev_con_iii_and_mobile_march_3_d",
"markdown": "I'm going to be speaking at AnDevCon III! &nbsp;My talk is called \"Don't Make Me Repeat Myself: Tips and Tricks to Avoid Code Duplication and Increase Code Reuse on Android\". &nbsp;You can find a long description of it&nbsp;[here](http://www.andevcon.com/AnDevCon_III/classes.html).\n\n[If you register](http://www.andevcon.com/AnDevCon_III/registration.html), you can use my last name (\"LEW\") as a $200 off coupon. &nbsp;This coupon should be valid all the way up till the conference. &nbsp;Also, if you register before March 2nd you get some pretty deep discounts.\n\nI'm slated to give a demo version of this talk at the [April AUG.MN meetup](http://groups.google.com/group/androiddevmn) (April 3rd), if you happen to be near the Twin Cities.\n\nI thought I'd also mention that I'm going to be briefly demoing [Mobiata's apps](http://www.mobiata.com/) at [Mobile March's 3D event](http://mobilemarchtc.com/mobile-3d-2/). &nbsp; I'll also be helping out with the Android workshop on Friday. &nbsp;Say hello if you happen to see me around.",
"html": "I'm going to be speaking at AnDevCon III! &nbsp;My talk is called \"Don't Make Me Repeat Myself: Tips and Tricks to Avoid Code Duplication and Increase Code Reuse on Android\". &nbsp;You can find a long description of it&nbsp;<a href=\"http://www.andevcon.com/AnDevCon_III/classes.html\">here</a>.<br /><br /><a href=\"http://www.andevcon.com/AnDevCon_III/registration.html\">If you register</a>, you can use my last name (\"LEW\") as a $200 off coupon. &nbsp;This coupon should be valid all the way up till the conference. &nbsp;Also, if you register before March 2nd you get some pretty deep discounts.<br /><br />I'm slated to give a demo version of this talk at the <a href=\"http://groups.google.com/group/androiddevmn\">April AUG.MN meetup</a> (April 3rd), if you happen to be near the Twin Cities.<br /><br />I thought I'd also mention that I'm going to be briefly demoing <a href=\"http://www.mobiata.com/\">Mobiata's apps</a> at <a href=\"http://mobilemarchtc.com/mobile-3d-2/\">Mobile March's 3D event</a>. &nbsp; I'll also be helping out with the Android workshop on Friday. &nbsp;Say hello if you happen to see me around.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1330628400000,
"created_by": 1,
"updated_at": 1330628404148,
"updated_by": 1,
"published_at": 1330628400000,
"published_by": 1
},
{
"id": 36,
"title": "Another App Widget Compatibility Trick",
"slug": "another_app_widget_compatibility_trick",
"markdown": "I've written previously on [the issue of preventing app widgets from appearing on particular versions of Android](http://daniel-codes.blogspot.com/2011/06/honeycomb-app-widget-and-backwards.html). &nbsp;This is useful, for example, when you have a Honeycomb-style widget but support pre-Honeycomb devices.\n\nI've got a second version of this trick which I think is a bit easier now. &nbsp;Instead of preventing the system from seeing your&nbsp;AppWidgetProviderInfo, you can actually enable/disable the widget receiver itself based on configuration resource selectors.\n\nFirst, setup your app widget receiver thus (important part bolded):\n<pre>&lt;receiver\n **android:enabled=\"@bool/widget_enabled\"**\n android:name=\"com.company.appwidget.MyAppWidgetProvider\" &gt;\n &lt;intent-filter &gt;\n &lt;action android:name=\"android.appwidget.action.APPWIDGET_UPDATE\" /&gt;\n &lt;/intent-filter&gt;\n\n &lt;meta-data\n android:name=\"android.appwidget.provider\"\n android:resource=\"@xml/appwidget_info\" /&gt;\n&lt;/receiver&gt;</pre>\nThen all you need to do is create a config.xml (in your /res/values/ directory) file that sets \"widget_enabled\":\n<pre>&lt;resources&gt;\n &lt;bool name=\"widget_enabled\"&gt;true&lt;/bool&gt;\n&lt;/resources&gt;</pre>\nYou can then leverage the resource qualifier system to enable or disable the widget as necessary for different configurations. &nbsp;For example, if you wanted your widget enabled on all versions of Android except for v11 through v13, you could set it up like this:\n\n/res/values/config.xml &lt;-- widget_enabled=true\n/res/values-v11/config.xml &lt;-- widget_enabled=false\n/res/values-v14/config.xml &lt;-- widget_enabled=true\n\nThe main advantage this provides over my last solution is that you need only modify a bool; the other solution required you to create duplicate versions of the&nbsp;AppWidgetProviderInfo XML file (if you supported, say, v3 through v10 and v14+).",
"html": "I've written previously on <a href=\"http://daniel-codes.blogspot.com/2011/06/honeycomb-app-widget-and-backwards.html\">the issue of preventing app widgets from appearing on particular versions of Android</a>. &nbsp;This is useful, for example, when you have a Honeycomb-style widget but support pre-Honeycomb devices.<br /><br />I've got a second version of this trick which I think is a bit easier now. &nbsp;Instead of preventing the system from seeing your&nbsp;AppWidgetProviderInfo, you can actually enable/disable the widget receiver itself based on configuration resource selectors.<br /><br />First, setup your app widget receiver thus (important part bolded):<br /><pre>&lt;receiver<br /> <b>android:enabled=\"@bool/widget_enabled\"</b><br /> android:name=\"com.company.appwidget.MyAppWidgetProvider\" &gt;<br /> &lt;intent-filter &gt;<br /> &lt;action android:name=\"android.appwidget.action.APPWIDGET_UPDATE\" /&gt;<br /> &lt;/intent-filter&gt;<br /><br /> &lt;meta-data<br /> android:name=\"android.appwidget.provider\"<br /> android:resource=\"@xml/appwidget_info\" /&gt;<br />&lt;/receiver&gt;</pre><br />Then all you need to do is create a config.xml (in your /res/values/ directory) file that sets \"widget_enabled\":<br /><pre>&lt;resources&gt;<br /> &lt;bool name=\"widget_enabled\"&gt;true&lt;/bool&gt;<br />&lt;/resources&gt;</pre><br />You can then leverage the resource qualifier system to enable or disable the widget as necessary for different configurations. &nbsp;For example, if you wanted your widget enabled on all versions of Android except for v11 through v13, you could set it up like this:<br /><br />/res/values/config.xml &lt;-- widget_enabled=true<br />/res/values-v11/config.xml &lt;-- widget_enabled=false<br />/res/values-v14/config.xml &lt;-- widget_enabled=true<br /><br />The main advantage this provides over my last solution is that you need only modify a bool; the other solution required you to create duplicate versions of the&nbsp;AppWidgetProviderInfo XML file (if you supported, say, v3 through v10 and v14+).",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1327604400000,
"created_by": 1,
"updated_at": 1327604403493,
"updated_by": 1,
"published_at": 1327604400000,
"published_by": 1
},
{
"id": 37,
"title": "GridLayout Child View Clipping Issues",
"slug": "grid_layout_child_view_clipping_issues",
"markdown": "[After back-porting GridLayout to 1.5+](https://github.com/dlew/android-gridlayout), I finally feel comfortable using it in my apps. &nbsp;There's a bit of an initial learning curve, but I think that is mostly a function of un-learning the LinearLayout/RelativeLayout state of mind. &nbsp;I've converted a number of my own layouts to use GridLayout and found them to be much faster/easier to understand afterwards.\n\nThere was one particular issue that I ran into that is worth noting, for its solution was not immediately obvious. &nbsp;I was making a two-column GridLayout, where an image was on the left and text was on the right. &nbsp;Here's a simplified version of this layout:\n<pre>&lt;GridLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:layout_width=\"match_parent\"\n android:layout_height=\"wrap_content\" &gt;\n\n &lt;Space android:layout_width=\"100dp\" /&gt;\n\n &lt;TextView android:text=\"@string/two_cities\" /&gt;\n\n&lt;/GridLayout&gt;</pre>\nThe two Views would align next to each other nicely, but the TextView on the right would end up overflowing off the edge (the example below is not cropped - this is how it appears on the device):\n\n<div class=\"separator\" style=\"clear: both; text-align: center;\">[![](http://2.bp.blogspot.com/-QAmQDFE-Uhg/Tx39slrQ39I/AAAAAAAAAVM/XrZ4Dl7hLGQ/s320/clipping.png)](http://2.bp.blogspot.com/-QAmQDFE-Uhg/Tx39slrQ39I/AAAAAAAAAVM/XrZ4Dl7hLGQ/s1600/clipping.png)</div>\n\nWhat was happening was that the TextView would take up the entire width of the GridLayout, instead of taking up just the width of the cell (as I expected).\n<insert fail=\"\" here=\"\" image=\"\"></insert>\n\nIt turns out the solution is to set the width of the TextView to zero, then let the View fill its space dynamically using layout_gravity:\n\n<pre>&lt;GridLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:layout_width=\"match_parent\"\n android:layout_height=\"wrap_content\" &gt;\n\n &lt;Space android:layout_width=\"100dp\" /&gt;\n\n &lt;TextView\n **android:layout_width=\"0dip\"\n android:layout_gravity=\"fill_horizontal\"**\n android:text=\"@string/two_cities\" /&gt;\n\n&lt;/GridLayout&gt;</pre>\nNow the problem is solved:\n\n<div class=\"separator\" style=\"clear: both; text-align: center;\">[![](http://1.bp.blogspot.com/-JXmoK_Ue3JA/Tx3-w29UmhI/AAAAAAAAAVU/TXouu6MR8No/s320/correct.png)](http://1.bp.blogspot.com/-JXmoK_Ue3JA/Tx3-w29UmhI/AAAAAAAAAVU/TXouu6MR8No/s1600/correct.png)</div>\n\nYou need both of the highlighted attributes above; one or the other won't fix the problem. &nbsp;However, it will nicely solve the issue and should be kept in mind anytime you setup a GridLayout child to fill horizontally or vertically.",
"html": "<a href=\"https://github.com/dlew/android-gridlayout\">After back-porting GridLayout to 1.5+</a>, I finally feel comfortable using it in my apps. &nbsp;There's a bit of an initial learning curve, but I think that is mostly a function of un-learning the LinearLayout/RelativeLayout state of mind. &nbsp;I've converted a number of my own layouts to use GridLayout and found them to be much faster/easier to understand afterwards.<br /><br />There was one particular issue that I ran into that is worth noting, for its solution was not immediately obvious. &nbsp;I was making a two-column GridLayout, where an image was on the left and text was on the right. &nbsp;Here's a simplified version of this layout:<br /><pre>&lt;GridLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"<br /> android:layout_width=\"match_parent\"<br /> android:layout_height=\"wrap_content\" &gt;<br /><br /> &lt;Space android:layout_width=\"100dp\" /&gt;<br /><br /> &lt;TextView android:text=\"@string/two_cities\" /&gt;<br /><br />&lt;/GridLayout&gt;</pre><br />The two Views would align next to each other nicely, but the TextView on the right would end up overflowing off the edge (the example below is not cropped - this is how it appears on the device):<br /><br /><div class=\"separator\" style=\"clear: both; text-align: center;\"><a href=\"http://2.bp.blogspot.com/-QAmQDFE-Uhg/Tx39slrQ39I/AAAAAAAAAVM/XrZ4Dl7hLGQ/s1600/clipping.png\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"><img border=\"0\" height=\"188\" src=\"http://2.bp.blogspot.com/-QAmQDFE-Uhg/Tx39slrQ39I/AAAAAAAAAVM/XrZ4Dl7hLGQ/s320/clipping.png\" width=\"320\" /></a></div><br /><br />What was happening was that the TextView would take up the entire width of the GridLayout, instead of taking up just the width of the cell (as I expected).<br /><insert fail=\"\" here=\"\" image=\"\"></insert><br /><br />It turns out the solution is to set the width of the TextView to zero, then let the View fill its space dynamically using layout_gravity:<br /><br /><pre>&lt;GridLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"<br /> android:layout_width=\"match_parent\"<br /> android:layout_height=\"wrap_content\" &gt;<br /><br /> &lt;Space android:layout_width=\"100dp\" /&gt;<br /><br /> &lt;TextView<br /> <b>android:layout_width=\"0dip\"<br /> android:layout_gravity=\"fill_horizontal\"</b><br /> android:text=\"@string/two_cities\" /&gt;<br /><br />&lt;/GridLayout&gt;</pre><br />Now the problem is solved:<br /><br /><div class=\"separator\" style=\"clear: both; text-align: center;\"><a href=\"http://1.bp.blogspot.com/-JXmoK_Ue3JA/Tx3-w29UmhI/AAAAAAAAAVU/TXouu6MR8No/s1600/correct.png\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"><img border=\"0\" height=\"246\" src=\"http://1.bp.blogspot.com/-JXmoK_Ue3JA/Tx3-w29UmhI/AAAAAAAAAVU/TXouu6MR8No/s320/correct.png\" width=\"320\" /></a></div><br /><br />You need both of the highlighted attributes above; one or the other won't fix the problem. &nbsp;However, it will nicely solve the issue and should be kept in mind anytime you setup a GridLayout child to fill horizontally or vertically.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1327431600001,
"created_by": 1,
"updated_at": 1327433289160,
"updated_by": 1,
"published_at": 1327431600001,
"published_by": 1
},
{
"id": 38,
"title": "Highlights from Android's New Design Docs",
"slug": "highlights_from_android_s_new_design_docs",
"markdown": "I've just finished reading through the wonderful new [Android Design site](http://developer.android.com/design/) Google just released. &nbsp;A lot of the information is stuff you should already know if you're an Android developer. &nbsp;However, I took notes of pages/information that I found particularly interesting (or new for ICS). &nbsp;Listed in order of appearance on the site:\n\n[**48dp Rhythm**](http://developer.android.com/design/style/metrics-grids.html) - Like me, you may have implicitly noticed this pattern before, but it's good to see it stated so explicitly. &nbsp;(Same with the 8dp gap.)\n\n[**Back vs. Up**](http://developer.android.com/design/patterns/navigation.html) - Having been confused on the exact distinction for a while, this page is a breath of fresh air.\n\n[**Action Bar Pattern**](http://developer.android.com/design/patterns/actionbar.html) - This entire page should be required reading for everyone. &nbsp;It definitely looks like the Action Bar is the future, and this is the instruction manual.\n\n[**Long Touch Multiselect**](http://developer.android.com/design/patterns/selection.html) - Breaking news: long touch no longer activates the contextual menu. &nbsp;Now, it is purely for activating selection (aka multiselect). &nbsp;Every longtime Android developer should be aware of this change.\n\n(Personally, I didn't even notice this change despite owning a Galaxy Nexus for a month. &nbsp;Perhaps that's because not even every Google app has switched to the new design yet. &nbsp;Or perhaps it's because long touch is just not an intuitive way to design any functionality - I've long since given up putting any core functionality into long touch. &nbsp;Still, it's worth noting the design shift.)\n\n[**Android is not the iPhone**](http://developer.android.com/design/patterns/pure-android.html) - At least, that's what this section *should* be called. &nbsp;This page will be most useful for showing to your designer or boss how Android differs from iPhone and why you shouldn't just port assets and design directly from one to the other.",
"html": "I've just finished reading through the wonderful new <a href=\"http://developer.android.com/design/\">Android Design site</a> Google just released. &nbsp;A lot of the information is stuff you should already know if you're an Android developer. &nbsp;However, I took notes of pages/information that I found particularly interesting (or new for ICS). &nbsp;Listed in order of appearance on the site:<br /><br /><a href=\"http://developer.android.com/design/style/metrics-grids.html\"><b>48dp Rhythm</b></a> - Like me, you may have implicitly noticed this pattern before, but it's good to see it stated so explicitly. &nbsp;(Same with the 8dp gap.)<br /><br /><a href=\"http://developer.android.com/design/patterns/navigation.html\"><b>Back vs. Up</b></a> - Having been confused on the exact distinction for a while, this page is a breath of fresh air.<br /><br /><a href=\"http://developer.android.com/design/patterns/actionbar.html\"><b>Action Bar Pattern</b></a> - This entire page should be required reading for everyone. &nbsp;It definitely looks like the Action Bar is the future, and this is the instruction manual.<br /><br /><a href=\"http://developer.android.com/design/patterns/selection.html\"><b>Long Touch Multiselect</b></a> - Breaking news: long touch no longer activates the contextual menu. &nbsp;Now, it is purely for activating selection (aka multiselect). &nbsp;Every longtime Android developer should be aware of this change.<br /><br />(Personally, I didn't even notice this change despite owning a Galaxy Nexus for a month. &nbsp;Perhaps that's because not even every Google app has switched to the new design yet. &nbsp;Or perhaps it's because long touch is just not an intuitive way to design any functionality - I've long since given up putting any core functionality into long touch. &nbsp;Still, it's worth noting the design shift.)<br /><br /><a href=\"http://developer.android.com/design/patterns/pure-android.html\"><b>Android is not the iPhone</b></a> - At least, that's what this section *should* be called. &nbsp;This page will be most useful for showing to your designer or boss how Android differs from iPhone and why you shouldn't just port assets and design directly from one to the other.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1326467340000,
"created_by": 1,
"updated_at": 1386866031987,
"updated_by": 1,
"published_at": 1326467340000,
"published_by": 1
},
{
"id": 39,
"title": "GridLayout Library for Android 1.5+ Support",
"slug": "grid_layout_library_for_android_1_5_support",
"markdown": "If you're like me, when you first heard about [GridLayout](http://developer.android.com/reference/android/widget/GridLayout.html), you were excited. &nbsp;Then disappointed, because it's currently only available for Ice Cream Sandwich. &nbsp;That is true no longer - I've taken the time to port a working version of it all the way back to Android 1.5 and above.\n\n[Check out the android-gridlayout library here.](https://github.com/dlew/android-gridlayout)\n\nThe one caveat is that there is one method in GridLayout that I was not able to port back. &nbsp;As a result, when you change the visibility of a child View of a compatibility GridLayout, you should also call GridLayout.notifyChildVisibilityChanged().\n\nLet me know what you think, especially if there are any bugs.",
"html": "If you're like me, when you first heard about <a href=\"http://developer.android.com/reference/android/widget/GridLayout.html\">GridLayout</a>, you were excited. &nbsp;Then disappointed, because it's currently only available for Ice Cream Sandwich. &nbsp;That is true no longer - I've taken the time to port a working version of it all the way back to Android 1.5 and above.<br /><br /><a href=\"https://github.com/dlew/android-gridlayout\">Check out the android-gridlayout library here.</a><br /><br />The one caveat is that there is one method in GridLayout that I was not able to port back. &nbsp;As a result, when you change the visibility of a child View of a compatibility GridLayout, you should also call GridLayout.notifyChildVisibilityChanged().<br /><br />Let me know what you think, especially if there are any bugs.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1326210720000,
"created_by": 1,
"updated_at": 1386865956696,
"updated_by": 1,
"published_at": 1326210720000,
"published_by": 1
},
{
"id": 40,
"title": "Sharing with Gmail",
"slug": "sharing_with_gmail",
"markdown": "I read through [the Android Training docs](http://developer.android.com/training/index.html) recently and came across [a section](http://developer.android.com/training/sharing/send.html#send-binary-content) which I thought I could use to improve sharing on [Rage Faces](https://github.com/dlew/android-ragefaces) (by getting rid of the need for an SD card-based share system):\n\n> <span style=\"background-color: white; color: #333333; font-family: arial, sans-serif; font-size: 13px; line-height: 16px;\">Write the data to a file in your own application directory using&nbsp;</span>`[openFileOutput()](http://developer.android.com/reference/android/content/Context.html#openFileOutput(java.lang.String, int))`<span style=\"background-color: white; color: #333333; font-family: arial, sans-serif; font-size: 13px; line-height: 16px;\">&nbsp;with mode&nbsp;</span>`[MODE_WORLD_READABLE](http://developer.android.com/reference/android/content/Context.html#MODE_WORLD_READABLE)`<span style=\"background-color: white; color: #333333; font-family: arial, sans-serif; font-size: 13px; line-height: 16px;\">&nbsp;after which&nbsp;</span>`[getFileStreamPath()](http://developer.android.com/reference/android/content/Context.html#getFileStreamPath(java.lang.String))`<span style=\"background-color: white; color: #333333; font-family: arial, sans-serif; font-size: 13px; line-height: 16px;\">&nbsp;can be used to return a&nbsp;</span>`[File](http://developer.android.com/reference/java/io/File.html)`<span style=\"background-color: white; color: #333333; font-family: arial, sans-serif; font-size: 13px; line-height: 16px;\">. As with the previous option,&nbsp;</span>`[Uri.fromFile()](http://developer.android.com/reference/android/net/Uri.html#fromFile(java.io.File))`<span style=\"background-color: white; color: #333333; font-family: arial, sans-serif; font-size: 13px; line-height: 16px;\">&nbsp;will create a&nbsp;</span>`file://`<span style=\"background-color: white; color: #333333; font-family: arial, sans-serif; font-size: 13px; line-height: 16px;\">&nbsp;style&nbsp;</span>`[Uri](http://developer.android.com/reference/android/net/Uri.html)`<span style=\"background-color: white; color: #333333; font-family: arial, sans-serif; font-size: 13px; line-height: 16px;\">&nbsp;for your share intent.</span>However, this setup fails to work with the Gmail. &nbsp;When you try to share with Gmail in this manner, an error message pops up in the logs:\n\n> <span style=\"background-color: #fbfbfb; color: #333333; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 12px; line-height: 18px;\">file:// attachment paths must point to file:///mnt/sdcard. Ignoring attachment file:///data/data/com.idunnolol.ragefaces/files/share.png</span>I'm not sure why Gmail arbitrarily rejects attachments not on the SD card, but it pretty much cuts you off from sharing files with MODE_WORLD_READABLE. &nbsp;Unfortunately sharing with Gmail feels like an essential part of the app so I'm going to have to stick with SD card sharing.",
"html": "I read through <a href=\"http://developer.android.com/training/index.html\">the Android Training docs</a> recently and came across <a href=\"http://developer.android.com/training/sharing/send.html#send-binary-content\">a section</a> which I thought I could use to improve sharing on <a href=\"https://github.com/dlew/android-ragefaces\">Rage Faces</a> (by getting rid of the need for an SD card-based share system):<br /><br /><blockquote class=\"tr_bq\"><span style=\"background-color: white; color: #333333; font-family: arial, sans-serif; font-size: 13px; line-height: 16px;\">Write the data to a file in your own application directory using&nbsp;</span><code style=\"background-color: white; color: #007000; font-size: 13px; line-height: 1em;\"><a href=\"http://developer.android.com/reference/android/content/Context.html#openFileOutput(java.lang.String, int)\" style=\"color: #006699;\">openFileOutput()</a></code><span style=\"background-color: white; color: #333333; font-family: arial, sans-serif; font-size: 13px; line-height: 16px;\">&nbsp;with mode&nbsp;</span><code style=\"background-color: white; color: #007000; font-size: 13px; line-height: 1em;\"><a href=\"http://developer.android.com/reference/android/content/Context.html#MODE_WORLD_READABLE\" style=\"color: #006699;\">MODE_WORLD_READABLE</a></code><span style=\"background-color: white; color: #333333; font-family: arial, sans-serif; font-size: 13px; line-height: 16px;\">&nbsp;after which&nbsp;</span><code style=\"background-color: white; color: #007000; font-size: 13px; line-height: 1em;\"><a href=\"http://developer.android.com/reference/android/content/Context.html#getFileStreamPath(java.lang.String)\" style=\"color: #006699;\">getFileStreamPath()</a></code><span style=\"background-color: white; color: #333333; font-family: arial, sans-serif; font-size: 13px; line-height: 16px;\">&nbsp;can be used to return a&nbsp;</span><code style=\"background-color: white; color: #007000; font-size: 13px; line-height: 1em;\"><a href=\"http://developer.android.com/reference/java/io/File.html\" style=\"color: #006699;\">File</a></code><span style=\"background-color: white; color: #333333; font-family: arial, sans-serif; font-size: 13px; line-height: 16px;\">. As with the previous option,&nbsp;</span><code style=\"background-color: white; color: #007000; font-size: 13px; line-height: 1em;\"><a href=\"http://developer.android.com/reference/android/net/Uri.html#fromFile(java.io.File)\" style=\"color: #006699;\">Uri.fromFile()</a></code><span style=\"background-color: white; color: #333333; font-family: arial, sans-serif; font-size: 13px; line-height: 16px;\">&nbsp;will create a&nbsp;</span><code style=\"background-color: white; color: #007000; font-size: 13px; line-height: 1em;\">file://</code><span style=\"background-color: white; color: #333333; font-family: arial, sans-serif; font-size: 13px; line-height: 16px;\">&nbsp;style&nbsp;</span><code style=\"background-color: white; color: #007000; font-size: 13px; line-height: 1em;\"><a href=\"http://developer.android.com/reference/android/net/Uri.html\" style=\"color: #006699;\">Uri</a></code><span style=\"background-color: white; color: #333333; font-family: arial, sans-serif; font-size: 13px; line-height: 16px;\">&nbsp;for your share intent.</span></blockquote>However, this setup fails to work with the Gmail. &nbsp;When you try to share with Gmail in this manner, an error message pops up in the logs:<br /><br /><blockquote class=\"tr_bq\"><span style=\"background-color: #fbfbfb; color: #333333; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 12px; line-height: 18px;\">file:// attachment paths must point to file:///mnt/sdcard. Ignoring attachment file:///data/data/com.idunnolol.ragefaces/files/share.png</span></blockquote>I'm not sure why Gmail arbitrarily rejects attachments not on the SD card, but it pretty much cuts you off from sharing files with MODE_WORLD_READABLE. &nbsp;Unfortunately sharing with Gmail feels like an essential part of the app so I'm going to have to stick with SD card sharing.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1324407600000,
"created_by": 1,
"updated_at": 1324407605681,
"updated_by": 1,
"published_at": 1324407600000,
"published_by": 1
},
{
"id": 41,
"title": "TextWatchers and onRestoreInstanceState()",
"slug": "text_watchers_and_on_restore_instance_state_",
"markdown": "There's a small timing issue I'd like to mention because it's bitten me a few times now.\n\nWhen you want to observe changes to an [EditText](http://developer.android.com/reference/android/widget/EditText.html), you add a [TextWatcher](http://developer.android.com/reference/android/text/TextWatcher.html) to it (via [TextView. addTextChangedListener()](http://developer.android.com/reference/android/widget/TextView.html#addTextChangedListener(android.text.TextWatcher))). There are a lot of uses for TextWatchers, like implementing your own autocomplete or filters based on a dynamic EditText. The only thing you have to be careful of is whether the text was changed by the user or the code - the listener fires either way.\n\nWhat's worth knowing about an EditText is that it will save and restore the state of the text inside of it within your Activity. That means that when you rotate the screen, the EditText will restore the text that was inside of it. And most importantly, <span style=\"font-weight:bold;\">the automated restoring of the text on rotation causes the TextWatcher's methods to fire</span>. Like I said - the TextWatcher doesn't discern between whether the user changed the EditText or the system did.\n\nThe solution is simple - just don't add the TextWatcher until after the EditText's content has been restored. It restores itself in Activity.onRestoreInstanceState(), which makes Activity.onResume() the preferred time to add TextWatchers to any EditTexts.",
"html": "There's a small timing issue I'd like to mention because it's bitten me a few times now.<br /><br />When you want to observe changes to an <a href=\"http://developer.android.com/reference/android/widget/EditText.html\">EditText</a>, you add a <a href=\"http://developer.android.com/reference/android/text/TextWatcher.html\">TextWatcher</a> to it (via <a href=\"http://developer.android.com/reference/android/widget/TextView.html#addTextChangedListener(android.text.TextWatcher)\">TextView. addTextChangedListener()</a>). There are a lot of uses for TextWatchers, like implementing your own autocomplete or filters based on a dynamic EditText. The only thing you have to be careful of is whether the text was changed by the user or the code - the listener fires either way.<br /><br />What's worth knowing about an EditText is that it will save and restore the state of the text inside of it within your Activity. That means that when you rotate the screen, the EditText will restore the text that was inside of it. And most importantly, <span style=\"font-weight:bold;\">the automated restoring of the text on rotation causes the TextWatcher's methods to fire</span>. Like I said - the TextWatcher doesn't discern between whether the user changed the EditText or the system did.<br /><br />The solution is simple - just don't add the TextWatcher until after the EditText's content has been restored. It restores itself in Activity.onRestoreInstanceState(), which makes Activity.onResume() the preferred time to add TextWatchers to any EditTexts.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1320076800000,
"created_by": 1,
"updated_at": 1320076810851,
"updated_by": 1,
"published_at": 1320076800000,
"published_by": 1
},
{
"id": 42,
"title": "Android Drawable XML Talk",
"slug": "android_drawable_xml_talk",
"markdown": "I recently gave a talk on the basics of Android drawable resources (via XML).\n\nThere's a recording I made of the talk - not super, but functional. I had to split it into two parts because of time restrictions on YouTube. Here's [part one](http://www.youtube.com/watch?v=pxeqA0lW158) and [part two](http://www.youtube.com/watch?v=DNC-OpFWxuE).\n\nI also have a few links that may be useful (whether you watch the talk or not):\n\n- [The slides for the presentation](https://github.com/dlew/android-drawable-xml-demo/raw/master/slides.pptx )\n\n- [Official Android drawable resource documentation](http://developer.android.com/guide/topics/resources/drawable-resource.html)\n\n- [My drawable XML documentation](http://idunnolol.com/android/drawables.html)\n\n- [The github project with my samples](https://github.com/dlew/android-drawable-xml-demo)",
"html": "I recently gave a talk on the basics of Android drawable resources (via XML).<br /><br />There's a recording I made of the talk - not super, but functional. I had to split it into two parts because of time restrictions on YouTube. Here's <a href=\"http://www.youtube.com/watch?v=pxeqA0lW158\">part one</a> and <a href=\"http://www.youtube.com/watch?v=DNC-OpFWxuE\">part two</a>.<br /><br />I also have a few links that may be useful (whether you watch the talk or not):<br /><br />- <a href=\"https://github.com/dlew/android-drawable-xml-demo/raw/master/slides.pptx \">The slides for the presentation</a><br /><br />- <a href=\"http://developer.android.com/guide/topics/resources/drawable-resource.html\">Official Android drawable resource documentation</a><br /><br />- <a href=\"http://idunnolol.com/android/drawables.html\">My drawable XML documentation</a><br /><br />- <a href=\"https://github.com/dlew/android-drawable-xml-demo\">The github project with my samples</a>",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1318266000000,
"created_by": 1,
"updated_at": 1318266001206,
"updated_by": 1,
"published_at": 1318266000000,
"published_by": 1
},
{
"id": 43,
"title": "Logc.at",
"slug": "logc_at",
"markdown": "A few developers and I have formed a new Android development blog. We snagged what I think is an awesome and nerdy url: [logc.at](http://logc.at).\n\nI will still be writing here - this blog is intended for one-off coding issues that I want to document. The new blog will be a place for me to write about Android development in a more general manner. Instead of assisting with individual hurdles, I hope my articles there will help one become a better Android developer (or at least pick up a few tips).\n\nMy first post is about [working with JSON on Android](http://logc.at/2011/09/26/working-with-json/). Check it out!",
"html": "A few developers and I have formed a new Android development blog. We snagged what I think is an awesome and nerdy url: <a href=\"http://logc.at\">logc.at</a>.<br /><br />I will still be writing here - this blog is intended for one-off coding issues that I want to document. The new blog will be a place for me to write about Android development in a more general manner. Instead of assisting with individual hurdles, I hope my articles there will help one become a better Android developer (or at least pick up a few tips).<br /><br />My first post is about <a href=\"http://logc.at/2011/09/26/working-with-json/\">working with JSON on Android</a>. Check it out!",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1317068580000,
"created_by": 1,
"updated_at": 1317069085997,
"updated_by": 1,
"published_at": 1317068580000,
"published_by": 1
},
{
"id": 44,
"title": "New to Android: More Style Restrictions",
"slug": "new_to_android_more_style_restrictions",
"markdown": "There have been two changes the Android platform build tools which have caught me off guard. You may run into these problems when you next update your aapt. Both of them cause compilation errors, so they're not easy to ignore, but it's not immediately obvious how to fix either.\n\n<span style=\"font-weight:bold;\">Change #1: Implicit parenting now requires a parent</span>\n\nSuppose I have this style defined in styles.xml:\n\n<pre>&lt;style name=\"Widget.MyWidget.Small\"> ... &lt;/style></pre>\nIt was named that way after how Android sets up their widget styles (for example, \"Widget.RatingBar.Small\"). One thing to know is the implicit aspects to using dots in the naming is that you automatically parent all the styles before the dot. So \"Widget\" is the parent of \"Widget.MyWidget\", and \"Widget.MyWidget\" is the parent of \"Widget.MyWidget.Small\".\n\nIn the new version of aapt, you'll see this error:\n\n<pre>Error retrieving parent for item: No resource found that matches the given name '@Style/Widget.MyWidget'.</pre>\nThis happens now because aapt is stricter with regards to style parenting. Before, if there was no parent, it would just ignore this oversight; now it requires a parent.\n\nThere are two possible solutions:\n\n1\\. Rename the style so that it doesn't use implicit parenting with dots.\n\n2\\. Create the parent styles. They could either be empty, or you could actually use them for something.\n\nI think #1 makes more sense, unless you actually have a use for the parent styles.\n\n<span style=\"font-weight:bold;\">Change #2: Some android styles are now enforced as private</span>\n\nBefore, you used to be able to get away with parenting some non-public Android styles:\n\n<pre>&lt;style name=\"MyRatingBar\" parent=\"@android:style/Widget.RatingBar.Small\"> ... &lt;/style></pre>\nHowever, these styles have always been intended to be private, and the latest aapt will not allow you to build with a private parent defined. [A Google employee explained the reason why this is no longer allowed:](http://code.google.com/p/android/issues/detail?id=18659#c8)\n\n> For the framework, only public resources are guaranteed to only have the same integer, build after build. The integer of private resources integer will change from build to build. This means that your custom style is referencing a parent that *will not* be valid once installed on a device. It'll referenced either another resources or none at all, and it won't do what you want.\n\nThat seems reasonable to me. The solution is to just import the entire style into your styles.xml; all the styles are [open source](http://android.git.kernel.org/?p=platform/frameworks/base.git;a=tree;f=core/res/res/values) anyways.",
"html": "There have been two changes the Android platform build tools which have caught me off guard. You may run into these problems when you next update your aapt. Both of them cause compilation errors, so they're not easy to ignore, but it's not immediately obvious how to fix either.<br /><br /><span style=\"font-weight:bold;\">Change #1: Implicit parenting now requires a parent</span><br /><br />Suppose I have this style defined in styles.xml:<br /><br /><pre>&lt;style name=\"Widget.MyWidget.Small\"> ... &lt;/style></pre><br />It was named that way after how Android sets up their widget styles (for example, \"Widget.RatingBar.Small\"). One thing to know is the implicit aspects to using dots in the naming is that you automatically parent all the styles before the dot. So \"Widget\" is the parent of \"Widget.MyWidget\", and \"Widget.MyWidget\" is the parent of \"Widget.MyWidget.Small\".<br /><br />In the new version of aapt, you'll see this error:<br /><br /><pre>Error retrieving parent for item: No resource found that matches the given name '@Style/Widget.MyWidget'.</pre><br />This happens now because aapt is stricter with regards to style parenting. Before, if there was no parent, it would just ignore this oversight; now it requires a parent.<br /><br />There are two possible solutions:<br /><br />1. Rename the style so that it doesn't use implicit parenting with dots.<br /><br />2. Create the parent styles. They could either be empty, or you could actually use them for something.<br /><br />I think #1 makes more sense, unless you actually have a use for the parent styles.<br /><br /><span style=\"font-weight:bold;\">Change #2: Some android styles are now enforced as private</span><br /><br />Before, you used to be able to get away with parenting some non-public Android styles:<br /><br /><pre>&lt;style name=\"MyRatingBar\" parent=\"@android:style/Widget.RatingBar.Small\"> ... &lt;/style></pre><br />However, these styles have always been intended to be private, and the latest aapt will not allow you to build with a private parent defined. <a href=\"http://code.google.com/p/android/issues/detail?id=18659#c8\">A Google employee explained the reason why this is no longer allowed:</a><br /><br /><blockquote>For the framework, only public resources are guaranteed to only have the same integer, build after build. The integer of private resources integer will change from build to build. This means that your custom style is referencing a parent that *will not* be valid once installed on a device. It'll referenced either another resources or none at all, and it won't do what you want.</blockquote><br /><br />That seems reasonable to me. The solution is to just import the entire style into your styles.xml; all the styles are <a href=\"http://android.git.kernel.org/?p=platform/frameworks/base.git;a=tree;f=core/res/res/values\">open source</a> anyways.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1312308000000,
"created_by": 1,
"updated_at": 1312309148186,
"updated_by": 1,
"published_at": 1312308000000,
"published_by": 1
},
{
"id": 45,
"title": "Honeycomb App Widget and Backwards Compatibility",
"slug": "honeycomb_app_widget_and_backwards_compatibility",
"markdown": "Honeycomb added [some neat functionality](http://developer.android.com/guide/topics/appwidgets/index.html#collections) to Android widgets. However, there's a problem that arises from adding a widget using collections to your app - what if your APK is supposed to work on all versions of Android? How do you prevent the Honeycomb-only widget from appearing in previous versions?\n\nNormally when you want to do something different between versions of Android, you either use [resource qualifiers](http://developer.android.com/guide/topics/resources/providing-resources.html#AlternativeResources) (for XML) or check [Build](http://developer.android.com/reference/android/os/Build.html) (for code). But in this case, the widget itself is defined in AndroidManifest.xml, which can only be at the root of your project.\n\nThere's a way of removing the app widget from the listing in previous versions: use resource qualifiers on the AppWidgetProviderInfo resource.\n\nWhen you define an app widget in AndroidManifest.xml, you must also define a &lt;meta-data&gt; element which points towards the AppWidgetProviderInfo (that is usually contained inside of a file in /res/xml/). Simply move that provider file to a directory that only Honeycomb can see - <span style=\"font-weight: bold;\">/res/xml-v11/</span>. Earlier versions of Android will try to load the widget only to find no AppWidgetProviderInfo and will thus ignore the widget.\n\nUDPATE (Jan 26th, 2012): [I've now written about an improved solution to this problem.](http://daniel-codes.blogspot.com/2012/01/another-app-widget-compatibility-trick.html)",
"html": "Honeycomb added <a href=\"http://developer.android.com/guide/topics/appwidgets/index.html#collections\">some neat functionality</a> to Android widgets. However, there's a problem that arises from adding a widget using collections to your app - what if your APK is supposed to work on all versions of Android? How do you prevent the Honeycomb-only widget from appearing in previous versions?<br /><br />Normally when you want to do something different between versions of Android, you either use <a href=\"http://developer.android.com/guide/topics/resources/providing-resources.html#AlternativeResources\">resource qualifiers</a> (for XML) or check <a href=\"http://developer.android.com/reference/android/os/Build.html\">Build</a> (for code). But in this case, the widget itself is defined in AndroidManifest.xml, which can only be at the root of your project.<br /><br />There's a way of removing the app widget from the listing in previous versions: use resource qualifiers on the AppWidgetProviderInfo resource.<br /><br />When you define an app widget in AndroidManifest.xml, you must also define a &lt;meta-data&gt; element which points towards the AppWidgetProviderInfo (that is usually contained inside of a file in /res/xml/). Simply move that provider file to a directory that only Honeycomb can see - <span style=\"font-weight: bold;\">/res/xml-v11/</span>. Earlier versions of Android will try to load the widget only to find no AppWidgetProviderInfo and will thus ignore the widget.<br /><br />UDPATE (Jan 26th, 2012): <a href=\"http://daniel-codes.blogspot.com/2012/01/another-app-widget-compatibility-trick.html\">I've now written about an improved solution to this problem.</a>",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1309460460000,
"created_by": 1,
"updated_at": 1327606971308,
"updated_by": 1,
"published_at": 1309460460000,
"published_by": 1
},
{
"id": 46,
"title": "Passwords: Longer, Not More Complex",
"slug": "passwords_longer_not_more_complex",
"markdown": "I was going through a mandatory security training course for my company when I came across a slide about passwords. Its advice was that the password should be at least 7 characters long and include a good mixture of lower/upper case characters, plus numbers and special symbols. Sony is using the same tactics. I had to change my PSN password and it forced me to use at least one number and one letter in the password.\n\nThis is totally bunk advice. <span style=\"font-weight:bold;\">What you want is a long password, and it doesn't have to be complex</span>.\n\nSuppose there's a server with your credentials that has the bare essentials of good security ([hash](http://en.wikipedia.org/wiki/Cryptographic_hash_function) + [salt](http://en.wikipedia.org/wiki/Salt_(cryptography))). If someone compromises the server, they will have to crack your password by checking every single password against the hash in the database. Therefore, the more possible passwords your scheme contains, the longer it takes to crack.\n\nYou can calculate an approximation on number of attempted passwords a cracker will have to attempt with this simple formula: (size of character set)^<sup>(password length)</sup>. Given a rudimentary understanding of exponents, it's pretty evident that increasing the password length will have a lot more impact than expanding the character set size.\n\nLet's look at some numbers. On my keyboard, there are 95 characters I could insert into a password. Let's compare a length eight password using that character set to a slightly longer password using only lower case letters (a 26 size character set):\n\n95^<sup>8</sup> ~= <span style=\"font-weight:bold;\">6 quadrillion</span> (or ~10^<sup>15</sup>)\n26^<sup>12</sup> ~= <span style=\"font-weight:bold;\">90 quadrillion</span> (or ~10^<sup>16</sup>)\n26^<sup>15</sup> ~= <span style=\"font-weight:bold;\">1 sextillion</span> (or ~10^<sup>21</sup>)\n\nWith four extra characters, my simpler password is already harder to crack than the complex eight character password.\n\nThe best part about using a limited character set is that you can create a pass <span style=\"font-weight:bold;\">phrases</span> instead of pass <span style=\"font-weight:bold;\">words</span>. It's much easier to remember \"please do not break into my account\" than \"x82@.Zij\", and it's also far more resilient to cracking, too.\n\nUnfortunately, not all sites allow for long passwords. In those cases, it's better to use a more complex character set. But when given the opportunity, a long and simple password is vastly superior to a short but complicated one.\n\n<span style=\"font-weight:bold;\">Addendum</span>: A friend pointed out that pass phrases are more vulnerable to dictionary attacks. This is true, but only if your pass phrase contains very few words. The approximate effort for pass phrases is (number of possible words)^<sup>(number of words)</sup>. [Given how many possible words there are](http://oxforddictionaries.com/page/93), it only takes a phrase of a few words to be as secure as 15 simple characters of nonsense. So while \"supercalifragilisticexpialidocious\" is a crappy password despite how long it is, my example from above (\"please do not break into my account\") is still very secure.",
"html": "I was going through a mandatory security training course for my company when I came across a slide about passwords. Its advice was that the password should be at least 7 characters long and include a good mixture of lower/upper case characters, plus numbers and special symbols. Sony is using the same tactics. I had to change my PSN password and it forced me to use at least one number and one letter in the password.<br /><br />This is totally bunk advice. <span style=\"font-weight:bold;\">What you want is a long password, and it doesn't have to be complex</span>.<br /><br />Suppose there's a server with your credentials that has the bare essentials of good security (<a href=\"http://en.wikipedia.org/wiki/Cryptographic_hash_function\">hash</a> + <a href=\"http://en.wikipedia.org/wiki/Salt_(cryptography)\">salt</a>). If someone compromises the server, they will have to crack your password by checking every single password against the hash in the database. Therefore, the more possible passwords your scheme contains, the longer it takes to crack.<br /><br />You can calculate an approximation on number of attempted passwords a cracker will have to attempt with this simple formula: (size of character set)^<sup>(password length)</sup>. Given a rudimentary understanding of exponents, it's pretty evident that increasing the password length will have a lot more impact than expanding the character set size.<br /><br />Let's look at some numbers. On my keyboard, there are 95 characters I could insert into a password. Let's compare a length eight password using that character set to a slightly longer password using only lower case letters (a 26 size character set):<br /><br />95^<sup>8</sup> ~= <span style=\"font-weight:bold;\">6 quadrillion</span> (or ~10^<sup>15</sup>)<br />26^<sup>12</sup> ~= <span style=\"font-weight:bold;\">90 quadrillion</span> (or ~10^<sup>16</sup>)<br />26^<sup>15</sup> ~= <span style=\"font-weight:bold;\">1 sextillion</span> (or ~10^<sup>21</sup>)<br /><br />With four extra characters, my simpler password is already harder to crack than the complex eight character password.<br /><br />The best part about using a limited character set is that you can create a pass <span style=\"font-weight:bold;\">phrases</span> instead of pass <span style=\"font-weight:bold;\">words</span>. It's much easier to remember \"please do not break into my account\" than \"x82@.Zij\", and it's also far more resilient to cracking, too.<br /><br />Unfortunately, not all sites allow for long passwords. In those cases, it's better to use a more complex character set. But when given the opportunity, a long and simple password is vastly superior to a short but complicated one.<br /><br /><span style=\"font-weight:bold;\">Addendum</span>: A friend pointed out that pass phrases are more vulnerable to dictionary attacks. This is true, but only if your pass phrase contains very few words. The approximate effort for pass phrases is (number of possible words)^<sup>(number of words)</sup>. <a href=\"http://oxforddictionaries.com/page/93\">Given how many possible words there are</a>, it only takes a phrase of a few words to be as secure as 15 simple characters of nonsense. So while \"supercalifragilisticexpialidocious\" is a crappy password despite how long it is, my example from above (\"please do not break into my account\") is still very secure.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1306864800000,
"created_by": 1,
"updated_at": 1306877249656,
"updated_by": 1,
"published_at": 1306864800000,
"published_by": 1
},
{
"id": 47,
"title": "Using Subquery Columns on Android with SQLite",
"slug": "using_subquery_columns_on_android_with_sqlite",
"markdown": "Take a look at this (contrived) query, as might be passed to [SQLiteDatabase.rawQuery()](http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#rawQuery(java.lang.String, java.lang.String[])):\n\n<pre>SELECT *\nFROM t1 A, (SELECT T2.id FROM t2 T2) B\nWHERE A.id = B.id</pre>\nOn Android 2.1 and below, this query will cause your app to crash. You'll get an error like this:\n\n<pre>Caused by: android.database.sqlite.SQLiteException: no such column: B.id: , while compiling: SELECT * FROM t1 A, (SELECT T2.id FROM t2 T2) B WHERE A.id = B.id\n at android.database.sqlite.SQLiteProgram.native_compile(Native Method)\n at android.database.sqlite.SQLiteProgram.compile(SQLiteProgram.java:110)\n at android.database.sqlite.SQLiteProgram.&lt;init>(SQLiteProgram.java:59)\n at android.database.sqlite.SQLiteQuery.&lt;init>(SQLiteQuery.java:49)\n at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:49)\n at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1220)\n at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1193)\n at com.mycompany.myapp.MyActivity.onCreate(QuickTestActivity.java:22)\n at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)\n at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2459)\n ... 11 more</pre>\nIt turns out that SQLite throws this error if two conditions are met:\n\nThe solution is simple: <span style=\"font-weight:bold;\">alias the selected field names</span>. This query will work:\n\n<pre>SELECT *\nFROM t1 A, (SELECT T2.id AS id FROM t2 T2) B\nWHERE A.id = B.id</pre>\nI'm hardly an expert on SQL or SQLite, so I don't know whether this is a bug or just me running into undefined behavior. I ran into this problem when doing JOINs on multiple tables, so as contrived as my example is, it can happen. Regardless, it is easy to work around.",
"html": "Take a look at this (contrived) query, as might be passed to <a href=\"http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#rawQuery(java.lang.String, java.lang.String[])\">SQLiteDatabase.rawQuery()</a>:<br /><br /><pre>SELECT *<br />FROM t1 A, (SELECT T2.id FROM t2 T2) B<br />WHERE A.id = B.id</pre><br />On Android 2.1 and below, this query will cause your app to crash. You'll get an error like this:<br /><br /><pre>Caused by: android.database.sqlite.SQLiteException: no such column: B.id: , while compiling: SELECT * FROM t1 A, (SELECT T2.id FROM t2 T2) B WHERE A.id = B.id<br /> at android.database.sqlite.SQLiteProgram.native_compile(Native Method)<br /> at android.database.sqlite.SQLiteProgram.compile(SQLiteProgram.java:110)<br /> at android.database.sqlite.SQLiteProgram.&lt;init>(SQLiteProgram.java:59)<br /> at android.database.sqlite.SQLiteQuery.&lt;init>(SQLiteQuery.java:49)<br /> at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:49)<br /> at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1220)<br /> at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1193)<br /> at com.mycompany.myapp.MyActivity.onCreate(QuickTestActivity.java:22)<br /> at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)<br /> at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2459)<br /> ... 11 more</pre><br />It turns out that SQLite throws this error if two conditions are met:<br /><ol><li>You use a subquery (in this case, the select subquery from table t2).<br /><br /><li>Your subquery has a table alias (in this case, referencing table t2 as \"T2\").</ol><br />The solution is simple: <span style=\"font-weight:bold;\">alias the selected field names</span>. This query will work:<br /><br /><pre>SELECT *<br />FROM t1 A, (SELECT T2.id AS id FROM t2 T2) B<br />WHERE A.id = B.id</pre><br />I'm hardly an expert on SQL or SQLite, so I don't know whether this is a bug or just me running into undefined behavior. I ran into this problem when doing JOINs on multiple tables, so as contrived as my example is, it can happen. Regardless, it is easy to work around.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1306256400000,
"created_by": 1,
"updated_at": 1306260650231,
"updated_by": 1,
"published_at": 1306256400000,
"published_by": 1
},
{
"id": 48,
"title": "Detecting the Keystore Signature in Code",
"slug": "detecting_the_keystore_signature_in_code",
"markdown": "Here's a problem I'm sure many of us have faced: you've got code that runs one way when you're developing and another way when you're releasing. A few examples I've run into:\n\n- Logging during development, but disabled for release.\n- Targeting development vs. production servers.\n- [MapView](http://code.google.com/android/add-ons/google-apis/reference/com/google/android/maps/MapView.html) requires an API key tied to the signing key.\n\nBefore, I just setup static parameters in code that I'd have to remember to change before making a release build. It's a pain and error prone.\n\nI've just determined a much better (and more automatic) way - detecting the [signing keystore](http://developer.android.com/guide/publishing/app-signing.html) in code. Through use of the [PackageManager](http://developer.android.com/reference/android/content/pm/PackageManager.html) you can actually determine the [Signature](http://developer.android.com/reference/android/content/pm/Signature.html) of the app that's currently running.\n\nFirst, you need to get the Signature of your release keystore. Put this code into your application temporarily, then sign it with your release keystore and run it:\n\n<pre>PackageInfo pi = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);\nLog.i(\"test\", pi.signatures[0].toCharsString());</pre>\nTake the output from logcat and put it into this method:\n\n<pre>private static final Signature SIG_RELEASE = new Signature(\"&lt;YOUR SIGNATURE HERE>\");\n\npublic static boolean isRelease(Context context) {\n try {\n PackageManager pm = context.getPackageManager();\n PackageInfo pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);\n for (Signature sig : pi.signatures) {\n if (sig.equals(SIG_RELEASE)) {\n return true;\n }\n }\n }\n catch (Exception e) {\n Log.w(\"Exception thrown when detecting if app is signed by a release keystore.\", e);\n\n // Return true if we can't figure it out, just to play it safe\n return true;\n }\n\n return false;\n}</pre>\nNow you can always call isRelease() and check whether your app was signed by your release keystore. No more having to edit files to create a release version of your app - just sign it with the correct keystore and you're ready to go!",
"html": "Here's a problem I'm sure many of us have faced: you've got code that runs one way when you're developing and another way when you're releasing. A few examples I've run into:<br /><br />- Logging during development, but disabled for release.<br />- Targeting development vs. production servers.<br />- <a href=\"http://code.google.com/android/add-ons/google-apis/reference/com/google/android/maps/MapView.html\">MapView</a> requires an API key tied to the signing key.<br /><br />Before, I just setup static parameters in code that I'd have to remember to change before making a release build. It's a pain and error prone.<br /><br />I've just determined a much better (and more automatic) way - detecting the <a href=\"http://developer.android.com/guide/publishing/app-signing.html\">signing keystore</a> in code. Through use of the <a href=\"http://developer.android.com/reference/android/content/pm/PackageManager.html\">PackageManager</a> you can actually determine the <a href=\"http://developer.android.com/reference/android/content/pm/Signature.html\">Signature</a> of the app that's currently running.<br /><br />First, you need to get the Signature of your release keystore. Put this code into your application temporarily, then sign it with your release keystore and run it:<br /><br /><pre>PackageInfo pi = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);<br />Log.i(\"test\", pi.signatures[0].toCharsString());</pre><br />Take the output from logcat and put it into this method:<br /><br /><pre>private static final Signature SIG_RELEASE = new Signature(\"&lt;YOUR SIGNATURE HERE>\");<br /><br />public static boolean isRelease(Context context) {<br /> try {<br /> PackageManager pm = context.getPackageManager();<br /> PackageInfo pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);<br /> for (Signature sig : pi.signatures) {<br /> if (sig.equals(SIG_RELEASE)) {<br /> return true;<br /> }<br /> }<br /> }<br /> catch (Exception e) {<br /> Log.w(\"Exception thrown when detecting if app is signed by a release keystore.\", e);<br /><br /> // Return true if we can't figure it out, just to play it safe<br /> return true;<br /> }<br /><br /> return false;<br />}</pre><br />Now you can always call isRelease() and check whether your app was signed by your release keystore. No more having to edit files to create a release version of your app - just sign it with the correct keystore and you're ready to go!",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1303927200000,
"created_by": 1,
"updated_at": 1303927207181,
"updated_by": 1,
"published_at": 1303927200000,
"published_by": 1
},
{
"id": 49,
"title": "HTML in TextViews",
"slug": "html_in_text_views",
"markdown": "There's a trick I've been increasingly using as I've learned how powerful it is: HTML in TextViews.\n\nI used to think that TextViews were pretty plain; they contained a CharSequence, and that was it. But it can actually contain a [Spanned](http://developer.android.com/reference/android/text/Spanned.html) (or its mutable cousin, [Spannable](http://developer.android.com/reference/android/text/Spannable.html)) buffer type as well. This means that there are a host of HTML tags that you can use to modify your TextView, which allows for different typefaces/functionality - all in the same TextView. Check out what you can do with just one string resource in a TextView:\n\n[![](http://1.bp.blogspot.com/-EYTU2tBpJ0g/TaRsK3OzigI/AAAAAAAAAIA/NRTNknH8T44/s320/html-textview.png)](http://1.bp.blogspot.com/-EYTU2tBpJ0g/TaRsK3OzigI/AAAAAAAAAIA/NRTNknH8T44/s1600/html-textview.png)\n\nHere's the string resource for above:\n\n<pre>&lt;string name=\"html\"&gt;This &lt;b&gt;is&lt;/b&gt; &lt;i&gt;all&lt;/i&gt; &lt;sub&gt;in&lt;/sub&gt; &lt;u&gt;&lt;sup&gt;one&lt;/sup&gt;&lt;/u&gt; &lt;a href=\"http://google.com\"&gt;TextView&lt;/a&gt;.&lt;/string&gt;</pre>\n[Android has tips on the basics of Html in TextViews](http://developer.android.com/resources/faq/commontasks.html#selectingtext), but it doesn't nearly cover some of the use cases. It also doesn't have a reference on which tags are supported (scroll to bottom for a reference I created).\n\nHere are a few tips:\n\n<span style=\"font-weight:bold;\">Links in TextViews</span>\n\nThe simplest way to add links to TextView is to use [the android:autoLink attribute](http://developer.android.com/reference/android/widget/TextView.html#attr_android:autoLink). However, this only allows you to link visible URIs in the text and can sometimes lead to undesired situations (I had an app that was detecting the copyright dates \"2009-2011\" as a phone number). By using the &lt;a&gt; tag, you can create links with any text that leads to any URI:\n\n<pre>&lt;string name=\"my_site\"&gt;&lt;a href=\"http://idunnolol.com\"&gt;My Website&lt;/a&gt;&lt;/string&gt;</pre>\nThere's only one catch: when you try to use this in a TextView, it won't be clickable unless you set the movement method in code:\n\n<pre>TextView myTextView = (TextView) findViewById(R.id.my_textview);\nmyTextView.setMovementMethod(LinkMovementMethod.getInstance());</pre>\n<span style=\"font-weight:bold;\">Dynamic Html</span>\n\nAll of the above examples have been with static text - that is, when the TextView's [android:text](http://developer.android.com/reference/android/widget/TextView.html#attr_android:text) attribute is set in XML from a string resource. What if you want to set a TextView's string resource in code? This is especially important when you use string formatting (which I'm a big fan of).\n\n[Android discusses this already](http://developer.android.com/guide/topics/resources/string-resource.html#FormattingAndStyling), but for posterity I'll repeat the process here:\n\n1\\. HTML-escape the string resource:\n\n<pre>&lt;string name=\"loud\"&gt;Loud text here: &amp;lt;b&gt;%s&amp;lt;/b&gt;&lt;/string&gt;</pre>\n2\\. Use [Html.fromHtml()](http://developer.android.com/reference/android/text/Html.html#fromHtml(java.lang.String)) to dynamically create a Spanned that a TextView can be styled with:\n\n<pre>Spanned spanned = Html.fromHtml(context.getString(R.string.loud, \"this is loud\"));\nmyTextView.setText(spanned);</pre>\n<span style=\"font-weight:bold;\">Handling Custom Tags</span>\n\nSo far so good, but I ran into a problem the other day: while the &lt;strike&gt; tag works if it's linked as a static string, it doesn't work when using Html.fromHtml(). I looked through the source code and discovered that Html.fromHtml() handles a different set of tags from static resources. Luckily, there's a way to handle tags that Html.fromHtml() doesn't: [the TagHandler interface](http://developer.android.com/reference/android/text/Html.TagHandler.html).\n\nIt's a little complex, but [here's one possible solution for how to handle the &lt;strike&gt; tag](http://stackoverflow.com/questions/4044509/android-how-to-use-the-html-taghandler). (My own solution differed a bit, but the essentials are the same.)\n\n<span style=\"font-weight:bold;\">Tags Supported in String Resources</span>\n\nTags in static string resources are parsed by [android.content.res.StringBlock](http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob_plain;f=core/java/android/content/res/StringBlock.java;hb=HEAD), which is a hidden class. I've looked through the class and determined which tags are supported:\n\n<span style=\"font-weight:bold;\">Tags Supported by Html.fromHtml()</span>\n\nFor some reason, Html.fromHtml() handles a different set of of tags than static text supports. Here's a list of the tags (gleaned from [Html.java's source code](http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob_plain;f=core/java/android/text/Html.java;hb=HEAD)):\n\nThe font \"color\" attribute supports some color names (along with the normal integer-based color scheme):",
"html": "There's a trick I've been increasingly using as I've learned how powerful it is: HTML in TextViews.<br /><br />I used to think that TextViews were pretty plain; they contained a CharSequence, and that was it. But it can actually contain a <a href=\"http://developer.android.com/reference/android/text/Spanned.html\">Spanned</a> (or its mutable cousin, <a href=\"http://developer.android.com/reference/android/text/Spannable.html\">Spannable</a>) buffer type as well. This means that there are a host of HTML tags that you can use to modify your TextView, which allows for different typefaces/functionality - all in the same TextView. Check out what you can do with just one string resource in a TextView:<br /><br /><a onblur=\"try {parent.deselectBloggerImageGracefully();} catch(e) {}\" href=\"http://1.bp.blogspot.com/-EYTU2tBpJ0g/TaRsK3OzigI/AAAAAAAAAIA/NRTNknH8T44/s1600/html-textview.png\"><img style=\"display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 84px;\" src=\"http://1.bp.blogspot.com/-EYTU2tBpJ0g/TaRsK3OzigI/AAAAAAAAAIA/NRTNknH8T44/s320/html-textview.png\" border=\"0\" alt=\"\"id=\"BLOGGER_PHOTO_ID_5594715570981538306\" /></a><br /><br />Here's the string resource for above:<br /><br /><pre>&lt;string name=\"html\"&gt;This &lt;b&gt;is&lt;/b&gt; &lt;i&gt;all&lt;/i&gt; &lt;sub&gt;in&lt;/sub&gt; &lt;u&gt;&lt;sup&gt;one&lt;/sup&gt;&lt;/u&gt; &lt;a href=\"http://google.com\"&gt;TextView&lt;/a&gt;.&lt;/string&gt;</pre><br /><a href=\"http://developer.android.com/resources/faq/commontasks.html#selectingtext\">Android has tips on the basics of Html in TextViews</a>, but it doesn't nearly cover some of the use cases. It also doesn't have a reference on which tags are supported (scroll to bottom for a reference I created).<br /><br />Here are a few tips:<br /><br /><span style=\"font-weight:bold;\">Links in TextViews</span><br /><br />The simplest way to add links to TextView is to use <a href=\"http://developer.android.com/reference/android/widget/TextView.html#attr_android:autoLink\">the android:autoLink attribute</a>. However, this only allows you to link visible URIs in the text and can sometimes lead to undesired situations (I had an app that was detecting the copyright dates \"2009-2011\" as a phone number). By using the &lt;a&gt; tag, you can create links with any text that leads to any URI:<br /><br /><pre>&lt;string name=\"my_site\"&gt;&lt;a href=\"http://idunnolol.com\"&gt;My Website&lt;/a&gt;&lt;/string&gt;</pre><br />There's only one catch: when you try to use this in a TextView, it won't be clickable unless you set the movement method in code:<br /><br /><pre>TextView myTextView = (TextView) findViewById(R.id.my_textview);<br />myTextView.setMovementMethod(LinkMovementMethod.getInstance());</pre><br /><span style=\"font-weight:bold;\">Dynamic Html</span><br /><br />All of the above examples have been with static text - that is, when the TextView's <a href=\"http://developer.android.com/reference/android/widget/TextView.html#attr_android:text\">android:text</a> attribute is set in XML from a string resource. What if you want to set a TextView's string resource in code? This is especially important when you use string formatting (which I'm a big fan of).<br /><br /><a href=\"http://developer.android.com/guide/topics/resources/string-resource.html#FormattingAndStyling\">Android discusses this already</a>, but for posterity I'll repeat the process here:<br /><br />1. HTML-escape the string resource:<br /><br /><pre>&lt;string name=\"loud\"&gt;Loud text here: &amp;lt;b&gt;%s&amp;lt;/b&gt;&lt;/string&gt;</pre><br />2. Use <a href=\"http://developer.android.com/reference/android/text/Html.html#fromHtml(java.lang.String)\">Html.fromHtml()</a> to dynamically create a Spanned that a TextView can be styled with:<br /><br /><pre>Spanned spanned = Html.fromHtml(context.getString(R.string.loud, \"this is loud\"));<br />myTextView.setText(spanned);</pre><br /><span style=\"font-weight:bold;\">Handling Custom Tags</span><br /><br />So far so good, but I ran into a problem the other day: while the &lt;strike&gt; tag works if it's linked as a static string, it doesn't work when using Html.fromHtml(). I looked through the source code and discovered that Html.fromHtml() handles a different set of tags from static resources. Luckily, there's a way to handle tags that Html.fromHtml() doesn't: <a href=\"http://developer.android.com/reference/android/text/Html.TagHandler.html\">the TagHandler interface</a>.<br /><br />It's a little complex, but <a href=\"http://stackoverflow.com/questions/4044509/android-how-to-use-the-html-taghandler\">here's one possible solution for how to handle the &lt;strike&gt; tag</a>. (My own solution differed a bit, but the essentials are the same.)<br /><br /><span style=\"font-weight:bold;\">Tags Supported in String Resources</span><br /><br />Tags in static string resources are parsed by <a href=\"http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob_plain;f=core/java/android/content/res/StringBlock.java;hb=HEAD\">android.content.res.StringBlock</a>, which is a hidden class. I've looked through the class and determined which tags are supported:<br /><ul><li>&lt;a&gt; (supports attributes \"href\")<br /><li>&lt;annotation&gt;<br /><li>&lt;b&gt;<br /><li>&lt;big&gt;<br /><li>&lt;font&gt; (supports attributes \"height\", \"size\", \"fgcolor\" and \"bicolor\", as integers)<br /><li>&lt;i&gt;<br /><li>&lt;li&gt;<br /><li>&lt;marquee&gt;<br /><li>&lt;small&gt;<br /><li>&lt;strike&gt;<br /><li>&lt;sub&gt;<br /><li>&lt;sup&gt;<br /><li>&lt;tt&gt;<br /><li>&lt;u&gt;</ul><br /><span style=\"font-weight:bold;\">Tags Supported by Html.fromHtml()</span><br /><br />For some reason, Html.fromHtml() handles a different set of of tags than static text supports. Here's a list of the tags (gleaned from <a href=\"http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob_plain;f=core/java/android/text/Html.java;hb=HEAD\">Html.java's source code</a>):<br /><ul><li>&lt;a&gt; (supports attribute \"href\")<br /><li>&lt;b&gt;<br /><li>&lt;big&gt;<br /><li>&lt;blockquote&gt;<br /><li>&lt;br&gt;<br /><li>&lt;cite&gt;<br /><li>&lt;dfn&gt;<br /><li>&lt;div&gt;<br /><li>&lt;em&gt;<br /><li>&lt;font&gt; (supports attributes \"color\" and \"face\")<br /><li>&lt;i&gt;<br /><li>&lt;img&gt; (supports attribute \"src\". Note: you have to include <a href=\"http://developer.android.com/reference/android/text/Html.ImageGetter.html\">an ImageGetter</a> to handle retrieving a Drawable for this tag)<br /><li>&lt;p&gt;<br /><li>&lt;small&gt;<br /><li>&lt;strong&gt;<br /><li>&lt;sub&gt;<br /><li>&lt;sup&gt;<br /><li>&lt;tt&gt;<br /><li>&lt;u&gt;</ul><br />The font \"color\" attribute supports some color names (along with the normal integer-based color scheme):<br /><ul><li>aqua<br /><li>black<br /><li>blue<br /><li>fuchsia<br /><li>green<br /><li>grey<br /><li>lime<br /><li>maroon<br /><li>navy<br /><li>olive<br /><li>purple<br /><li>red<br /><li>silver<br /><li>teal<br /><li>white<br /><li>yellow</ul>",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1302710400001,
"created_by": 1,
"updated_at": 1309298104683,
"updated_by": 1,
"published_at": 1302710400001,
"published_by": 1
},
{
"id": 50,
"title": "Image Sharing on Android",
"slug": "image_sharing_on_android",
"markdown": "One of the sillier projects I've worked on in my spare time is [Rage Faces for Android](https://market.android.com/details?id=com.idunnolol.ragefaces). It has almost no value to anyone, which is why it's free ([in every sense of the word](https://github.com/dlew/android-ragefaces)). However, it's been quite useful to me, as it's taught me a few things about sharing images on Android. Overall, I think this is a good reason for Android developers (or any developer, really) to have fun side projects to work on - there's almost no app so trivial that you can't learn something from doing it.\n\nHere's three big ones I learned from working on Rage Faces.\n\n<span style=\"font-weight:bold;\">Sharing Images</span>\n\nThe first thing it taught me is that you need space on the SD card in order to share images. This makes sense, as sending images (typically) uses the [ACTION_SEND](http://developer.android.com/reference/android/content/Intent.html#ACTION_SEND) intent along with a URI to the image. You can't link a URI to a resource inside your application package, so you have to put it somewhere else (I chose the SD card).\n\nIt's also possible to put the media into a ContentProvider using [MediaStore.Images.Media.insertImage()](http://developer.android.com/reference/android/provider/MediaStore.Images.Media.html#insertImage(android.content.ContentResolver, android.graphics.Bitmap, java.lang.String, java.lang.String)). The downside is that the image is then inserted into the Gallery, which I didn't want just for sharing images (the whole point of the app is to avoid having to fill up your gallery with images you don't want, instead keeping them in one organized place). You can avoid putting images in the Gallery by putting them into a folder on the SD card and creating a file \".nomedia\".\n\n<span style=\"font-weight:bold;\">Picture Frame and ACTION_GET_CONTENT</span>\n\n[ACTION_SEND](http://developer.android.com/reference/android/content/Intent.html#ACTION_SEND) can be used to send the images to other applications. The opposite of that is having the intent filter [ACTION_GET_CONTENT](http://developer.android.com/reference/android/content/Intent.html#ACTION_GET_CONTENT) enabled; that way, other applications can request data from your app. They both work essentially the same way, by passing a URI to the image in an Intent. In the case of ACTION_SEND, you pass the URI in EXTRA_STREAM. For ACTION_GET_CONTENT, it's actually provided in the return Intent's data.\n\nHowever, there is one exception: the standard Picture Frame widget doesn't play by these rules. It uses ACTION_GET_CONTENT to allow anyone to hook into their system, but they won't read a stream URI. If you try it, the picture frame widget crashes. The relevant part of the crash log is here:\n\n<pre> Caused by: java.lang.NullPointerException\n at com.cooliris.media.PhotoAppWidgetProvider$PhotoDatabaseHelper.setPhoto(PhotoAppWidgetProvider.java:121)\n at com.cooliris.media.PhotoAppWidgetConfigure.onActivityResult(PhotoAppWidgetConfigure.java:92)\n at android.app.Activity.dispatchActivityResult(Activity.java:3908)\n at android.app.ActivityThread.deliverResults(ActivityThread.java:2528)\n ... 11 more</pre>\nWhat they expect is for you to pass an extra called \"data\", as a Bitmap. This means you need to pass back both the URI and the Bitmap as a Parcelable in the return Intent:\n\n<pre>Intent return = new Intent();\nreturn.setData(myImageUri);\nreturn.putExtra(\"data\", myBitmap);\nsetResult(RESULT_OK, return);\nfinish();</pre>\nThis neglect in following the rules of the road is, I assume, due to [Cool Iris](http://www.cooliris.com/) both writing the standard Picture Frame widget and the standard Gallery application. As a result, the two play together nicely, but you'll have to follow their rules to be part of the gang.\n\n<span style=\"font-weight:bold;\">Messaging on HTC</span>\n\nThere's another player who doesn't quite follow the rules: HTC Sense's messaging application. Instead of filtering on the ACTION_SEND action like everyone else, HTC Sense's messaging application listens to \"android.intent.action.SEND_MSG\". This means two things for you as a developer: You have to test for the existence of an app that accepts the action \"android.intent.action.SEND_MSG\", and then give the user an explicit option to send to HTC Sense's messaging application, in addition to the normal picker.\n\nYou can test whether the HTC Sense messaging app is on the phone by querying for the intent filter:\n\n<pre>Intent dummy = new Intent(\"android.intent.action.SEND_MSG\");\ndummy.putExtra(Intent.EXTRA_STREAM, myImageUri);\ndummy.setType(\"image/png\");\nPackageManager packageManager = getPackageManager();\nList<ResolveInfo> list = packageManager.queryIntentActivities(dummy, PackageManager.MATCH_DEFAULT_ONLY);\nif (list.size() > 0) { // This means the HTC Sense messaging app is on the phone }</pre>\nIf you do have HTC Sense, you'll have to give your users the option to send messages to it. This means another layer of dialogs, which is a pain to users. At this point, I think the best solution is to stop using [the Android chooser](http://developer.android.com/reference/android/content/Intent.html#createChooser(android.content.Intent, java.lang.CharSequence)) altogether. As useful as it is, the Android ecosystem is too abused to keep using it. In an ideal world, you'd only need one Intent to pass your data around, but that's just not been the case. If you roll your own chooser (which is not particularly difficult), you can include multiple possible Intents to pass out.\n\nIt's also worth noting that HTC Sense's messaging system doesn't implement ACTION_GET_CONTENT, so you can't have users insert your app's content into a conversation already in progress. This is not an insignificant oversight - people have told me they switched text messaging apps because of this lacking feature!",
"html": "One of the sillier projects I've worked on in my spare time is <a href=\"https://market.android.com/details?id=com.idunnolol.ragefaces\">Rage Faces for Android</a>. It has almost no value to anyone, which is why it's free (<a href=\"https://github.com/dlew/android-ragefaces\">in every sense of the word</a>). However, it's been quite useful to me, as it's taught me a few things about sharing images on Android. Overall, I think this is a good reason for Android developers (or any developer, really) to have fun side projects to work on - there's almost no app so trivial that you can't learn something from doing it.<br /><br />Here's three big ones I learned from working on Rage Faces.<br /><br /><span style=\"font-weight:bold;\">Sharing Images</span><br /><br />The first thing it taught me is that you need space on the SD card in order to share images. This makes sense, as sending images (typically) uses the <a href=\"http://developer.android.com/reference/android/content/Intent.html#ACTION_SEND\">ACTION_SEND</a> intent along with a URI to the image. You can't link a URI to a resource inside your application package, so you have to put it somewhere else (I chose the SD card).<br /><br />It's also possible to put the media into a ContentProvider using <a href=\"http://developer.android.com/reference/android/provider/MediaStore.Images.Media.html#insertImage(android.content.ContentResolver, android.graphics.Bitmap, java.lang.String, java.lang.String)\">MediaStore.Images.Media.insertImage()</a>. The downside is that the image is then inserted into the Gallery, which I didn't want just for sharing images (the whole point of the app is to avoid having to fill up your gallery with images you don't want, instead keeping them in one organized place). You can avoid putting images in the Gallery by putting them into a folder on the SD card and creating a file \".nomedia\".<br /><br /><span style=\"font-weight:bold;\">Picture Frame and ACTION_GET_CONTENT</span><br /><br /><a href=\"http://developer.android.com/reference/android/content/Intent.html#ACTION_SEND\">ACTION_SEND</a> can be used to send the images to other applications. The opposite of that is having the intent filter <a href=\"http://developer.android.com/reference/android/content/Intent.html#ACTION_GET_CONTENT\">ACTION_GET_CONTENT</a> enabled; that way, other applications can request data from your app. They both work essentially the same way, by passing a URI to the image in an Intent. In the case of ACTION_SEND, you pass the URI in EXTRA_STREAM. For ACTION_GET_CONTENT, it's actually provided in the return Intent's data.<br /><br />However, there is one exception: the standard Picture Frame widget doesn't play by these rules. It uses ACTION_GET_CONTENT to allow anyone to hook into their system, but they won't read a stream URI. If you try it, the picture frame widget crashes. The relevant part of the crash log is here:<br /><br /><pre> Caused by: java.lang.NullPointerException<br /> at com.cooliris.media.PhotoAppWidgetProvider$PhotoDatabaseHelper.setPhoto(PhotoAppWidgetProvider.java:121)<br /> at com.cooliris.media.PhotoAppWidgetConfigure.onActivityResult(PhotoAppWidgetConfigure.java:92)<br /> at android.app.Activity.dispatchActivityResult(Activity.java:3908)<br /> at android.app.ActivityThread.deliverResults(ActivityThread.java:2528)<br /> ... 11 more</pre><br />What they expect is for you to pass an extra called \"data\", as a Bitmap. This means you need to pass back both the URI and the Bitmap as a Parcelable in the return Intent:<br /><br /><pre>Intent return = new Intent();<br />return.setData(myImageUri);<br />return.putExtra(\"data\", myBitmap);<br />setResult(RESULT_OK, return);<br />finish();</pre><br />This neglect in following the rules of the road is, I assume, due to <a href=\"http://www.cooliris.com/\">Cool Iris</a> both writing the standard Picture Frame widget and the standard Gallery application. As a result, the two play together nicely, but you'll have to follow their rules to be part of the gang.<br /><br /><span style=\"font-weight:bold;\">Messaging on HTC</span><br /><br />There's another player who doesn't quite follow the rules: HTC Sense's messaging application. Instead of filtering on the ACTION_SEND action like everyone else, HTC Sense's messaging application listens to \"android.intent.action.SEND_MSG\". This means two things for you as a developer: You have to test for the existence of an app that accepts the action \"android.intent.action.SEND_MSG\", and then give the user an explicit option to send to HTC Sense's messaging application, in addition to the normal picker.<br /><br />You can test whether the HTC Sense messaging app is on the phone by querying for the intent filter:<br /><br /><pre>Intent dummy = new Intent(\"android.intent.action.SEND_MSG\");<br />dummy.putExtra(Intent.EXTRA_STREAM, myImageUri);<br />dummy.setType(\"image/png\");<br />PackageManager packageManager = getPackageManager();<br />List<ResolveInfo> list = packageManager.queryIntentActivities(dummy, PackageManager.MATCH_DEFAULT_ONLY);<br />if (list.size() > 0) { // This means the HTC Sense messaging app is on the phone }</pre><br />If you do have HTC Sense, you'll have to give your users the option to send messages to it. This means another layer of dialogs, which is a pain to users. At this point, I think the best solution is to stop using <a href=\"http://developer.android.com/reference/android/content/Intent.html#createChooser(android.content.Intent, java.lang.CharSequence)\">the Android chooser</a> altogether. As useful as it is, the Android ecosystem is too abused to keep using it. In an ideal world, you'd only need one Intent to pass your data around, but that's just not been the case. If you roll your own chooser (which is not particularly difficult), you can include multiple possible Intents to pass out.<br /><br />It's also worth noting that HTC Sense's messaging system doesn't implement ACTION_GET_CONTENT, so you can't have users insert your app's content into a conversation already in progress. This is not an insignificant oversight - people have told me they switched text messaging apps because of this lacking feature!",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1302105600000,
"created_by": 1,
"updated_at": 1302624276475,
"updated_by": 1,
"published_at": 1302105600000,
"published_by": 1
},
{
"id": 51,
"title": "Tiled bitmaps in layer drawables",
"slug": "tiled_bitmaps_in_layer_drawables",
"markdown": "This is a bizarre bug that a coworker came across.\n\nThere's a cool feature of XML drawables that allows you to tile bitmaps, using [android:tileMode](http://developer.android.com/intl/fr/guide/topics/resources/drawable-resource.html#Bitmap). There is also the ability to layer drawables in XML, via [the layer list](http://developer.android.com/intl/fr/guide/topics/resources/drawable-resource.html#LayerList). Naturally, there are some circumstances where you might want to layer bitmaps that are tiled.\n\nIt turns out there is a bug in Android with trying to layer a tiled bitmap. Every once in a while, a tiled bitmap in a layer list won't tile. It's not every time (nor even that common) but anything less than a 100% success rate for graphics is problematic.\n\nThe solution is to not define the bitmap drawable tileMode in XML, instead defining it dynamically in code. Inflate the drawable in code somehow (either directly, or by inflating a layout that uses the drawable). Grab the drawable, cast it to a [LayerDrawable](http://developer.android.com/intl/fr/reference/android/graphics/drawable/LayerDrawable.html), then retrieve the [BitmapDrawable](http://developer.android.com/intl/fr/reference/android/graphics/drawable/BitmapDrawable.html) from the layer list (there are a few methods for it, like [LayerDrawable.getDrawable()](http://developer.android.com/intl/fr/reference/android/graphics/drawable/LayerDrawable.html#getDrawable(int))). Then, set the tileMode in code via [BitmapDrawable.setTileModeXY()](http://developer.android.com/intl/fr/reference/android/graphics/drawable/BitmapDrawable.html#setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode)).\n\nI've looked through the code and haven't figured out exactly why this bug occurs. I would appreciate any insight; in the meantime, the fix works well enough.",
"html": "This is a bizarre bug that a coworker came across.<br /><br />There's a cool feature of XML drawables that allows you to tile bitmaps, using <a href=\"http://developer.android.com/intl/fr/guide/topics/resources/drawable-resource.html#Bitmap\">android:tileMode</a>. There is also the ability to layer drawables in XML, via <a href=\"http://developer.android.com/intl/fr/guide/topics/resources/drawable-resource.html#LayerList\">the layer list</a>. Naturally, there are some circumstances where you might want to layer bitmaps that are tiled.<br /><br />It turns out there is a bug in Android with trying to layer a tiled bitmap. Every once in a while, a tiled bitmap in a layer list won't tile. It's not every time (nor even that common) but anything less than a 100% success rate for graphics is problematic.<br /><br />The solution is to not define the bitmap drawable tileMode in XML, instead defining it dynamically in code. Inflate the drawable in code somehow (either directly, or by inflating a layout that uses the drawable). Grab the drawable, cast it to a <a href=\"http://developer.android.com/intl/fr/reference/android/graphics/drawable/LayerDrawable.html\">LayerDrawable</a>, then retrieve the <a href=\"http://developer.android.com/intl/fr/reference/android/graphics/drawable/BitmapDrawable.html\">BitmapDrawable</a> from the layer list (there are a few methods for it, like <a href=\"http://developer.android.com/intl/fr/reference/android/graphics/drawable/LayerDrawable.html#getDrawable(int)\">LayerDrawable.getDrawable()</a>). Then, set the tileMode in code via <a href=\"http://developer.android.com/intl/fr/reference/android/graphics/drawable/BitmapDrawable.html#setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode)\">BitmapDrawable.setTileModeXY()</a>.<br /><br />I've looked through the code and haven't figured out exactly why this bug occurs. I would appreciate any insight; in the meantime, the fix works well enough.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1299697200001,
"created_by": 1,
"updated_at": 1299697203961,
"updated_by": 1,
"published_at": 1299697200001,
"published_by": 1
},
{
"id": 52,
"title": "Custom styles in Android libraries",
"slug": "custom_styles_in_android_libraries",
"markdown": "About nine months ago, Android added [library support](http://developer.android.com/intl/fr/guide/developing/projects/projects-eclipse.html#ReferencingLibraryProject). It allows you to define multiple Android projects where (at build time) it combines them all into one. These libraries have proven very useful in my work because there's a lot of common code between applications. In some cases, I'm even reusing entire Activities.\n\nBut this brings up a problem - how do you restyle an Activity in a library? Say you've got a custom date picker in your library which you want to customize to each application's look and feel. You could subclass the library's Activity and (in code) change the style, but then you miss out on all the advantages of [resource qualifiers](http://developer.android.com/intl/fr/guide/topics/resources/providing-resources.html#AlternativeResources). You could try subclassing but using your own XML, but then you're tightly coupling your code to the library and will likely end up duplicating code.\n\nThe answer is to use attributes and styles/themes. Chances are you've already worked with styles and themes before (if you haven't, [you should read up on them](http://developer.android.com/intl/fr/guide/topics/ui/themes.html)), but attributes aren't commonly needed when you're working on a one-off application. Attributes are a tad under-documented, but with attributes, you can define references which are filled in later by styles.\n\nAttributes are one level of abstraction beyond the normal use of XML references in Android. Let's take the simple example of a background: the most direct way to set a background is directly in code (android:background=\"#FF0000\"). Instead of putting the background in the code, you can create a color resource (&lt;color name=\"red\"&gt;#FF0000&lt;/color&gt;) then reference that (android:background=\"@color/red\"). Going one level of abstraction higher is to create an attribute(&lt;attr name=\"red\" format=\"color\" /&gt;), which doesn't directly define the color but can be set by a style or theme (android:background=\"?style/red\").\n\nA high-level layout of the solution looks like this:\n\n1\\. Define attributes for what XML values you want to customize.\n\n2\\. Link to those attributes in the library's XML.\n\n3\\. In the application using the library, create a style which defines values for those attributes.\n\n4\\. Apply that style as a theme for the application.\n\nHere's a specific example. Suppose we want the background of an Activity to be black in one application and white in another.\n\n1\\. Create a file in /values/ called \"attrs.xml\" and add an attribute for the background color:\n\n<pre>&lt;resources&gt;\n &lt;attr name=\"myBackground\" format=\"reference|color\" /&gt;\n&lt;/resources&gt;</pre>\nThe \"format\" field defines what sort of values can be entered for this attribute. There's no official documentation, but [people have written about possible values](http://stackoverflow.com/questions/3441396/android-defining-custom-attrs/3441986#3441986).\n\n2\\. Now let's create a simple layout in /layout/:\n\n<pre>&lt;LinearLayout android:layout_height=\"fill_parent\" android:layout_width=\"fill_parent\"\n android:background=\"?attr/myBackground\" /&gt;</pre>\nNote how you use the \"?\" instead of \"@\" when referencing an attribute.\n\n3\\. Now switch away from the library to the application using it. Inside, we create a \"styles.xml\" in /values/, and create a style to fill in the values for the attributes we defined in the library:\n\n<pre>&lt;resources&gt;\n &lt;style name=\"LibraryTheme\"&gt;\n &lt;item name=\"myBackground\"&gt;@android:color/black&lt;/item&gt;\n &lt;/style&gt;\n&lt;resources&gt;</pre>\n4\\. Now in AndroidManifest.xml, we set the overall application theme:\n\n<pre>&lt;application android:icon=\"@drawable/icon\" android:label=\"My App\"\n android:theme=\"@style/LibraryTheme\"&gt;</pre>\nIf you wanted to set another theme for the application already, use [style parenting](http://developer.android.com/intl/fr/guide/topics/ui/themes.html#DefiningStyles) to lump both styles together.\n\nTa-da! Now you've written a layout in a library that can be customized in each application that uses it. You can repeat steps #3 and #4 for any number of applications, setting the background to a different color for each.\n\nThere is only one caveat about this method, which is that you need to define <span style=\"font-weight:bold;\">all</span> the attributes in each application that uses the library. If you miss an attribute, your app will blow up in your face when the app tries to use it. What's worse, the stack trace when this occurs for missing attributes is complete gibberish and unrelated to the actual problem, making it difficult to debug.\n\nThis technique can be used for any attributes from a library. Use your imagination; at this point I've just been using it to style layouts, but you can apply attributes to just anything you can define in XML.",
"html": "About nine months ago, Android added <a href=\"http://developer.android.com/intl/fr/guide/developing/projects/projects-eclipse.html#ReferencingLibraryProject\">library support</a>. It allows you to define multiple Android projects where (at build time) it combines them all into one. These libraries have proven very useful in my work because there's a lot of common code between applications. In some cases, I'm even reusing entire Activities.<br /><br />But this brings up a problem - how do you restyle an Activity in a library? Say you've got a custom date picker in your library which you want to customize to each application's look and feel. You could subclass the library's Activity and (in code) change the style, but then you miss out on all the advantages of <a href=\"http://developer.android.com/intl/fr/guide/topics/resources/providing-resources.html#AlternativeResources\">resource qualifiers</a>. You could try subclassing but using your own XML, but then you're tightly coupling your code to the library and will likely end up duplicating code.<br /><br />The answer is to use attributes and styles/themes. Chances are you've already worked with styles and themes before (if you haven't, <a href=\"http://developer.android.com/intl/fr/guide/topics/ui/themes.html\">you should read up on them</a>), but attributes aren't commonly needed when you're working on a one-off application. Attributes are a tad under-documented, but with attributes, you can define references which are filled in later by styles.<br /><br />Attributes are one level of abstraction beyond the normal use of XML references in Android. Let's take the simple example of a background: the most direct way to set a background is directly in code (android:background=\"#FF0000\"). Instead of putting the background in the code, you can create a color resource (&lt;color name=\"red\"&gt;#FF0000&lt;/color&gt;) then reference that (android:background=\"@color/red\"). Going one level of abstraction higher is to create an attribute(&lt;attr name=\"red\" format=\"color\" /&gt;), which doesn't directly define the color but can be set by a style or theme (android:background=\"?style/red\").<br /><br />A high-level layout of the solution looks like this:<br /><br />1. Define attributes for what XML values you want to customize.<br /><br />2. Link to those attributes in the library's XML.<br /><br />3. In the application using the library, create a style which defines values for those attributes.<br /><br />4. Apply that style as a theme for the application.<br /><br />Here's a specific example. Suppose we want the background of an Activity to be black in one application and white in another.<br /><br />1. Create a file in /values/ called \"attrs.xml\" and add an attribute for the background color:<br /><br /><pre>&lt;resources&gt;<br /> &lt;attr name=\"myBackground\" format=\"reference|color\" /&gt;<br />&lt;/resources&gt;</pre><br />The \"format\" field defines what sort of values can be entered for this attribute. There's no official documentation, but <a href=\"http://stackoverflow.com/questions/3441396/android-defining-custom-attrs/3441986#3441986\">people have written about possible values</a>.<br /><br />2. Now let's create a simple layout in /layout/:<br /><br /><pre>&lt;LinearLayout android:layout_height=\"fill_parent\" android:layout_width=\"fill_parent\"<br /> android:background=\"?attr/myBackground\" /&gt;</pre><br />Note how you use the \"?\" instead of \"@\" when referencing an attribute.<br /><br />3. Now switch away from the library to the application using it. Inside, we create a \"styles.xml\" in /values/, and create a style to fill in the values for the attributes we defined in the library:<br /><br /><pre>&lt;resources&gt;<br /> &lt;style name=\"LibraryTheme\"&gt;<br /> &lt;item name=\"myBackground\"&gt;@android:color/black&lt;/item&gt;<br /> &lt;/style&gt;<br />&lt;resources&gt;</pre><br />4. Now in AndroidManifest.xml, we set the overall application theme:<br /><br /><pre>&lt;application android:icon=\"@drawable/icon\" android:label=\"My App\"<br /> android:theme=\"@style/LibraryTheme\"&gt;</pre><br />If you wanted to set another theme for the application already, use <a href=\"http://developer.android.com/intl/fr/guide/topics/ui/themes.html#DefiningStyles\">style parenting</a> to lump both styles together.<br /><br />Ta-da! Now you've written a layout in a library that can be customized in each application that uses it. You can repeat steps #3 and #4 for any number of applications, setting the background to a different color for each.<br /><br />There is only one caveat about this method, which is that you need to define <span style=\"font-weight:bold;\">all</span> the attributes in each application that uses the library. If you miss an attribute, your app will blow up in your face when the app tries to use it. What's worse, the stack trace when this occurs for missing attributes is complete gibberish and unrelated to the actual problem, making it difficult to debug.<br /><br />This technique can be used for any attributes from a library. Use your imagination; at this point I've just been using it to style layouts, but you can apply attributes to just anything you can define in XML.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1299178800000,
"created_by": 1,
"updated_at": 1299178802166,
"updated_by": 1,
"published_at": 1299178800000,
"published_by": 1
},
{
"id": 53,
"title": "Sending Emails on Android, Take 2",
"slug": "sending_emails_on_android_take_2",
"markdown": "A while back, I wrote [a post about how to send specifically send only emails on Android](http://daniel-codes.blogspot.com/2010/08/sending-emails-on-android.html). Unfortunately, the solution I posted does not work 100% of the time.\n\nMy previous solution was a hack and (as hacks are wont to do) it came back to bite my in the ass. It turns out that some email programs have buggy implementations of the mailto protocol. This led us to some users not getting the body content when using the mailto trick.\n\nThe correct solution is to use the normal ACTION_SEND intent, but setting the type to \"message/rfc822\", so only programs that implement emails will accept the intent.\n\n<pre>Intent intent = new Intent(Intent.ACTION_SEND);\nintent.setType(\"message/rfc822\");\nintent.putExtra(Intent.EXTRA_EMAIL, \"foo@bar.com\");\nintent.putExtra(Intent.EXTRA_SUBJECT, \"A Subject\");\nintent.putExtra(Intent.EXTRA_TEXT, \"Here's my message.\");\nstartActivity(intent);</pre>\n\nNot only does this work more often than my hack, but it's far more elegant, too.\n\nOne other choice I've made recently is to just use startActivity() on the original intent instead of creating a chooser first. That way, the user can opt for a default email program to use instead of being asked each time which app should handle the intent.",
"html": "A while back, I wrote <a href=\"http://daniel-codes.blogspot.com/2010/08/sending-emails-on-android.html\">a post about how to send specifically send only emails on Android</a>. Unfortunately, the solution I posted does not work 100% of the time.<br /><br />My previous solution was a hack and (as hacks are wont to do) it came back to bite my in the ass. It turns out that some email programs have buggy implementations of the mailto protocol. This led us to some users not getting the body content when using the mailto trick.<br /><br />The correct solution is to use the normal ACTION_SEND intent, but setting the type to \"message/rfc822\", so only programs that implement emails will accept the intent.<br /><br /><pre>Intent intent = new Intent(Intent.ACTION_SEND);<br />intent.setType(\"message/rfc822\");<br />intent.putExtra(Intent.EXTRA_EMAIL, \"foo@bar.com\");<br />intent.putExtra(Intent.EXTRA_SUBJECT, \"A Subject\");<br />intent.putExtra(Intent.EXTRA_TEXT, \"Here's my message.\");<br />startActivity(intent);</pre><br /><br />Not only does this work more often than my hack, but it's far more elegant, too.<br /><br />One other choice I've made recently is to just use startActivity() on the original intent instead of creating a chooser first. That way, the user can opt for a default email program to use instead of being asked each time which app should handle the intent.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1298660400000,
"created_by": 1,
"updated_at": 1298660405758,
"updated_by": 1,
"published_at": 1298660400000,
"published_by": 1
},
{
"id": 54,
"title": "Drop shadow text",
"slug": "drop_shadow_text",
"markdown": "Here's a little tip for creating a decent drop shadow effect in a TextView.\n\nThe issue I ran into initially when trying the shadow effects on TextView is that I could rarely get it to look right - instead of a clean, single pixel shadow, it'd always come out fuzzy. It turns out that the secret is that shadowRadius can be a float, and that you should make that float very small. Here's an example style you can apply to TextViews:\n\n<pre>&lt;style name=\"GreyEtchedText\"&gt;\n &lt;item name=\"android:textColor\"&gt;#2F3541&lt;/item&gt;\n &lt;item name=\"android:shadowColor\"&gt;#88FFFFFF&lt;/item&gt;\n &lt;item name=\"android:shadowRadius\"&gt;.1&lt;/item&gt;\n &lt;item name=\"android:shadowDx\"&gt;0&lt;/item&gt;\n &lt;item name=\"android:shadowDy\"&gt;1&lt;/item&gt;\n&lt;/style&gt;</pre>\nOf course, you can use whatever colors you want for the foreground/shadow.",
"html": "Here's a little tip for creating a decent drop shadow effect in a TextView.<br /><br />The issue I ran into initially when trying the shadow effects on TextView is that I could rarely get it to look right - instead of a clean, single pixel shadow, it'd always come out fuzzy. It turns out that the secret is that shadowRadius can be a float, and that you should make that float very small. Here's an example style you can apply to TextViews:<br /><br /><pre>&lt;style name=\"GreyEtchedText\"&gt;<br /> &lt;item name=\"android:textColor\"&gt;#2F3541&lt;/item&gt;<br /> &lt;item name=\"android:shadowColor\"&gt;#88FFFFFF&lt;/item&gt;<br /> &lt;item name=\"android:shadowRadius\"&gt;.1&lt;/item&gt;<br /> &lt;item name=\"android:shadowDx\"&gt;0&lt;/item&gt;<br /> &lt;item name=\"android:shadowDy\"&gt;1&lt;/item&gt;<br />&lt;/style&gt;</pre><br />Of course, you can use whatever colors you want for the foreground/shadow.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1298487600000,
"created_by": 1,
"updated_at": 1298487610362,
"updated_by": 1,
"published_at": 1298487600000,
"published_by": 1
},
{
"id": 55,
"title": "The True Problem With Google's License Verification Library (LVL)",
"slug": "the_true_problem_with_google_s_license_verification_library_lvl_",
"markdown": "Google recently introduced a new method to fight piracy on the Android Market, the License Verification Library (LVL). It replaces the old system copy protection system, wherein your APKs would be put in a folder that you can't access. Unless you root. Oh, and anyone who can copy that APK off can then give it to someone else to put on their device, too. It was so weak, it was almost non-existant.\n\nAt first I took the news of LVL to be a great next step. In case you've not been paying attention, LVL puts the copy protection methods in the app itself - a form of DRM. Your app would now communicate with Google's servers to authorize use of the app. You'd no longer prevent a user from copying/transferring APKs, but doing so would be pointless because they wouldn't run on someone else's phone unless they were authorized.\n\nHowever, any DRM measure can be cracked, it's just a matter effort. Only a few weeks after LVL was released [it was shown how easy it was to modify bytecode to bypass the authorization altogether](http://www.androidpolice.com/2010/08/23/exclusive-report-googles-android-market-license-verification-easily-circumvented-will-not-stop-pirates/). Google responded with a series of posts ([1](http://android-developers.blogspot.com/2010/08/licensing-server-news.html), [2](http://android-developers.blogspot.com/2010/09/securing-android-lvl-applications.html), [3](http://android-developers.blogspot.com/2010/09/proguard-android-and-licensing-server.html)) that explained how to circumvent this early crack in their armor. Essentially, it all boils down to different methods of obsfucating your code, [which as we all know can still fail](http://en.wikipedia.org/wiki/Security_through_obscurity#Arguments_against) - and the steps Google proposes for protecting your APKs complicates your code and build process. As happens with most DRM, this has become a game of cat-and-mouse between Google and pirates, using ever-escalating tactics to one-up the other.\n\nBut there's a much bigger issue at the root of the entire system: <span style=\"font-weight:bold;\">The LVL library only works on apps sold through Google's Android Market.</span>\n\nThe whole point of LVL is that the APK itself has some protection built in, so copying it around will not be an issue. But the LVL library only authenticates users who bought the app using the Android Market. If a user buys your app on a third-party store, then the LVL library will reject them. This means that in order to release on a third-party store, you'd have to ditch the LVL library for those builds - and thus defeat your own DRM.\n\nThere are a lot of Android Market alternatives now and more on the way. There are some publicly available are sites like [SlideME](http://slideme.org/) and [AppsLib](http://appslib.com/) (and possibly soon, [Amazon](http://www.wired.com/gadgetlab/2010/10/amazon-android-app-store/)). There are also some carrier-specific app stores - [Verizon just launched V-Cast](http://androidandme.com/2010/09/carriers/v-cast-app-store-to-compete-with-official-android-market/) and in Europe, both [Orange](http://www.androidguys.com/2009/12/11/orange-application-store-with-click-and-go/) and [Vodafone](http://mobile.slashdot.org/story/10/04/10/1915256/Android-Gets-Carrier-Operated-European-App-Store) have their own offerings.\n\n[Android Market's recent expansion](http://android-developers.blogspot.com/2010/09/more-countries-more-sellers-more-buyers.html) is, I believe, partially a response to this problem, but it comes too late. If the Market was more widespread and accessible early on then there would not have been an incentive to create and sell apps on alternative app stores in the first place; but now the momentum is there.\n\nAs much as it pains me, my conclusion is that it's better off to just go without any copy protection whatsoever. It does not makes sense to limit yourself to one store when potential customers could browsing another. Also, people who pirate will find a way to pirate, regardless your DRM; don't worry about them, and just worry about the people who would buy legit in the first place.",
"html": "Google recently introduced a new method to fight piracy on the Android Market, the License Verification Library (LVL). It replaces the old system copy protection system, wherein your APKs would be put in a folder that you can't access. Unless you root. Oh, and anyone who can copy that APK off can then give it to someone else to put on their device, too. It was so weak, it was almost non-existant.<br /><br />At first I took the news of LVL to be a great next step. In case you've not been paying attention, LVL puts the copy protection methods in the app itself - a form of DRM. Your app would now communicate with Google's servers to authorize use of the app. You'd no longer prevent a user from copying/transferring APKs, but doing so would be pointless because they wouldn't run on someone else's phone unless they were authorized.<br /><br />However, any DRM measure can be cracked, it's just a matter effort. Only a few weeks after LVL was released <a href=\"http://www.androidpolice.com/2010/08/23/exclusive-report-googles-android-market-license-verification-easily-circumvented-will-not-stop-pirates/\">it was shown how easy it was to modify bytecode to bypass the authorization altogether</a>. Google responded with a series of posts (<a href=\"http://android-developers.blogspot.com/2010/08/licensing-server-news.html\">1</a>, <a href=\"http://android-developers.blogspot.com/2010/09/securing-android-lvl-applications.html\">2</a>, <a href=\"http://android-developers.blogspot.com/2010/09/proguard-android-and-licensing-server.html\">3</a>) that explained how to circumvent this early crack in their armor. Essentially, it all boils down to different methods of obsfucating your code, <a href=\"http://en.wikipedia.org/wiki/Security_through_obscurity#Arguments_against\">which as we all know can still fail</a> - and the steps Google proposes for protecting your APKs complicates your code and build process. As happens with most DRM, this has become a game of cat-and-mouse between Google and pirates, using ever-escalating tactics to one-up the other.<br /><br />But there's a much bigger issue at the root of the entire system: <span style=\"font-weight:bold;\">The LVL library only works on apps sold through Google's Android Market.</span><br /><br />The whole point of LVL is that the APK itself has some protection built in, so copying it around will not be an issue. But the LVL library only authenticates users who bought the app using the Android Market. If a user buys your app on a third-party store, then the LVL library will reject them. This means that in order to release on a third-party store, you'd have to ditch the LVL library for those builds - and thus defeat your own DRM.<br /><br />There are a lot of Android Market alternatives now and more on the way. There are some publicly available are sites like <a href=\"http://slideme.org/\">SlideME</a> and <a href=\"http://appslib.com/\">AppsLib</a> (and possibly soon, <a href=\"http://www.wired.com/gadgetlab/2010/10/amazon-android-app-store/\">Amazon</a>). There are also some carrier-specific app stores - <a href=\"http://androidandme.com/2010/09/carriers/v-cast-app-store-to-compete-with-official-android-market/\">Verizon just launched V-Cast</a> and in Europe, both <a href=\"http://www.androidguys.com/2009/12/11/orange-application-store-with-click-and-go/\">Orange</a> and <a href=\"http://mobile.slashdot.org/story/10/04/10/1915256/Android-Gets-Carrier-Operated-European-App-Store\">Vodafone</a> have their own offerings.<br /><br /><a href=\"http://android-developers.blogspot.com/2010/09/more-countries-more-sellers-more-buyers.html\">Android Market's recent expansion</a> is, I believe, partially a response to this problem, but it comes too late. If the Market was more widespread and accessible early on then there would not have been an incentive to create and sell apps on alternative app stores in the first place; but now the momentum is there.<br /><br />As much as it pains me, my conclusion is that it's better off to just go without any copy protection whatsoever. It does not makes sense to limit yourself to one store when potential customers could browsing another. Also, people who pirate will find a way to pirate, regardless your DRM; don't worry about them, and just worry about the people who would buy legit in the first place.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1286812800000,
"created_by": 1,
"updated_at": 1286813020904,
"updated_by": 1,
"published_at": 1286812800000,
"published_by": 1
},
{
"id": 56,
"title": "Palm Shaking",
"slug": "palm_shaking",
"markdown": "This is a small point, but I could find no one else who has ever commented on this issue before: minor filtering with Palm shake events via the Accelerometer.\n\nIt's pretty easy to setup an event listener for the \"shaking\" event, just follow [the instructions here](http://developer.palm.com/index.php?option=com_content&view=article&id=1554&Itemid=261). However there are two partially tricky points to getting it right.\n\nFirst, you don't want to listen to every shake event. When listening to the \"shaking\" event, there's a parameter event.magnitude that you should use to filter. If you listen to all shaking events, then it's easy for your app to pick up shakes that are unintentional, such as someone putting their phone on a table or back in their pocket. I've found that a good number to pick is 2.08 - the reason for this being that the emulator, when you press \"f5\", simulates a shake event of magnitude ~2.09\\. Set your filter any higher and you won't be able to test with the emulator, but with a magnitude of at least 2, the user's shake has to be relatively intentional.\n\nThe second catch is that the shake event, unlike most events you might listen to in a scene, can happen in any scene on the stack. With buttons and the like, you can be lazy and not disable their listeners when you add another scene to the stack because those buttons are not accessible. You cannot be so lazy with the \"shaking\" event; even if you push another scene, your previous event listener will still fire off whenever the phone shakes. So make sure to disable any \"shaking\" handlers before you launch a new scene.",
"html": "This is a small point, but I could find no one else who has ever commented on this issue before: minor filtering with Palm shake events via the Accelerometer.<br /><br />It's pretty easy to setup an event listener for the \"shaking\" event, just follow <a href=\"http://developer.palm.com/index.php?option=com_content&view=article&id=1554&Itemid=261\">the instructions here</a>. However there are two partially tricky points to getting it right.<br /><br />First, you don't want to listen to every shake event. When listening to the \"shaking\" event, there's a parameter event.magnitude that you should use to filter. If you listen to all shaking events, then it's easy for your app to pick up shakes that are unintentional, such as someone putting their phone on a table or back in their pocket. I've found that a good number to pick is 2.08 - the reason for this being that the emulator, when you press \"f5\", simulates a shake event of magnitude ~2.09. Set your filter any higher and you won't be able to test with the emulator, but with a magnitude of at least 2, the user's shake has to be relatively intentional.<br /><br />The second catch is that the shake event, unlike most events you might listen to in a scene, can happen in any scene on the stack. With buttons and the like, you can be lazy and not disable their listeners when you add another scene to the stack because those buttons are not accessible. You cannot be so lazy with the \"shaking\" event; even if you push another scene, your previous event listener will still fire off whenever the phone shakes. So make sure to disable any \"shaking\" handlers before you launch a new scene.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1284388200001,
"created_by": 1,
"updated_at": 1284388618946,
"updated_by": 1,
"published_at": 1284388200001,
"published_by": 1
},
{
"id": 57,
"title": "Sending Emails on Android",
"slug": "sending_emails_on_android",
"markdown": "UPDATE 2/25/2011: [There is a much better solution to the problem I have now posted](http://daniel-codes.blogspot.com/2011/02/sending-emails-on-android-take-2.html).\n\nIn this post I outline how to share information solely via email. There's some background information up front; if you're interested in just how to share data only with email apps, skip to the bottom.\n\nOne thing that users like to do a lot is share information. They want to be able to post things to Twitter, Facebook, or email their friends. Android makes this really simple via the ACTION_SEND intent:\n\n<pre>Intent intent = new Intent(Intent.ACTION_SEND);\nintent.setType(\"text/plain\");\nintent.putExtra(Intent.EXTRA_SUBJECT, \"A Subject\");\nintent.putExtra(Intent.EXTRA_TEXT, \"Here's my message.\");\nIntent mailer = Intent.createChooser(intent, null);\nstartActivity(mailer);</pre>\n\nThere's only one issue that arises from this method: any app that's registered to receive the ACTION_SEND intent will show up in the chooser. This means some oddball choices pop up (\"Bluetooth\" being the weirdest one for me), but that's kind of unavoidable. The bigger issue that I ran into was a matter of message length; Twitter messages are inherently shorter than what I might send via email. If I knew I only had 140 characters, the share message should be a lot shorter; but with the freedom of email, I can template out detailed information.\n\nOne solution that I've used is to pop up a dialog which asks the user whether they want a short template message or a long one, with examples of where to use each - short (Twitter, Facebook) vs. long (email).\n\nA bigger problem arises when you want to only share information via emails. Suppose the information your app shares is just too complex for a short Twitter message - an unfortunate circumstance for the Twitter population but a fact of some apps. How do you force the chooser to select email? It turns out that there's a very roundabout way of handling this issue by taking advantage of the mailto protocol in Android:\n\n<pre>Intent intent = new Intent(Intent.ACTION_VIEW);\nUri data = Uri.parse(\"mailto:?subject=\" + subject + \"&body=\" + body);\nintent.setData(data);\nstartActivity(intent);</pre>\n\nUsing the data scheme that you do, only email apps pick up on this scheme. As a result, only email apps will open. You may not even force the user to go through a chooser if they have a default email app chosen already.",
"html": "UPDATE 2/25/2011: <a href=\"http://daniel-codes.blogspot.com/2011/02/sending-emails-on-android-take-2.html\">There is a much better solution to the problem I have now posted</a>.<br /><br />In this post I outline how to share information solely via email. There's some background information up front; if you're interested in just how to share data only with email apps, skip to the bottom.<br /><br />One thing that users like to do a lot is share information. They want to be able to post things to Twitter, Facebook, or email their friends. Android makes this really simple via the ACTION_SEND intent:<br /><br /><pre>Intent intent = new Intent(Intent.ACTION_SEND);<br />intent.setType(\"text/plain\");<br />intent.putExtra(Intent.EXTRA_SUBJECT, \"A Subject\");<br />intent.putExtra(Intent.EXTRA_TEXT, \"Here's my message.\");<br />Intent mailer = Intent.createChooser(intent, null);<br />startActivity(mailer);</pre><br /><br />There's only one issue that arises from this method: any app that's registered to receive the ACTION_SEND intent will show up in the chooser. This means some oddball choices pop up (\"Bluetooth\" being the weirdest one for me), but that's kind of unavoidable. The bigger issue that I ran into was a matter of message length; Twitter messages are inherently shorter than what I might send via email. If I knew I only had 140 characters, the share message should be a lot shorter; but with the freedom of email, I can template out detailed information.<br /><br />One solution that I've used is to pop up a dialog which asks the user whether they want a short template message or a long one, with examples of where to use each - short (Twitter, Facebook) vs. long (email).<br /><br />A bigger problem arises when you want to only share information via emails. Suppose the information your app shares is just too complex for a short Twitter message - an unfortunate circumstance for the Twitter population but a fact of some apps. How do you force the chooser to select email? It turns out that there's a very roundabout way of handling this issue by taking advantage of the mailto protocol in Android:<br /><br /><pre>Intent intent = new Intent(Intent.ACTION_VIEW);<br />Uri data = Uri.parse(\"mailto:?subject=\" + subject + \"&body=\" + body);<br />intent.setData(data);<br />startActivity(intent);</pre><br /><br />Using the data scheme that you do, only email apps pick up on this scheme. As a result, only email apps will open. You may not even force the user to go through a chooser if they have a default email app chosen already.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1282240800000,
"created_by": 1,
"updated_at": 1298732373329,
"updated_by": 1,
"published_at": 1282240800000,
"published_by": 1
},
{
"id": 58,
"title": "Palm and CRUD",
"slug": "palm_and_crud",
"markdown": "I've been working with some Calendar integration on Palm and it's a mess because their documentation is out of line with reality. The basic CRUD API I have some issues with because of their ill-defined error codes - for example, if I want to find out if I've already created a calendar event or not I use service getEvent, but the error it returns if the event doesn't exist is the same error as if you input an invalid parameter. But beyond that there's simply mis-documented code or bad samples they give out that don't work.\n\nSome things I've found:\n\n**createAccount** - There's a lot of different hogwash in the documentation and samples, all of it wrong in one form or another. The icons parameter should actually be setup thus:\n\n<pre>icons: {\n \"32x32\": Mojo.appPath + \"icon32.png\",\n \"48x48\": Mojo.appPath + \"icon48.png\"\n}</pre>\n\nMojo.appPath is required, and then after that you link your icons from wherever they are in your project.\n\n**Accounts Linked to Email** - There was some initial confusion because when I created an account with domain of \"idunnolol\" with username \"dlew\", Palm would give me the option to log into an email account \"dlew@idunnolol.com\". The fact of the matter is, Palm always thinks the account you create is linked to an email, even if you're just using for email. Sorry! You'll just have to get over this.\n\n**updateEvent** - The documentation would have you believe that it takes two parameters - event and trackChanges. But when you do that, you get the error \"ErrorGenericInvalidParameter: Missing Required Parameter: event.startTimestamp\". What you really need to do is setup your event as the entire parameters. I have no idea where trackChanges could go (but I don't use it):\n\n<pre>parameters: {\n eventId: '1241251801',\n startTimestamp: '92912911212',\n endTimestamp: '1299592929291',\n ... etc\n}</pre>\n\nBesides those three things, I found that the code was much easier to work with if I setup a chain of onSuccess(), onFailure() calls that always guaranteed that I had a valid account and calendar. When I try to create a calendar event, first it checks that I have an account, then it checks if I have a calendar, and creates them if it doesn't exist. It's nice to have this built into your implementation because users can (at any time) delete your account if they feel like it.",
"html": "I've been working with some Calendar integration on Palm and it's a mess because their documentation is out of line with reality. The basic CRUD API I have some issues with because of their ill-defined error codes - for example, if I want to find out if I've already created a calendar event or not I use service getEvent, but the error it returns if the event doesn't exist is the same error as if you input an invalid parameter. But beyond that there's simply mis-documented code or bad samples they give out that don't work.<br /><br />Some things I've found:<br /><br /><b>createAccount</b> - There's a lot of different hogwash in the documentation and samples, all of it wrong in one form or another. The icons parameter should actually be setup thus:<br /><br /><pre>icons: {<br /> \"32x32\": Mojo.appPath + \"icon32.png\",<br /> \"48x48\": Mojo.appPath + \"icon48.png\"<br />}</pre><br /><br />Mojo.appPath is required, and then after that you link your icons from wherever they are in your project.<br /><br /><b>Accounts Linked to Email</b> - There was some initial confusion because when I created an account with domain of \"idunnolol\" with username \"dlew\", Palm would give me the option to log into an email account \"dlew@idunnolol.com\". The fact of the matter is, Palm always thinks the account you create is linked to an email, even if you're just using for email. Sorry! You'll just have to get over this.<br /><br /><b>updateEvent</b> - The documentation would have you believe that it takes two parameters - event and trackChanges. But when you do that, you get the error \"ErrorGenericInvalidParameter: Missing Required Parameter: event.startTimestamp\". What you really need to do is setup your event as the entire parameters. I have no idea where trackChanges could go (but I don't use it):<br /><br /><pre>parameters: {<br /> eventId: '1241251801',<br /> startTimestamp: '92912911212',<br /> endTimestamp: '1299592929291',<br /> ... etc<br />}</pre><br /><br />Besides those three things, I found that the code was much easier to work with if I setup a chain of onSuccess(), onFailure() calls that always guaranteed that I had a valid account and calendar. When I try to create a calendar event, first it checks that I have an account, then it checks if I have a calendar, and creates them if it doesn't exist. It's nice to have this built into your implementation because users can (at any time) delete your account if they feel like it.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1281574800000,
"created_by": 1,
"updated_at": 1281574801424,
"updated_by": 1,
"published_at": 1281574800000,
"published_by": 1
},
{
"id": 59,
"title": "The Curious Case of the Missing HttpsURLConnection",
"slug": "the_curious_case_of_the_missing_https_urlconnection",
"markdown": "I ran into an Android OS bug recently that is pretty harsh related to HTTPS connections. Basically, what happens is this:\n\n1\\. You want to setup a connection between the phone and a server, and you need to control both the input and the output. As a result, you use URL.openConnection(), with setDoInput() and setDoOutput() set to true:\n\n<pre>URL url = new URL(\"https://blahblahblah.com\");\nURLConnection conn = url.openConnection();\nconn.setDoInput(true);\nconn.setDoOutput(true);</pre>\n\nAt some point you use both conn.getOutputStream() to write to the stream, then conn.getInputStream() to get the response.\n\n2\\. You're doing an HTTPS connection. Some people report this happening on normal HTTP, but I've only seen it happen on HTTPS.\n\n3\\. The first request goes through fine and dandy.\n\n4\\. The second time you try to make the request, the connection doesn't send any data out and doesn't receive any data; it looks like it happens instantly. If you cast to an HttpURLConnection, conn.getResponseCode() returns -1 instead of anything meaningful.\n\nIn other words, every other request, the request fails outright. [This is a noted bug in Android](http://code.google.com/p/android/issues/detail?id=7786&can=1&q=httpsurlconnection&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars), but it isn't fixed yet in any released versions. Even when it's fixed, you'll still have to deal with this on older versions of Android.\n\nThere are a few workarounds. The first is to simply not use URLConnection; if you can find some way around it, avoid it. The second is to repeatedly make the same request until it works; it's a little too much of a hack for my tastes, but it'll work.\n\nThen there's the third workaround, which I do not claim to understand why it fixes the issue but it does. Just set this setting when your application begins:\n\n<pre>System.setProperty(\"http.keepAlive\", \"false\");</pre>\n\nUnfortunately this has some drawbacks (keep-alive is a good thing normally), but in comparison to mysteriously failed requests I'll ditch it.",
"html": "I ran into an Android OS bug recently that is pretty harsh related to HTTPS connections. Basically, what happens is this:<br /><br />1. You want to setup a connection between the phone and a server, and you need to control both the input and the output. As a result, you use URL.openConnection(), with setDoInput() and setDoOutput() set to true:<br /><br /><pre>URL url = new URL(\"https://blahblahblah.com\");<br />URLConnection conn = url.openConnection();<br />conn.setDoInput(true);<br />conn.setDoOutput(true);</pre><br /><br />At some point you use both conn.getOutputStream() to write to the stream, then conn.getInputStream() to get the response.<br /><br />2. You're doing an HTTPS connection. Some people report this happening on normal HTTP, but I've only seen it happen on HTTPS.<br /><br />3. The first request goes through fine and dandy.<br /><br />4. The second time you try to make the request, the connection doesn't send any data out and doesn't receive any data; it looks like it happens instantly. If you cast to an HttpURLConnection, conn.getResponseCode() returns -1 instead of anything meaningful.<br /><br />In other words, every other request, the request fails outright. <a href=\"http://code.google.com/p/android/issues/detail?id=7786&can=1&q=httpsurlconnection&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars\">This is a noted bug in Android</a>, but it isn't fixed yet in any released versions. Even when it's fixed, you'll still have to deal with this on older versions of Android.<br /><br />There are a few workarounds. The first is to simply not use URLConnection; if you can find some way around it, avoid it. The second is to repeatedly make the same request until it works; it's a little too much of a hack for my tastes, but it'll work.<br /><br />Then there's the third workaround, which I do not claim to understand why it fixes the issue but it does. Just set this setting when your application begins:<br /><br /><pre>System.setProperty(\"http.keepAlive\", \"false\");</pre><br /><br />Unfortunately this has some drawbacks (keep-alive is a good thing normally), but in comparison to mysteriously failed requests I'll ditch it.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1279907520000,
"created_by": 1,
"updated_at": 1279908049925,
"updated_by": 1,
"published_at": 1279907520000,
"published_by": 1
},
{
"id": 60,
"title": "How to Change a ListView Row's Background but Keep Normal Android Selector",
"slug": "how_to_change_a_list_view_row_s_background_but_keep_normal_android_selector",
"markdown": "Here's a problem which I thought would be super complex to solve but is actually rather simple. The solution assumes a bit of knowledge of ListView row types, though; if you've never dealt with them, [here's a primer](http://android.amberfog.com/?p=296).\n\nSuppose I want to make a ListView composed of similar rows with different backgrounds. This is simple enough; create a ListView with multiple item view types and then as each one loads, set a different background resource based on their type. The catch is that you want the selected/pressed graphics to still look the same. An example of this would be an email app; you want read and unread emails to look different, but when the item is selected or pressed you still want that tacky orange (or whatever your system uses).\n\nThe naive solution of simply setting the background resource does not work, because it completely blocks the standard selector:\n\n<pre>// Bad; don't use this!\nconvertView.setBackgroundResrouce(R.color.some_color);</pre>\n\nI was able to glean the correct answer by examining the Email app's source code (thank goodness for open source). What you want to do is create a background which is transparent whenever the list's background selector kicks in, but uses your custom background color (or resource) when it's not. Here's what the drawable xml looks like:\n\n &lt;selector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;\n &lt;item android:state_window_focused=&quot;false&quot; android:state_selected=&quot;true&quot; android:drawable=&quot;@android:color/transparent&quot; /&gt; \n &lt;item android:state_selected=&quot;true&quot; android:drawable=&quot;@android:color/transparent&quot; /&gt; \n &lt;item android:state_pressed=&quot;true&quot; android:state_selected=&quot;false&quot; android:drawable=&quot;@android:color/transparent&quot; /&gt; \n &lt;item android:state_selected=&quot;false&quot; android:drawable=&quot;@color/some_color&quot; /&gt; \n &lt;/selector&gt;\n\nWith this in hand, you can set your view's background like so:\n\n<pre>convertView.setBackgroundResrouce(R.drawable.some_row_background);</pre>\n\nJust apply the above XML to multiple files, and you'll be able to set different types of backgrounds but still preserve the ListView's selector background.",
"html": "Here's a problem which I thought would be super complex to solve but is actually rather simple. The solution assumes a bit of knowledge of ListView row types, though; if you've never dealt with them, <a href=\"http://android.amberfog.com/?p=296\">here's a primer</a>.<br /><br />Suppose I want to make a ListView composed of similar rows with different backgrounds. This is simple enough; create a ListView with multiple item view types and then as each one loads, set a different background resource based on their type. The catch is that you want the selected/pressed graphics to still look the same. An example of this would be an email app; you want read and unread emails to look different, but when the item is selected or pressed you still want that tacky orange (or whatever your system uses).<br /><br />The naive solution of simply setting the background resource does not work, because it completely blocks the standard selector:<br /><br /><pre>// Bad; don't use this!<br />convertView.setBackgroundResrouce(R.color.some_color);</pre><br /><br />I was able to glean the correct answer by examining the Email app's source code (thank goodness for open source). What you want to do is create a background which is transparent whenever the list's background selector kicks in, but uses your custom background color (or resource) when it's not. Here's what the drawable xml looks like:<br /><br /><pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>&lt;selector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;<br /> &lt;item android:state_window_focused=&quot;false&quot; android:state_selected=&quot;true&quot; android:drawable=&quot;@android:color/transparent&quot; /&gt; <br /> &lt;item android:state_selected=&quot;true&quot; android:drawable=&quot;@android:color/transparent&quot; /&gt; <br /> &lt;item android:state_pressed=&quot;true&quot; android:state_selected=&quot;false&quot; android:drawable=&quot;@android:color/transparent&quot; /&gt; <br /> &lt;item android:state_selected=&quot;false&quot; android:drawable=&quot;@color/some_color&quot; /&gt; <br /> &lt;/selector&gt;<br /></code></pre><br /><br />With this in hand, you can set your view's background like so:<br /><br /><pre>convertView.setBackgroundResrouce(R.drawable.some_row_background);</pre><br /><br />Just apply the above XML to multiple files, and you'll be able to set different types of backgrounds but still preserve the ListView's selector background.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1279228440001,
"created_by": 1,
"updated_at": 1279229226731,
"updated_by": 1,
"published_at": 1279228440001,
"published_by": 1
},
{
"id": 61,
"title": "app-assistant handleLaunch and large numbers",
"slug": "app_assistant_handle_launch_and_large_numbers",
"markdown": "I've been working in the world of webOS for the last month, and while there's a lot of new APIs to learn I've not really run into an amazing \"gotcha\" moment until now.\n\nIn our app, we show some banner notifications. When you click on that banner notification, it takes you to a page with some information. On that page is some information about time, which means we're passing a timestamp in launchArguments (part of [showBanner()](http://www.weboshelp.net/webos-mojo-development-resources/api-reference/555-mojocontrollerappcontrollershowbannerbannerparamsbannerparams-launcharguments-category-?catid=65:mojocontrollerappcontroller)).\n\nThe intriguing thing that happens is that, unlike the rest of Palm (nay, JS in general), integers passed using launchArguments are limited to 32 bits. Guess what's typically larger than 32 bits: timestamps measured in milliseconds from the epoch. It confounds me that such a limitation exists, but any number larger than 2^31 - 1 is converted to the max integer instead.\n\nThe solution? Wrap the number as a string. Bizarre that they'll let any length string through, but not a number larger than an integer. If anyone can explain, please do.",
"html": "I've been working in the world of webOS for the last month, and while there's a lot of new APIs to learn I've not really run into an amazing \"gotcha\" moment until now.<br /><br />In our app, we show some banner notifications. When you click on that banner notification, it takes you to a page with some information. On that page is some information about time, which means we're passing a timestamp in launchArguments (part of <a href=\"http://www.weboshelp.net/webos-mojo-development-resources/api-reference/555-mojocontrollerappcontrollershowbannerbannerparamsbannerparams-launcharguments-category-?catid=65:mojocontrollerappcontroller\">showBanner()</a>).<br /><br />The intriguing thing that happens is that, unlike the rest of Palm (nay, JS in general), integers passed using launchArguments are limited to 32 bits. Guess what's typically larger than 32 bits: timestamps measured in milliseconds from the epoch. It confounds me that such a limitation exists, but any number larger than 2^31 - 1 is converted to the max integer instead.<br /><br />The solution? Wrap the number as a string. Bizarre that they'll let any length string through, but not a number larger than an integer. If anyone can explain, please do.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1276114920000,
"created_by": 1,
"updated_at": 1276115177206,
"updated_by": 1,
"published_at": 1276114920000,
"published_by": 1
},
{
"id": 62,
"title": "Android 1.5 Widgets, Google Maps API and VerifyError",
"slug": "android_1_5_widgets_google_maps_api_and_verify_error",
"markdown": "Here are two things that don't get along: Android 1.5 widgets and the Google Maps API. Trying to include both in your application results in a dreaded VerifyError when you try to create a widget on the home screen.\n\nThe basic cause, [according to Dianne Hackborn](http://groups.google.com/group/android-developers/msg/904fae350cda3ebc):\n\n> Hi, it looks like there is a bug initializing a process when it is launched to handle a broadcast sent to an explicit component. In this case its shared libraries are not linked to it.\n\nThis manifests itself in two ways, basically whenever a class imports any com.google.android.maps classes. The first is if your widget needs to initialize any classes that import maps. The second is if any of your broadcast receivers initialize any classes that import maps. In both cases, the widget will attempt to load com.google.android.maps and fail, throwing a VerifyError.\n\nThe solution to the first is to not have any references to com.google.android.maps. This is sometimes easier said than done, but if you divide out your maps classes from your widget classes this is doable. Worst-case scenario, you can use reflection to call your maps classes; they will throw exceptions when the widget tries to load them, but hopefully you don't need them anyways. (This happened when I had my Application try to clear some maps cache data onLowMemory()).\n\nThe solution to the second is [to put all of your receivers in a different process](http://code.google.com/p/android/issues/detail?id=2886#c3).",
"html": "Here are two things that don't get along: Android 1.5 widgets and the Google Maps API. Trying to include both in your application results in a dreaded VerifyError when you try to create a widget on the home screen.<br /><br />The basic cause, <a href=\"http://groups.google.com/group/android-developers/msg/904fae350cda3ebc\">according to Dianne Hackborn</a>:<br /><br /><blockquote>Hi, it looks like there is a bug initializing a process when it is launched to handle a broadcast sent to an explicit component. In this case its shared libraries are not linked to it. </blockquote><br /><br />This manifests itself in two ways, basically whenever a class imports any com.google.android.maps classes. The first is if your widget needs to initialize any classes that import maps. The second is if any of your broadcast receivers initialize any classes that import maps. In both cases, the widget will attempt to load com.google.android.maps and fail, throwing a VerifyError.<br /><br />The solution to the first is to not have any references to com.google.android.maps. This is sometimes easier said than done, but if you divide out your maps classes from your widget classes this is doable. Worst-case scenario, you can use reflection to call your maps classes; they will throw exceptions when the widget tries to load them, but hopefully you don't need them anyways. (This happened when I had my Application try to clear some maps cache data onLowMemory()).<br /><br />The solution to the second is <a href=\"http://code.google.com/p/android/issues/detail?id=2886#c3\">to put all of your receivers in a different process</a>.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1275588000000,
"created_by": 1,
"updated_at": 1276018368837,
"updated_by": 1,
"published_at": 1275588000000,
"published_by": 1
},
{
"id": 63,
"title": "Headset Blocker",
"slug": "headset_blocker",
"markdown": "If you own a Nexus One, you may be familiar with this scenario: you load up your N1 with some rocking tunes. You plug in your headphones and go out exercising with it. Suddenly, the tunes start skipping. Why?\n\nThe problem is that the headset jack is interpreting what you are doing as a control signal. The exact cause hasn't been shown to me yet; there are a number of theories from a lack of software noise filtering to the difference between TRS and TRRS connectors. Regardless, it's a serious issue - some people can't even listen to music in their cars with the N1 because it skips so much.\n\nLuckily, in the last few days I was shown an answer. The control commands from headsets are actually sent out as a chain broadcast, MEDIA_BUTTON. As with any chain broadcast, your receiver can abort the broadcast. So the simple solution is to make a BroadcastReceiver with an ultra-high priority that intercepts and aborts the MEDIA_BUTTON broadcast.\n\nTo that end, I've put a small app on the Market, Headset Blocker. It's a small, free widget that allows you to enable/disable blocking of the MEDIA_BUTTON broadcast. You can get it here: \n\n![QR code for Headset Blocker](http://chart.apis.google.com/chart?cht=qr&amp;chs=200x200&amp;chld=L|0&amp;chl=market://details%3Fid%3Dcom.idunnolol.headsetblocker)\n\n[The source code is here](http://code.google.com/p/android-headset-blocker/).\n\nOne interesting choice I had to make when writing this app was how to toggle the blocking. I had one of two options:\n\n1\\. Use SharedPreferences to track when blocking is enabled. Capture all MEDIA_BUTTON broadcasts, but only abort when the preference is enabled.\n\n2\\. Enable/disable my app's BroadcastReceiver. It will always abort when enabled, but is only enabled via the widget.\n\nI went with the latter option, as I felt that would save just a little bit more battery when disabled (as the BroadcastReceiver itself would be disabled).",
"html": "If you own a Nexus One, you may be familiar with this scenario: you load up your N1 with some rocking tunes. You plug in your headphones and go out exercising with it. Suddenly, the tunes start skipping. Why?<br /><br />The problem is that the headset jack is interpreting what you are doing as a control signal. The exact cause hasn't been shown to me yet; there are a number of theories from a lack of software noise filtering to the difference between TRS and TRRS connectors. Regardless, it's a serious issue - some people can't even listen to music in their cars with the N1 because it skips so much.<br /><br />Luckily, in the last few days I was shown an answer. The control commands from headsets are actually sent out as a chain broadcast, MEDIA_BUTTON. As with any chain broadcast, your receiver can abort the broadcast. So the simple solution is to make a BroadcastReceiver with an ultra-high priority that intercepts and aborts the MEDIA_BUTTON broadcast.<br /><br />To that end, I've put a small app on the Market, Headset Blocker. It's a small, free widget that allows you to enable/disable blocking of the MEDIA_BUTTON broadcast. You can get it here: <br /><br /><img alt=\"QR code for Headset Blocker\" border=\"0\" src=\"http://chart.apis.google.com/chart?cht=qr&amp;chs=200x200&amp;chld=L|0&amp;chl=market://details%3Fid%3Dcom.idunnolol.headsetblocker\" /><br /><br /><a href=\"http://code.google.com/p/android-headset-blocker/\">The source code is here</a>.<br /><br />One interesting choice I had to make when writing this app was how to toggle the blocking. I had one of two options:<br /><br />1. Use SharedPreferences to track when blocking is enabled. Capture all MEDIA_BUTTON broadcasts, but only abort when the preference is enabled.<br /><br />2. Enable/disable my app's BroadcastReceiver. It will always abort when enabled, but is only enabled via the widget.<br /><br />I went with the latter option, as I felt that would save just a little bit more battery when disabled (as the BroadcastReceiver itself would be disabled).",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1275488760000,
"created_by": 1,
"updated_at": 1386865926055,
"updated_by": 1,
"published_at": 1275488760000,
"published_by": 1
},
{
"id": 64,
"title": "Android: Serializable Considered Harmful",
"slug": "android_serializable_considered_harmful",
"markdown": "This is an old problem, but anyone I can convince not to use Serializable on Android will help the system as a whole.\n\nThere is some data saved between launches of my application - a list of complex objects. When I first learned Android I assumed that the fastest way to get the app up and running would be to slap [Serializable](http://developer.android.com/reference/java/io/Serializable.html) on my data classes and call it a day. It certainly got things up and running quickly, but with some serious performance issues. I never noticed this in early testing because I only saved a few objects at a time. However, when I got up to 5+ objects the system started to slow down, and at 10+ it ran like molasses. There's not normally that many objects, but it's still something to be concerned about. It's not like I was doing anything complex, however - it was simply that Serializable is that slow.\n\nNot only that, but I had to live in constant fear of changing the data structure. If enough things changed I would have to write my own serialization processes to work with backwards compatibility. Yuck.\n\nI switched to using JSON to store all my data and this decision has made my life so much better. Android comes with [a good JSON library](http://developer.android.com/reference/org/json/package-summary.html) and it's pretty simple to add JSON support to classes. JSON is much, much faster than serialization and comes out with much smaller results, too (you can even GZip the results to make them smaller still). To put it in perspective, the save time is now unnoticeable, whereas I could count the seconds using Serializable; and the file size was reduced by an order of magnitude.\n\nNot only is it better for saving data, it's a very easy way to pass data between components. When I first started, I saw three ways to pass data between components: Serializing, parceling, or storing data in the Application context. Serializing was proving too slow, parceling is really a pain in the ass, and the last solution is harder to integrate with later on (no one else can call your component). JSON has proven a much better solution - it's fast enough to get by, but not nearly the pain in the ass that Parcels are.",
"html": "This is an old problem, but anyone I can convince not to use Serializable on Android will help the system as a whole.<br /><br />There is some data saved between launches of my application - a list of complex objects. When I first learned Android I assumed that the fastest way to get the app up and running would be to slap <a href=\"http://developer.android.com/reference/java/io/Serializable.html\">Serializable</a> on my data classes and call it a day. It certainly got things up and running quickly, but with some serious performance issues. I never noticed this in early testing because I only saved a few objects at a time. However, when I got up to 5+ objects the system started to slow down, and at 10+ it ran like molasses. There's not normally that many objects, but it's still something to be concerned about. It's not like I was doing anything complex, however - it was simply that Serializable is that slow.<br /><br />Not only that, but I had to live in constant fear of changing the data structure. If enough things changed I would have to write my own serialization processes to work with backwards compatibility. Yuck.<br /><br />I switched to using JSON to store all my data and this decision has made my life so much better. Android comes with <a href=\"http://developer.android.com/reference/org/json/package-summary.html\">a good JSON library</a> and it's pretty simple to add JSON support to classes. JSON is much, much faster than serialization and comes out with much smaller results, too (you can even GZip the results to make them smaller still). To put it in perspective, the save time is now unnoticeable, whereas I could count the seconds using Serializable; and the file size was reduced by an order of magnitude.<br /><br />Not only is it better for saving data, it's a very easy way to pass data between components. When I first started, I saw three ways to pass data between components: Serializing, parceling, or storing data in the Application context. Serializing was proving too slow, parceling is really a pain in the ass, and the last solution is harder to integrate with later on (no one else can call your component). JSON has proven a much better solution - it's fast enough to get by, but not nearly the pain in the ass that Parcels are.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1274641920000,
"created_by": 1,
"updated_at": 1274634756666,
"updated_by": 1,
"published_at": 1274641920000,
"published_by": 1
},
{
"id": 65,
"title": "ViewFlipper \"Receiver not registered\" Error",
"slug": "view_flipper_receiver_not_registered_error",
"markdown": "There is this error that plagued me for a few months. If you use a ViewFlipper, this error will pop up on Android 2.1 devices every once in a while:\n\n<pre>java.lang.IllegalArgumentException: Receiver not registered: android.widget.ViewFlipper$1@44b6ab90</pre>\n\nIt does not affect any devices before 2.1, and so what was troubling at first was that the 2.1 source code wasn't yet released so I could't diagnose the issue. Everyone knew it had to do with orientation changes on an Activity with a ViewFlipper, but why exactly it happens isn't clear ([I took my own stab at it, but was incorrect about the exact cause](http://code.google.com/p/android/issues/detail?id=6191); it just seems to happen randomly).\n\nThankfully, [the source has been available now for a while](http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob_plain;f=core/java/android/widget/ViewFlipper.java;hb=HEAD). Obviously, the problem is that onDetachedFromWindow() is somehow being called before onAttachedToWindow(); but how do we come up with a workaround until it is fixed at Google?\n\nOne simple solution is to override onDetachedFromWindow() and catch the error from super:\n\n<pre>@Override\nprotected void onDetachedFromWindow() {\n try {\n super.onDetachedFromWindow();\n }\n catch (IllegalArgumentException e) {\n\n }\n}</pre>\n\nThe only problem with this is that the error is thrown before calling updateRunning(). A simple workaround for this is to call stopFlipping(), as that will kick off updateRunning() without any negative side effects:\n\n<pre>@Override\nprotected void onDetachedFromWindow() {\n try {\n super.onDetachedFromWindow();\n }\n catch (IllegalArgumentException e) {\n stopFlipping();\n }\n}</pre>\n\nYou should only use this version of the class on Android 2.1 phones, as they are the only ones requiring the fix.\n\nEDIT May 25, 2010: ViewFlipper bug still occurs in Android 2.2\\. I sure hope you didn't filter based on apiLevel == 7; better to use apiLevel >= 7.",
"html": "There is this error that plagued me for a few months. If you use a ViewFlipper, this error will pop up on Android 2.1 devices every once in a while:<br /><br /><pre>java.lang.IllegalArgumentException: Receiver not registered: android.widget.ViewFlipper$1@44b6ab90</pre><br /><br />It does not affect any devices before 2.1, and so what was troubling at first was that the 2.1 source code wasn't yet released so I could't diagnose the issue. Everyone knew it had to do with orientation changes on an Activity with a ViewFlipper, but why exactly it happens isn't clear (<a href=\"http://code.google.com/p/android/issues/detail?id=6191\">I took my own stab at it, but was incorrect about the exact cause</a>; it just seems to happen randomly).<br /><br />Thankfully, <a href=\"http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob_plain;f=core/java/android/widget/ViewFlipper.java;hb=HEAD\">the source has been available now for a while</a>. Obviously, the problem is that onDetachedFromWindow() is somehow being called before onAttachedToWindow(); but how do we come up with a workaround until it is fixed at Google?<br /><br />One simple solution is to override onDetachedFromWindow() and catch the error from super:<br /><br /><pre>@Override<br />protected void onDetachedFromWindow() {<br /> try {<br /> super.onDetachedFromWindow();<br /> }<br /> catch (IllegalArgumentException e) {<br /><br /> }<br />}</pre><br /><br />The only problem with this is that the error is thrown before calling updateRunning(). A simple workaround for this is to call stopFlipping(), as that will kick off updateRunning() without any negative side effects:<br /><br /><pre>@Override<br />protected void onDetachedFromWindow() {<br /> try {<br /> super.onDetachedFromWindow();<br /> }<br /> catch (IllegalArgumentException e) {<br /> stopFlipping();<br /> }<br />}</pre><br /><br />You should only use this version of the class on Android 2.1 phones, as they are the only ones requiring the fix.<br /><br />EDIT May 25, 2010: ViewFlipper bug still occurs in Android 2.2. I sure hope you didn't filter based on apiLevel == 7; better to use apiLevel >= 7.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1272897960000,
"created_by": 1,
"updated_at": 1274820749947,
"updated_by": 1,
"published_at": 1272897960000,
"published_by": 1
},
{
"id": 66,
"title": "Why They Can't Find Your App",
"slug": "why_they_can_t_find_your_app",
"markdown": "The Android Market is a mixed blessing; on the one hand, I much prefer the near-instantaneous publishing time for applications. It makes things a lot less stressful; if there's a terrible bug you can fix it quickly instead of having to go through Apple's approval process all over again. On the other hand, it has a number of bugs and limitations that are frustrating.\n\nOne of the most common support emails I get is \"why can't I find your app on the Market?\" This is a sad email, one of a customer lost; and over time (from contact with Google or perusing the net) I've come up with a good list of reasons why customers can't find my applications. Here it is, to help others diagnose the dreaded customer-who-would-be (in order of most likely to least likely):\n\n1\\. The customer has an older version of Android that your app does not support; for example, if you support 2.x but the user is on a 1.5 phone.\n\n2\\. Paid apps are only supported in some countries; if the customer is not in one of these countries, then you will not be able to find or purchase any paid applications. [The list of supported countries can be found here](http://market.android.com/support/bin/answer.py?hl=en&amp;answer=143779).\n\nNote that the customer can't simply move to a different country, either; this limitation is dependent on where your phone plan originally comes from. (Thanks to a European customer who confirmed this for me on a business trip!)\n\n3\\. The customer is using a Google Apps account, rather than a gmail.com account. This can either cause the app not to appear at all, or in some cases make it unpurchaseable. [More details can be found here](http://www.google.com/support/forum/p/Android+Market/thread?tid=5be7ec2291114a13&amp;hl=en).\n\n4\\. The customer has a recently released phone and Google hasn't \"fingerprinted\" that device yet. This blocks all paid apps from that device. The only solution is to wait until Google fingerprints; [it was kind of a pain with HTC Desire](http://www.google.com/support/forum/p/Android+Market/thread?tid=72687bc93eba9a1b&amp;hl=en), at it took them a few weeks to get around to it.\n\n5\\. The customer is using a non-standard build of Android (that is, rooted and installed a custom ROM). Some of these builds cause the Market to malfunction and fail to display paid apps.\n\n6\\. The customer is using an Android Developer Phone and your application has copyright protection enabled. ADPs aren't allowed to view copyright protection applications. [More info here](http://market.android.com/support/bin/answer.py?hl=en&amp;answer=141659).\n\n7\\. This is by far the least likely situation, but you can't buy your own app under the same account as you published from!",
"html": "The Android Market is a mixed blessing; on the one hand, I much prefer the near-instantaneous publishing time for applications. It makes things a lot less stressful; if there's a terrible bug you can fix it quickly instead of having to go through Apple's approval process all over again. On the other hand, it has a number of bugs and limitations that are frustrating.<br /><br />One of the most common support emails I get is \"why can't I find your app on the Market?\" This is a sad email, one of a customer lost; and over time (from contact with Google or perusing the net) I've come up with a good list of reasons why customers can't find my applications. Here it is, to help others diagnose the dreaded customer-who-would-be (in order of most likely to least likely):<br /><br />1. The customer has an older version of Android that your app does not support; for example, if you support 2.x but the user is on a 1.5 phone.<br /><br />2. Paid apps are only supported in some countries; if the customer is not in one of these countries, then you will not be able to find or purchase any paid applications. <a href=\"http://market.android.com/support/bin/answer.py?hl=en&amp;answer=143779\">The list of supported countries can be found here</a>.<br /><br />Note that the customer can't simply move to a different country, either; this limitation is dependent on where your phone plan originally comes from. (Thanks to a European customer who confirmed this for me on a business trip!)<br /><br />3. The customer is using a Google Apps account, rather than a gmail.com account. This can either cause the app not to appear at all, or in some cases make it unpurchaseable. <a href=\"http://www.google.com/support/forum/p/Android+Market/thread?tid=5be7ec2291114a13&amp;hl=en\">More details can be found here</a>.<br /><br />4. The customer has a recently released phone and Google hasn't \"fingerprinted\" that device yet. This blocks all paid apps from that device. The only solution is to wait until Google fingerprints; <a href=\"http://www.google.com/support/forum/p/Android+Market/thread?tid=72687bc93eba9a1b&amp;hl=en\">it was kind of a pain with HTC Desire</a>, at it took them a few weeks to get around to it.<br /><br />5. The customer is using a non-standard build of Android (that is, rooted and installed a custom ROM). Some of these builds cause the Market to malfunction and fail to display paid apps.<br /><br />6. The customer is using an Android Developer Phone and your application has copyright protection enabled. ADPs aren't allowed to view copyright protection applications. <a href=\"http://market.android.com/support/bin/answer.py?hl=en&amp;answer=141659\">More info here</a>.<br /><br />7. This is by far the least likely situation, but you can't buy your own app under the same account as you published from!",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1272896700000,
"created_by": 1,
"updated_at": 1386865916037,
"updated_by": 1,
"published_at": 1272896700000,
"published_by": 1
},
{
"id": 67,
"title": "The Missing Manual - Android Drawables from XML",
"slug": "the_missing_manual_android_drawables_from_xml",
"markdown": "I have been fairly frustrated with a gap in the Android documentation recently - the file formats for creating Drawables from XML. Drawables XML has been pretty useful to me in the past in creating gradients; I'd rather use it than create 9-patches all the time. However, the Android documentation is strangely silent about the format; they provide a few samples, but as far as I know there's nothing beyond that.\n\nI've taken it upon myself to study the source code and create a missing manual for all the possibilities for Drawable XMLs. The data was gathered from the Android source code, from the [android.graphics.drawables](http://android.git.kernel.org/?p=platform/frameworks/base.git;a=tree;f=graphics/java/android/graphics/drawable;h=edf3142b151e2dfc2c84dffc07206ee0447a5cb7;hb=HEAD) package. I was surprised to find a lot of really useful code I wish I'd known about a long time ago; regardless, I was able to figure out all of how Drawables XML works.\n\nWithout further ado, here it is: [the missing manual on Android Drawables via XML](http://idunnolol.com/android/drawables.html). I hope this lessens the pain someone else has slightly.",
"html": "I have been fairly frustrated with a gap in the Android documentation recently - the file formats for creating Drawables from XML. Drawables XML has been pretty useful to me in the past in creating gradients; I'd rather use it than create 9-patches all the time. However, the Android documentation is strangely silent about the format; they provide a few samples, but as far as I know there's nothing beyond that.<br /><br />I've taken it upon myself to study the source code and create a missing manual for all the possibilities for Drawable XMLs. The data was gathered from the Android source code, from the <a href=\"http://android.git.kernel.org/?p=platform/frameworks/base.git;a=tree;f=graphics/java/android/graphics/drawable;h=edf3142b151e2dfc2c84dffc07206ee0447a5cb7;hb=HEAD\">android.graphics.drawables</a> package. I was surprised to find a lot of really useful code I wish I'd known about a long time ago; regardless, I was able to figure out all of how Drawables XML works.<br /><br />Without further ado, here it is: <a href=\"http://idunnolol.com/android/drawables.html\">the missing manual on Android Drawables via XML</a>. I hope this lessens the pain someone else has slightly.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1271019420001,
"created_by": 1,
"updated_at": 1271019733386,
"updated_by": 1,
"published_at": 1271019420001,
"published_by": 1
},
{
"id": 68,
"title": "Uri and Android 1.5",
"slug": "uri_and_android_1_5",
"markdown": "I came across an interesting Android bug the other day that deserves some mention.\n\nI was creating an Intent, setting some data for it, then calling startActivity(). The data Uri was created via Uri.Builder. Let's say, for example, the Uri I wanted was \"http://google.com\". The code would look like thus:\n\n<pre>Intent intent = new Intent(context, TestActivity.class);\nUri.Builder builder = new Uri.Builder();\nbuilder.scheme(\"http\");\nbuilder.authority(\"google.com\");\nintent.setData(builder.build());\nstartActivity(intent);</pre>\nThis works in 1.6+. But an interesting thing happens if you try this in 1.5... it blows up in your face with NullPointerExceptions! To answer why, I ended up digging around [previous versions of the android.net.Uri class](http://android.git.kernel.org/?p=platform/frameworks/base.git;a=history;f=core/java/android/net/Uri.java;h=9a1b65de15915ddf5f0897cfada93913ccb3247a;hb=HEAD). It turns out that, previous to 1.6, Uri expects you to fill out <span style=\"font-weight:bold;\">every</span> part of the Uri - including the query parameters (parts following ?) as well as the fragment (part following #).\n\nThe fix is to add dummy parameters for the sake of Android 1.5:\n\n<pre>Intent intent = new Intent(context, TestActivity.class);\nUri.Builder builder = new Uri.Builder();\nbuilder.scheme(\"http\");\nbuilder.authority(\"google.com\");\nbuilder.appendQueryParameter(\"ignore\", \"ignore\");\nbuilder.fragment(\"ignore\");\nintent.setData(builder.build());\nstartActivity(intent);</pre>\nThis isn't a problem if you already are using all parts of a Uri, or if you only support Android 1.6+.",
"html": "I came across an interesting Android bug the other day that deserves some mention.<br /><br />I was creating an Intent, setting some data for it, then calling startActivity(). The data Uri was created via Uri.Builder. Let's say, for example, the Uri I wanted was \"http://google.com\". The code would look like thus:<br /><br /><pre>Intent intent = new Intent(context, TestActivity.class);<br />Uri.Builder builder = new Uri.Builder();<br />builder.scheme(\"http\");<br />builder.authority(\"google.com\");<br />intent.setData(builder.build());<br />startActivity(intent);</pre><br />This works in 1.6+. But an interesting thing happens if you try this in 1.5... it blows up in your face with NullPointerExceptions! To answer why, I ended up digging around <a href=\"http://android.git.kernel.org/?p=platform/frameworks/base.git;a=history;f=core/java/android/net/Uri.java;h=9a1b65de15915ddf5f0897cfada93913ccb3247a;hb=HEAD\">previous versions of the android.net.Uri class</a>. It turns out that, previous to 1.6, Uri expects you to fill out <span style=\"font-weight:bold;\">every</span> part of the Uri - including the query parameters (parts following ?) as well as the fragment (part following #).<br /><br />The fix is to add dummy parameters for the sake of Android 1.5:<br /><br /><pre>Intent intent = new Intent(context, TestActivity.class);<br />Uri.Builder builder = new Uri.Builder();<br />builder.scheme(\"http\");<br />builder.authority(\"google.com\");<br />builder.appendQueryParameter(\"ignore\", \"ignore\");<br />builder.fragment(\"ignore\");<br />intent.setData(builder.build());<br />startActivity(intent);</pre><br />This isn't a problem if you already are using all parts of a Uri, or if you only support Android 1.6+.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1268239200000,
"created_by": 1,
"updated_at": 1268340170419,
"updated_by": 1,
"published_at": 1268239200000,
"published_by": 1
},
{
"id": 69,
"title": "ViewFlipper and Memory Leaks",
"slug": "view_flipper_and_memory_leaks",
"markdown": "Have you ever had a mysterious memory leak on Android when your code seemed clean as a whistle? I sure have, and I finally figured out why: ViewFlipper.\n\nIt turns out that when you call ViewFlipper.startFlipping(), it sets up a loop via messages which flips between its child Views. This is all well and good, but there's no code which detects that the ViewFlipper itself is no longer being displayed and should be canned. So the ViewFlipper keeps a hold on itself and its children, who inevitably keep a hold on their Context, and bam - gigantic memory leak. Depending on how much memory your Activity takes up, all you need to do is start changing the orientation of the ViewFlipper's containing Activity a few times and you could crash your application.\n\nThe solution to this is relatively simple: just call ViewFlipper.stopFlipping() in your Activity's onPause(), and then have it start flipping again in onResume().\n\nThere is, however, one small catch. Since ViewFlipper uses delayed messages, it's possible that a user can pause your activity then resume within the amount of time between flips (if they hit power then menu in quick succession, for example). The way ViewFlipper is setup, this means you can end up with multiple flip messages being passed around, resulting in faster flipping than intended. Unfortunately, the only solution I can think of to this is a real hassle (you would have to intentionally delay some time before resuming flipping in onResume()), so I'm just ignoring it for now.",
"html": "Have you ever had a mysterious memory leak on Android when your code seemed clean as a whistle? I sure have, and I finally figured out why: ViewFlipper.<br /><br />It turns out that when you call ViewFlipper.startFlipping(), it sets up a loop via messages which flips between its child Views. This is all well and good, but there's no code which detects that the ViewFlipper itself is no longer being displayed and should be canned. So the ViewFlipper keeps a hold on itself and its children, who inevitably keep a hold on their Context, and bam - gigantic memory leak. Depending on how much memory your Activity takes up, all you need to do is start changing the orientation of the ViewFlipper's containing Activity a few times and you could crash your application.<br /><br />The solution to this is relatively simple: just call ViewFlipper.stopFlipping() in your Activity's onPause(), and then have it start flipping again in onResume().<br /><br />There is, however, one small catch. Since ViewFlipper uses delayed messages, it's possible that a user can pause your activity then resume within the amount of time between flips (if they hit power then menu in quick succession, for example). The way ViewFlipper is setup, this means you can end up with multiple flip messages being passed around, resulting in faster flipping than intended. Unfortunately, the only solution I can think of to this is a real hassle (you would have to intentionally delay some time before resuming flipping in onResume()), so I'm just ignoring it for now.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1263844980000,
"created_by": 1,
"updated_at": 1263846078750,
"updated_by": 1,
"published_at": 1263844980000,
"published_by": 1
},
{
"id": 70,
"title": "Android Dialogs Created From Threads",
"slug": "android_dialogs_created_from_threads",
"markdown": "There are a lot of issues with Dialogs, but I've run into one recently that deserves mention.\n\nSuppose you've got a background task running with AsyncTask. At the end of this task (in onPostExecute()), you display a Dialog informing the user of success or failure. This seems to be pretty cut and dry, but there's a catch - sometimes you'll get this error:\n\n<pre>android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@4479b390 is not valid; is your activity running?\n at android.view.ViewRoot.setView(ViewRoot.java:468)\n at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)\n at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)\n at android.view.Window$LocalWindowManager.addView(Window.java:424)\n at android.app.Dialog.show(Dialog.java:239)\n at android.app.Activity.showDialog(Activity.java:2488)\n ...</pre>\nThe problem lies in the fact that the AsyncTask can continue running past when the Activity itself has been finished. If a user hits the \"back\" button on your Activity while the AsyncTask is running, you will end up calling showDialog() after the Activity itself is finished.\n\nMy initial fix was to try to augment onCreateDialog() to handle finished activities, but unfortunately, there's no way to cancel dialog creation once you've called showDialog(); you'll cause errors returning null from onCreateDialog(). Thus, the only solution is to play it safe before you call showDialog():\n\n<pre>protected void onPostExecute(Object result) {\n if (!isFinishing()) {\n showDialog(MY_DIALOG_ID);\n }\n}</pre>",
"html": "There are a lot of issues with Dialogs, but I've run into one recently that deserves mention.<br /><br />Suppose you've got a background task running with AsyncTask. At the end of this task (in onPostExecute()), you display a Dialog informing the user of success or failure. This seems to be pretty cut and dry, but there's a catch - sometimes you'll get this error:<br /><br /><pre>android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@4479b390 is not valid; is your activity running?<br /> at android.view.ViewRoot.setView(ViewRoot.java:468)<br /> at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)<br /> at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)<br /> at android.view.Window$LocalWindowManager.addView(Window.java:424)<br /> at android.app.Dialog.show(Dialog.java:239)<br /> at android.app.Activity.showDialog(Activity.java:2488)<br /> ...</pre><br />The problem lies in the fact that the AsyncTask can continue running past when the Activity itself has been finished. If a user hits the \"back\" button on your Activity while the AsyncTask is running, you will end up calling showDialog() after the Activity itself is finished.<br /><br />My initial fix was to try to augment onCreateDialog() to handle finished activities, but unfortunately, there's no way to cancel dialog creation once you've called showDialog(); you'll cause errors returning null from onCreateDialog(). Thus, the only solution is to play it safe before you call showDialog():<br /><br /><pre>protected void onPostExecute(Object result) {<br /> if (!isFinishing()) {<br /> showDialog(MY_DIALOG_ID);<br /> }<br />}</pre>",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1262205120001,
"created_by": 1,
"updated_at": 1262205677963,
"updated_by": 1,
"published_at": 1262205120001,
"published_by": 1
},
{
"id": 71,
"title": "Dynamically Retrieving Resources in Android",
"slug": "dynamically_retrieving_resources_in_android",
"markdown": "Normally, when retrieving resources (drawables, strings, what have you) in code you use the automatically generated R.java to do so. However, I recently wrote a reference application wherein each item in a ListView has a different icon next to it. The data for all this is stored in JSON as an asset, which meant that there was no way for me to link my data to R.java.\n\nStill, I needed some way to get a hold of the Drawable by name, and so I first turned to [Resources.getIdentifier()](http://developer.android.com/reference/android/content/res/Resources.html#getIdentifier(java.lang.String,%20java.lang.String,%20java.lang.String)). This method does the job well of finding the resource id of anything you desire, in any package:\n\n<pre>Resources r = getResources();\nint drawableId = r.getIdentifier(\"drawableName\", \"drawable\", \"com.mypackage.myapp\");</pre>\nThis is all well and good, but: getIdentifier() is a general tool and as a result, slow. Running through 10,000 iterations, it took about 3200 ms on my G1\\. Also, it requires that you pass around a Context (or a Resources) wherever you need to use getIdentifier() which is an annoyance and seems unnecessary given that you can access R.java just fine normally in code.\n\nThe better solution - as long as you are retrieving data from your application's own R.java - is to use reflection.\n\n<pre>try {\n Class res = R.drawable.class;\n Field field = res.getField(\"drawableName\");\n int drawableId = field.getInt(null);\n}\ncatch (Exception e) {\n Log.e(\"MyTag\", \"Failure to get drawable id.\", e);\n}</pre>\nIn testing, the second method is about 5x faster than getIdentifier(). Not only that, but it means you don't have to pass a Resources object around to use it. Obviously this cannot be used if you're accessing resources outside of your application's permissions and you'll have to rely on getIdentifier() then.\n\nOne last note - simply linking to R.java is way faster than either of these two methods, so only fall back on these if you need to link to resource identifiers dynamically by name.",
"html": "Normally, when retrieving resources (drawables, strings, what have you) in code you use the automatically generated R.java to do so. However, I recently wrote a reference application wherein each item in a ListView has a different icon next to it. The data for all this is stored in JSON as an asset, which meant that there was no way for me to link my data to R.java.<br /><br />Still, I needed some way to get a hold of the Drawable by name, and so I first turned to <a href=\"http://developer.android.com/reference/android/content/res/Resources.html#getIdentifier(java.lang.String,%20java.lang.String,%20java.lang.String)\">Resources.getIdentifier()</a>. This method does the job well of finding the resource id of anything you desire, in any package:<br /><br /><pre>Resources r = getResources();<br />int drawableId = r.getIdentifier(\"drawableName\", \"drawable\", \"com.mypackage.myapp\");</pre><br />This is all well and good, but: getIdentifier() is a general tool and as a result, slow. Running through 10,000 iterations, it took about 3200 ms on my G1. Also, it requires that you pass around a Context (or a Resources) wherever you need to use getIdentifier() which is an annoyance and seems unnecessary given that you can access R.java just fine normally in code.<br /><br />The better solution - as long as you are retrieving data from your application's own R.java - is to use reflection.<br /><br /><pre>try {<br /> Class res = R.drawable.class;<br /> Field field = res.getField(\"drawableName\");<br /> int drawableId = field.getInt(null);<br />}<br />catch (Exception e) {<br /> Log.e(\"MyTag\", \"Failure to get drawable id.\", e);<br />}</pre><br />In testing, the second method is about 5x faster than getIdentifier(). Not only that, but it means you don't have to pass a Resources object around to use it. Obviously this cannot be used if you're accessing resources outside of your application's permissions and you'll have to rely on getIdentifier() then.<br /><br />One last note - simply linking to R.java is way faster than either of these two methods, so only fall back on these if you need to link to resource identifiers dynamically by name.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1261933560000,
"created_by": 1,
"updated_at": 1262105541888,
"updated_by": 1,
"published_at": 1261933560000,
"published_by": 1
},
{
"id": 72,
"title": "Android Add-On Applications",
"slug": "android_add_on_applications",
"markdown": "I recently developed an add-on package for an Android application and thought I'd share some findings. That is, there is a base application and an add-on application which unlocks extras features in the base app.\n\nI chose to put all the functionality in the base application and simply have the add-on unlock it. It turns out that this is very easy to do due to Android's dependence on [signing keys](http://developer.android.com/guide/publishing/app-signing.html). First, I made an application that has no components - it has no launcher, code, or layouts. All it has is a launcher icon (as this is viewable from the market and applications settings). Next, I signed both the base application and the add-on with the same key. Then, you can use the [PackageManager](http://developer.android.com/reference/android/content/pm/PackageManager.html) to verify if the other application is installed:\n\n<pre>public static boolean isAddOnInstalled(Context context) {\n PackageManager pm = context.getPackageManager();\n return pm.checkSignatures(BASE_APPLICATION_PACKAGE, ADDON_APPLICATION_PACKAGE) == PackageManager.SIGNATURE_MATCH;\n}</pre>\nThe neat part of this solution is that it relies on the PackageManager's signature checking to verify the add-on. If the add-on application doesn't exist, or it was signed by a different key, this will return false.\n\nAn alternative way to do add-ons would be to put actual functionality or data in the add-on package. Again, you can use signing keys to share data. Beyond this, you can use [sharedUserId](http://developer.android.com/guide/topics/manifest/manifest-element.html#uid) to put both the base application and the add-on application in the same user ID. This will allow the applications to access each others' data files directory. A warning, though: it appears that adding a sharedUserId after the initial install causes the old data directory to still be under the old user ID, thus making all of your old files inaccessible (nor can you start writing new files - it kind of sucks). [Google isn't acknowledging this issue](http://code.google.com/p/android/issues/detail?id=1227), unfortunately.\n\nOne might think the way to go would be to use a ContentProvider, but if you're just doing an add-on for your own application, do you need to share the data with others? Besides that, ContentProviders are a much more difficult solution for a simple problem when you're working with just your own data. This isn't to say you shouldn't use ContentProviders, just that you should use the right tool for the job.",
"html": "I recently developed an add-on package for an Android application and thought I'd share some findings. That is, there is a base application and an add-on application which unlocks extras features in the base app.<br /><br />I chose to put all the functionality in the base application and simply have the add-on unlock it. It turns out that this is very easy to do due to Android's dependence on <a href=\"http://developer.android.com/guide/publishing/app-signing.html\">signing keys</a>. First, I made an application that has no components - it has no launcher, code, or layouts. All it has is a launcher icon (as this is viewable from the market and applications settings). Next, I signed both the base application and the add-on with the same key. Then, you can use the <a href=\"http://developer.android.com/reference/android/content/pm/PackageManager.html\">PackageManager</a> to verify if the other application is installed:<br /><br /><pre>public static boolean isAddOnInstalled(Context context) {<br /> PackageManager pm = context.getPackageManager();<br /> return pm.checkSignatures(BASE_APPLICATION_PACKAGE, ADDON_APPLICATION_PACKAGE) == PackageManager.SIGNATURE_MATCH;<br />}</pre><br />The neat part of this solution is that it relies on the PackageManager's signature checking to verify the add-on. If the add-on application doesn't exist, or it was signed by a different key, this will return false.<br /><br />An alternative way to do add-ons would be to put actual functionality or data in the add-on package. Again, you can use signing keys to share data. Beyond this, you can use <a href=\"http://developer.android.com/guide/topics/manifest/manifest-element.html#uid\">sharedUserId</a> to put both the base application and the add-on application in the same user ID. This will allow the applications to access each others' data files directory. A warning, though: it appears that adding a sharedUserId after the initial install causes the old data directory to still be under the old user ID, thus making all of your old files inaccessible (nor can you start writing new files - it kind of sucks). <a href=\"http://code.google.com/p/android/issues/detail?id=1227\">Google isn't acknowledging this issue</a>, unfortunately.<br /><br />One might think the way to go would be to use a ContentProvider, but if you're just doing an add-on for your own application, do you need to share the data with others? Besides that, ContentProviders are a much more difficult solution for a simple problem when you're working with just your own data. This isn't to say you shouldn't use ContentProviders, just that you should use the right tool for the job.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1261002120000,
"created_by": 1,
"updated_at": 1386865903033,
"updated_by": 1,
"published_at": 1261002120000,
"published_by": 1
},
{
"id": 73,
"title": "Welcome",
"slug": "welcome",
"markdown": "Starting a new blog because I keep coming across old blog posts other coders make that help me... I figure it's time for me to give back to the community.",
"html": "Starting a new blog because I keep coming across old blog posts other coders make that help me... I figure it's time for me to give back to the community.",
"image": null,
"featured": 0,
"page": 0,
"status": "published",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"author_id": 1,
"created_at": 1260316560000,
"created_by": 1,
"updated_at": 1260316646940,
"updated_by": 1,
"published_at": 1260316560000,
"published_by": 1
}
],
"tags": [
{
"id": 0,
"name": "android",
"slug": "android",
"description": ""
},
{
"id": 1,
"name": "apps",
"slug": "apps",
"description": ""
},
{
"id": 2,
"name": "conferences",
"slug": "conferences",
"description": ""
},
{
"id": 3,
"name": "palm",
"slug": "palm",
"description": ""
},
{
"id": 4,
"name": "testing",
"slug": "testing",
"description": ""
},
{
"id": 5,
"name": "bugs",
"slug": "bugs",
"description": ""
},
{
"id": 6,
"name": "fragments",
"slug": "fragments",
"description": ""
},
{
"id": 7,
"name": "library",
"slug": "library",
"description": ""
},
{
"id": 8,
"name": "mat",
"slug": "mat",
"description": ""
},
{
"id": 9,
"name": "memory",
"slug": "memory",
"description": ""
},
{
"id": 10,
"name": "passwords",
"slug": "passwords",
"description": ""
},
{
"id": 11,
"name": "piracy",
"slug": "piracy",
"description": ""
},
{
"id": 12,
"name": "python",
"slug": "python",
"description": ""
},
{
"id": 13,
"name": "webos",
"slug": "webos",
"description": ""
}
],
"posts_tags": [
{
"tag_id": 0,
"post_id": 1
},
{
"tag_id": 4,
"post_id": 1
},
{
"tag_id": 0,
"post_id": 2
},
{
"tag_id": 1,
"post_id": 2
},
{
"tag_id": 0,
"post_id": 3
},
{
"tag_id": 4,
"post_id": 3
},
{
"tag_id": 0,
"post_id": 4
},
{
"tag_id": 0,
"post_id": 5
},
{
"tag_id": 0,
"post_id": 6
},
{
"tag_id": 1,
"post_id": 6
},
{
"tag_id": 0,
"post_id": 7
},
{
"tag_id": 1,
"post_id": 7
},
{
"tag_id": 0,
"post_id": 8
},
{
"tag_id": 2,
"post_id": 8
},
{
"tag_id": 0,
"post_id": 9
},
{
"tag_id": 0,
"post_id": 10
},
{
"tag_id": 0,
"post_id": 11
},
{
"tag_id": 2,
"post_id": 11
},
{
"tag_id": 0,
"post_id": 12
},
{
"tag_id": 0,
"post_id": 13
},
{
"tag_id": 0,
"post_id": 14
},
{
"tag_id": 0,
"post_id": 15
},
{
"tag_id": 0,
"post_id": 16
},
{
"tag_id": 1,
"post_id": 16
},
{
"tag_id": 12,
"post_id": 17
},
{
"tag_id": 0,
"post_id": 18
},
{
"tag_id": 8,
"post_id": 18
},
{
"tag_id": 9,
"post_id": 18
},
{
"tag_id": 0,
"post_id": 19
},
{
"tag_id": 0,
"post_id": 20
},
{
"tag_id": 0,
"post_id": 21
},
{
"tag_id": 0,
"post_id": 22
},
{
"tag_id": 1,
"post_id": 22
},
{
"tag_id": 0,
"post_id": 23
},
{
"tag_id": 0,
"post_id": 24
},
{
"tag_id": 0,
"post_id": 25
},
{
"tag_id": 0,
"post_id": 26
},
{
"tag_id": 0,
"post_id": 27
},
{
"tag_id": 0,
"post_id": 28
},
{
"tag_id": 0,
"post_id": 29
},
{
"tag_id": 6,
"post_id": 29
},
{
"tag_id": 0,
"post_id": 30
},
{
"tag_id": 5,
"post_id": 30
},
{
"tag_id": 0,
"post_id": 31
},
{
"tag_id": 0,
"post_id": 32
},
{
"tag_id": 0,
"post_id": 33
},
{
"tag_id": 0,
"post_id": 34
},
{
"tag_id": 0,
"post_id": 35
},
{
"tag_id": 2,
"post_id": 35
},
{
"tag_id": 0,
"post_id": 36
},
{
"tag_id": 0,
"post_id": 37
},
{
"tag_id": 0,
"post_id": 38
},
{
"tag_id": 0,
"post_id": 39
},
{
"tag_id": 7,
"post_id": 39
},
{
"tag_id": 0,
"post_id": 40
},
{
"tag_id": 0,
"post_id": 41
},
{
"tag_id": 0,
"post_id": 42
},
{
"tag_id": 0,
"post_id": 43
},
{
"tag_id": 0,
"post_id": 44
},
{
"tag_id": 0,
"post_id": 45
},
{
"tag_id": 10,
"post_id": 46
},
{
"tag_id": 0,
"post_id": 47
},
{
"tag_id": 0,
"post_id": 48
},
{
"tag_id": 0,
"post_id": 49
},
{
"tag_id": 0,
"post_id": 50
},
{
"tag_id": 0,
"post_id": 51
},
{
"tag_id": 0,
"post_id": 52
},
{
"tag_id": 0,
"post_id": 53
},
{
"tag_id": 0,
"post_id": 54
},
{
"tag_id": 0,
"post_id": 55
},
{
"tag_id": 11,
"post_id": 55
},
{
"tag_id": 3,
"post_id": 56
},
{
"tag_id": 0,
"post_id": 57
},
{
"tag_id": 3,
"post_id": 58
},
{
"tag_id": 0,
"post_id": 59
},
{
"tag_id": 0,
"post_id": 60
},
{
"tag_id": 13,
"post_id": 61
},
{
"tag_id": 0,
"post_id": 62
},
{
"tag_id": 0,
"post_id": 63
},
{
"tag_id": 1,
"post_id": 63
},
{
"tag_id": 0,
"post_id": 64
},
{
"tag_id": 0,
"post_id": 65
},
{
"tag_id": 0,
"post_id": 66
},
{
"tag_id": 0,
"post_id": 67
},
{
"tag_id": 0,
"post_id": 68
},
{
"tag_id": 0,
"post_id": 69
},
{
"tag_id": 0,
"post_id": 70
},
{
"tag_id": 0,
"post_id": 71
},
{
"tag_id": 0,
"post_id": 72
}
]
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment