Mark L. Murphy's Blog, page 70
November 20, 2012
Think About android:allowBackup
It is always interesting to see what things show up as new Lint rules when a new version of the Android developer tools is released. One from R21 stunned me:
Should explicitly set android:allowBackup to true or false (it’s true by default, and that can have some security implications for the application’s data)
I could not figure out how I had missed this… until I realized that android:allowBackup is not actually documented in the docs for the <application> element. Instead, it is documented in the documenation of BackupManager, a class pertaining to Google’s proprietary data backup service. With luck, this attribute will be documented in both places in the future.
As the quoted Lint warning indicates, android:allowBackup defaults to true, meaning that your app’s data can be backed up. This includes the opt-in backup stuff that I am not a fan of and also an adb-based full backup command.
It is entirely possible that you want your app to be backed up in this fashion. It is also entirely possible that you do not. Hence, as you edit your app in R21, go into the manifest and explicitly assign true or false to android:allowBackup, thinking along the way which is the right answer for you.
November 19, 2012
Busting a Mobile App Dev Patent
A company named Appsbar has been granted a patent on creating a cross-platform mobile app via code generation via a specific user interface.
This patent is actually fairly narrow in scope, as it requires a particular flow of user interface for collecting the information that drives the code generation process. It is really designed for those “create your own mobile app” sorts of Web sites, more than anything normally associated with traditional software development.
However, the firm has stated that they intend to go after “other companies that currently provide similar types of services”. Patents, when used as offensive weapons, nowadays tend to get used in a “shotgun” approach, where anything vaguely resembling the patent is a possible target, in a process reminiscent of mob-style shakedowns. At least, that is the pattern here in the US, where software patents abound.
Hence, I am starting to collect prior art on this patent, courtesy of StackExchange’s Ask Patents site. I have lots of notes on this market segment, which I will be perusing and posting to the Ask Patents item over time.
However, if you are familiar with any “create your own mobile app” sites or related techology, please post answers to the item. In particular, I am interested in those that might have been created before February 14, 2012 (or, better yet, April 6, 2011, when a related provisional patent was applied for), as they would represent possible prior art for the patent.
Thanks in advance!
November 14, 2012
Fixing the "Fixing the First Impression"
Having more information on Android development published is generally a good thing, particularly when it comes to performance. Therefore today’s post from the Amazon team, First Impressions Count: Boost Your App’s Start-Up Time, should be a good thing.
And, indeed, the information conveyed in the post is good. However, it is going to lead developers to waste their time, and their users’ time, because of the manner in which that information is conveyed. Having the right information in the wrong order can drag down otherwise solid writing.
Rule #1: Measure Twice, Cut Once
The premise of the Amazon post is to help apps start quickly. Since a do-nothing app starts as quickly as possible, it stands to reason that apps that do not start quickly has to do with our code. Hence, if your app does not start quickly, you need to find out why.
Two of the more common solutions for this, Traceview and StrictMode are indeed covered in the Amazon post, but not until the very end.
In technical writing, do not “bury the lede” (to borrow a phrase from journalism). Developers, like anyone else, have a chance of abandoning reading before the end is reached. Put high-priority items first in article-length pieces, and there should be nothing higher priority than actually figuring out where your problem lies. Only once you know what you should fix should you figure out how to fix it.
Rule #2: Size Matters
The Amazon post offers many techniques for actually improving launch times, from using background threads to lazy-inflating views. Everything they list is good.
However, not all performance tweaks are created equal.
Some of the ones cited in the Amazon post fall in the area of micro-optimizations, such as “use static methods”. These can have benefits, but only if the affected code is run a zillion times (note: zillion here is shorthand for “some sufficiently large number to make the micro-optimization add up to a user-visible amount of time”).
Unfortunately, micro-optimizations like this and “minimize allocations” are lumped in with macro-optimizations like background threads in Amazon’s blog post.
When discussing performance improvement, try to point out which items are macro-optimizations and which are micro-optimizations. Macro-optimizations (e.g., move I/O to background threads) should be considered anywhere; micro-optimizations should only be considered for code that Traceview (or other diagnostic measures) have indicated are “hot spots” in your code.
Rule #3: Really Try to Fix Things, Before You Fake It
The technique the Amazon piece leads off with is to add a splash screen.
Having splash screens in an app has been decried by:
Cyril Mottier
Juhani Lehtimaki (in his book, Smashing Android UI)
Reto Meier
and many others.
I too dislike splash screens, because they are too often used for purely branding purposes or as a crutch for developers.
Even if you are not opposed to splash screens on UX grounds, having a splash screen makes a slow-launching app even slower. After all, it’s not like splash screens are powered by tachyons and launch in negative time. Hence, in actual terms, a splash screen makes things worse.
Amazon’s contention, echoed by others, is that a splash screen gives the illusion of responsiveness to a less-responsive app. And this may be true, though I would argue that there could be something more useful that could be displayed initially than a splash screen.
But my primary concern is that Amazon presents this option first.
A splash screen to help hide launch time issues is like wearing stripes for the “slimming effect”: possibly useful, but as a last resort (compared to, say, actually losing weight). Non-solutions like splash screens may be worthy of discussion, but only when couched as being a “last resort” technique, and then probably at the end of the post to emphasize the point.
Now, I am sure that I have broken my own rules in any number of places, and I wil be happy to fix them as I encounter them. It is always easier to critique the work of others, and I do not mean my analysis here to indicate that I am free from blame or that Amazon’s post is useless. On the contrary, Amazon’s highlighting of these points is generally a good thing, but the organization of topics in their post unfortunately hinders what otherwise is a fine piece.
Sometimes, packaging does make the product.
November 8, 2012
Minimize Open Files on External Storage, Please
There is some evidence to suggest that on some devices, there is a limit of 1024 simultaenously open file descriptors on external storage. This was mentioned in an android-developers post, which leads to this issue.
What you will see, when you hit the limit, is a FileNotFoundException triggered by an EMFILE error:
11-08 15:57:46.915: E/OpenLotsaFiles2(17398): Exception reading file
11-08 15:57:46.915: E/OpenLotsaFiles2(17398): java.io.FileNotFoundException: /storage/sdcard0/...
(Too many open files)
11-08 15:57:46.915: E/OpenLotsaFiles2(17398): at libcore.io.IoBridge.open(IoBridge.java:416)
11-08 15:57:46.915: E/OpenLotsaFiles2(17398): at java.io.FileInputStream.<init>(FileInputStream.java:78)
11-08 15:57:46.915: E/OpenLotsaFiles2(17398): at com.commonsware.android.olf2.MainActivity...
11-08 15:57:46.915: E/OpenLotsaFiles2(17398): Caused by: libcore.io.ErrnoException: open failed: EMFILE
(Too many open files)
11-08 15:57:46.915: E/OpenLotsaFiles2(17398): at libcore.io.Posix.open(Native Method)
11-08 15:57:46.915: E/OpenLotsaFiles2(17398): at libcore.io.BlockGuardOs.open(BlockGuardOs.java:110)
11-08 15:57:46.915: E/OpenLotsaFiles2(17398): at libcore.io.IoBridge.open(IoBridge.java:400)
11-08 15:57:46.915: E/OpenLotsaFiles2(17398): ... 2 more
Please make sure that you are modest in how many open files you have on external storage at once. It is very possible for there to be quite a few running processes on an Android device nowadays, and if many of them have many open external storage files, apps will start failing with these sorts of errors.
Many thanks to Elliot Hughes for pointing out a flaw in my original test, leading me to write a better test, which has been uploaded to the issue.
November 6, 2012
The Busy Coder's Guide to Android Development Version 4.3 Released
Subscribers now have access to the latest release of The Busy Coder’s Guide to Android Development, known as Version 4.3, in all formats. Just log into your Warescription page and download away, or set up an account and subscribe!
I apologize for the delay in getting this out, caused by a wee hurricane last week. However, it adds over 100 pages of material, so hopefully the delay will be worth it.
Specifically, this update adds:
Coverage of using a ContentProvider as a pipe between your app and some consumer or publisher of a stream, with an example of serving a PDF (theoretically from an encrypted data store) in this fashion
A new chapter on audio recording, including using the aforementioned pipe to allow near-real-time receipt of the audio data
A completely rewritten chapter on drawables, including coverage of all the XML drawable types
An updated chapter on service binding, with an emphasis on remote services
Coverage of single-header PreferenceActivity implementations, both using the conditional preference headers that I blogged about recently and the EXTRA_SHOW_FRAGMENT Intent extra
Coverage of the SecretAgentMan NFC sample app, as seen at the 2012 droidcon UK conference
A new chapter on progress indicators, from ProgressBar through animating a “refresh” action bar item
A new “widget catalog” entry on StackView
Coverage of tying a ViewPager to action bar tabs, and the limitations imposed by this technique
Better coverage of using Eclipse for editing basic resources
A bit more coverage of building x86 binaries as part of your NDK work
A new section on the network monitor in DDMS
And the beginnings of a new chapter outlining anti-patterns in Android development
Notably, this release does not include anything on Android 4.2, because (::ahem::) there is no new SDK at the time of this writing. With luck, and assuming I get 4.2 hardware in time, I will be covering Android 4.2 in the next update to the book.
If you encounter any problems with this update or your Warescription in general, please contact wares@commonsware.com, and be sure to provide your Warescription user ID.
Announcing AndGlobe
I am now maintaining a Web page (backed by a JSON dataset) listing localized Android developer question-and-answer sites.
This is the outcome of my call for global Android developer sites that I posted a few weeks ago.
The JSON dataset and the scripts to generate the page are stored in GitHub.
If you know of other sites that should be included in this roster, please get that information to me — the GitHub project home page has details for how to do this.
Also, I am desperately seeking better translations for my one-sentence site explanation:
These sites are places where you can ask or answer Android application development questions.
Many of the translations presently used on the site are from Google Translate, with your typical awkward results. If you have a replacement that expresses the same concept (not necessarily a literal translation), please send it to me, such as via globaldev@commonsware.com.
If you would like to integrate the data on your own site, or otherwise offer your own front-end to the JSON, feel free to do so, as the data is available under the Creative Commons Attribution-ShareAlike 3.0 Unported License. For more tactical changes, file issues or contribute pull requests that I can attempt to integrate.
Finally, if you know of some already-existing resource that does a better job with this than I am, please point me to it. I do not want to “reinvent the wheel”, so I would rather help somebody else succeed if somebody else already has more content and more momentum.
Thanks in advance for any contributions!
November 1, 2012
I Shall Return. Eventually.
My apologies for anyone who has been trying to reach me these past ~60 hours. My home has been without power and Internet during that time, courtesy of Hurricane Sandy. My cell tower started working overnight, which is why I can get this blog post out.
I will be online intermittently until I can get to stable power, either because power here has been restored or I have been able to solve a transportation issue and get somewhere that already has power.
Subscribers: I have rescheduled this week’s office hours chats to next week, as I missed Tuesday’s and may not be able to make today’s depending on how things go.
October 23, 2012
No Unnecessary Accounts, Please
The iosched sample app is a fine bit of engineering and a useful source for mining various Android development techniques. However, first and foremost, it is a production app for the Google I|O conference. That limits its appropriateness as a template for other apps, even apps for other conferences.
Notably, when you run the app, you are immediately required to supply a Google account, and if you do not do so, you cannot enter the main portion of the app.
This is a regrettable decision by the authors of iosched. There are many features of a conference app that should not require a Google account, such as viewing the list of sessions and viewing details of a given session. Associating a Google account with the app should be optional, not mandatory, even for Google I|O.
That being said, you needed a Google account to attend Google I|O in the first place. Hence, while forcing you to supply an account to iosched is regrettable, it is at least somewhat understandable… for Google I|O.
It is not understandable for conferences run by other groups.
And, for the vast majority of Android applications, forcing the user to supply unrelated account credentials to use the app would be an exceptionally bad idea.
Note the use of the word “unrelated”. It makes perfect sense for the Evernote app to require an Evernote account. It makes perfect sense for the Remember the Milk app to require a Remember the Milk account. In those cases, the apps are dedicated mobile front-ends to what, at its core, is a Web app. And, the accounts in question are highly relevant to the apps.
You are welcome to prompt the user to supply an unrelated account on first run of your app. But please provide a “Skip” option, with the ability to supply (or replace) the account information later on from elsewhere in the app, such as from a PreferenceActivity. If the user elects not to provide the account, simply hide or disable UI options that require the account (e.g., drop the +1 button if they do not provide a Google account), or perhaps just lead the user back to the “provide the account” screen at that point before continuing.
More importantly, when repurposing somebody else’s code, do not just blindly adopt it en masse. Instead, think about the app’s behavior, decide whether or not that behavior is appropriate for your user base, and change things as needed.
October 20, 2012
4.1.2, Locations, Google Apps, and a UX WTF? Moment
If your device (e.g., Galaxy Nexus) got the 4.1.2 upgrade, and you try using Maps, you may encounter problems using GPS. You may get a Toast with “Please enable Google apps location access”.
The solution for you, as a user, is to go into Settings > Accounts > Google > Location settings, and in there slide the “Let Google apps access your location” Switch to ON. That should clear up your Maps problem.
From a usability standpoint, this little incident has a number of interesting lessons:
Do not ship undocumented user regressions. Maps worked fine previously; 4.1.2 broke its GPS access. The fact that the user needs to go in and adjust a setting is not a problem, except that the user does not know that this is the case. Moreover, the user did not find out about this as part of installing the 4.1.2 upgrade, but only when Maps broke. This is not say “do not ship regressions”, but do not ship undocumented ones. Whether at the OS level or at the Maps app level, the user should have been proactively notified about this change, by something less obtuse than this Toast.
Do not use Toasts for “load bearing” issues. A Toast is great for an advisory message, one that if the user misses, it is not a major problem. If the issue is something that is impeding the user’s use of the app, though, you need something more persistent. If you do not want to use a modal dialog, use a Crouton or the equivalent.
If the user needs to take an action to fix a problem, lead the user to the action. Another problem with a Toast is that the user has no way of immediately taking whatever action you may be advising, since a Toast is modeless. Instead, the user has to guess what you mean, based on the text of the Toast, which may be problematic. A dialog or Crouton offer the possibility of buttons or links or something. In this case, the notice about the required setting change could have a link to that individual screen in Settings, or at least to the Google account page. Since the Maps app already does this when GPS is disabled (to lead the user to the location settings to go enable it), I do not know why they failed to take this approach for this change.
On the whole, change is good. Obtuse change is bad. Obtuse change when the user is trying desperately to catch a flight and cannot understand how to get Maps to use GPS to get a new route past an accident is really, really bad, and may make the user cranky, causing the user to write a blog post that ends in a run-on sentence.
October 17, 2012
Conditional Preference Headers
Android 3.0 introduced the new, two-tier form of PreferenceActivity. You supply header+fragment pairs. Android shows the user the list of headers, and upon clicking on a header, Android shows the fragment. However, on phone-sized devices, it will do those one a time: the list of fragments fills the screen, and then the chosen fragment fills the screen. On larger devices, PreferenceActivity shows them both side by side. This is a classic rendition of the master-detail pattern.
However, it does tend to steer developers in the direction of displaying headers all of the time. For many apps, that is rather pointless, because there are too few preferences to collect to warrant having more than one header.
One alternative approach is to use the headers on larger devices, but skip them on smaller devices. That way, the user does not have to tap past a single-item ListFragment just to get to the actual preferences to adjust.
This is a wee bit tricky to implement.
The basic plan is to have smarts in onBuildHeaders() to handle this. onBuildHeaders() is the callback that Android invokes on our PreferenceActivity to let us define the headers to use in the master-detail pattern. If we want to have headers, we would supply them here; if we want to skip the headers, we would instead fall back to the classic (and, admittedly, deprecated) addPreferencesFromResource() method to load up some preference XML.
There is an isMultiPane() method on PreferenceActivity, starting with API Level 11, that will tell you if the activity will render with two fragments (master+detail) or not. In principle, this would be ideal to use. Unfortunately, it does not seem to be designed to be called from onBuildHeaders(). Similarly, addPreferencesFromResource() does not seem to be callable from onBuildHeaders(). Both are due to timing: onBuildHeaders() is called in the middle of the PreferenceActivity onCreate() processing.
So, we have to do some fancy footwork.
By examining the source code to PreferenceActivity, you will see that the logic that drives the single-pane vs. dual-pane UI decision boils down to:
onIsHidingHeaders() || !onIsMultiPane()
If that expression returns true, we are in single-pane mode; otherwise, we are in dual-pane mode. onIsHidingHeaders() will normally return false, while onIsMultiPane() will return either true or false based upon screen size. Specifically, onIsMultiPane() looks at an internal boolean resource (com.android.internal.R.bool.preferences_prefer_dual_pane), which has different definitions based upon screen size. At present, it will be true for -sw720dp devices, false otherwise.
So, we can leverage this information in a PreferenceActivity to conditionally load our headers:
public class EditPreferences extends SherlockPreferenceActivity {
private boolean needResource=false;
@SuppressWarnings("deprecation")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (needResource
|| Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
addPreferencesFromResource(R.xml.preferences);
}
}
@Override
public void onBuildHeaders(List<Header> target) {
if (onIsHidingHeaders() || !onIsMultiPane()) {
needResource=true;
}
else {
loadHeadersFromResource(R.xml.preference_headers, target);
}
}
}
Here, if we are in dual-pane mode, onBuildHeaders() populates the headers as normal. If, though, we are in single-pane mode, we skip that step and make note that we need to do some more work in onCreate().
Then, in onCreate(), if we did not load our headers, or if we are on API Level 10 or below, we use the classic addPreferencesFromResource() method.
The net result is that on Android 3.0+ tablets, we get the dual-pane, master-detail look with our one header, but on smaller devices (regardless of version), we roll straight to the preferences themselves.


