Android has long labored under the shadow of a “fragmentation problem” that makes it tough to write apps that work reliably across the many devices and platform versions. I’ve written before that this problem is overblown, yet it’s not without merit.
Google has done a lot to address the fragmentation problem, including creating support libraries that make new features available on older devices. These libraries have been a huge help to developers like myself.
But I’ve noticed my fellow devs getting less enthusiastic with each support library release. Sure, we look forward to the new features and bug fixes – but we’ve learned that with each release comes a new set of problems, some of which are specific to certain versions of Android. We’ll spend time codingworkarounds for these problems, then have to revisit them the next time a support library is updated.
This situation is starting to resemble the fragmentation problem the support libraries were designed to address. Instead of writing code to deal with problems in specific Android versions, we’re writing code to deal with issues in specific support library versions.
In 2006 I wrote about how the fear of installing desktop software accelerated the move to the web. Security warnings, firewall alerts and antivirus popups made installing software feel like an incredibly risky thing to do.
We’re seeing a similar situation with mobile apps now. The seemingly simple act of installing an app requires you to first approve a scary list of permissions, and while some may approve them the same way they dismiss a EULA, others find them daunting. Add to that the spammy notifications and addiction-feeding of popular games plus the privacy violations of popular social apps, and it feels like I’m watching a rerun from eight years ago.
If this trend continues, the whole debate about mobile apps vs. web apps will be pointless: users will feel safer with web apps so that’s what they’ll choose, and developers will follow.
A recent addition I made to the Reader in WordPress for Android is the ability to swipe through articles, which is a pretty standard thing on Android thanks to the ViewPager.
But after using it a while, I decided I wasn’t happy with the default swipe animation, so I created a custom PageTransformer to provide a different one.
I then added the ability to swipe through photos in an article, and again I wasn’t happy with the default animation. Rather than create another PageTransformer, I changed the one I’d already coded so it could provide a number of different animations.
/*
* ViewPager transformation animation invoked when a visible/attached page is scrolled – before
* changing this, first see https://code.google.com/p/android/issues/detail?id=58918#c5
* tl;dr make sure to remove X translation when a page is no longer fully visible
*
* Usage: viewPager.setPageTransformer(false, new ReaderViewPagerTransformer(TransformType.FLOW));
*/
class ReaderViewPagerTransformer implements ViewPager.PageTransformer {
static enum TransformType {
FLOW,
DEPTH,
ZOOM,
SLIDE_OVER
}
private final TransformType mTransformType;
Shortly after I published this celebratory post about dropping Gingerbread support in WordPress for Android, I found myself writing animation code that had to special case itself to work on pre-JellyBean devices.
I was working on Glassboard when I wrote that post, and Glassboard hadn’t become a Google Play “staff pick” yet so it still had a fairly small audience. These days I work on WordPress for Android which has a much larger audience, so I figured I’d revisit the fragmentation topic.
I’ve seen a lot more fragmentation-related problems since working on WordPress, but I still maintain that fragmentation is less of an issue than is commonly believed.
That’s not to say, of course, that it isn’t a problem at all.
I think the biggest problem is that unless your app is relatively new, you probably have to continue supporting Android 2.3. Making sure your app works on that ugly, buggy OS is a massive pain. Every Android developer I know will dance in the streets the day they can drop support for pre-ICS versions of Android.
Another problem is the number of inexpensive, low-powered Android devices in use – especially outside the US. If you want your apps to run well on them, you have to be extra-cautious about memory consumption and performance (but then, you should be anyway).
Overall, though, I haven’t found the number of devices to be as big an issue as the number of OS versions. Here’s a breakdown of the different Android versions our customers are running:
This isn’t as big a deal as you might think, but it’s not unusual to find your app works flawlessly on the latest version of Android yet breaks on a previous version due to a bug fixed between releases. The Android Issue Tracker is a big help in these situations.
The only other oft-recurring problem I’ve encountered is differences between phone and tablet versions of your app, but these are usually self-inflicted (often caused by having too many screen-specific layouts and not synching changes between them).
I’m sure these issues look horrific to iOS developers, who are blessed by only needing to support a few devices and OS versions. But they’re certainly not as horrific as the press often makes fragmentation sound, and they’re far easier to deal with than all the fragmentation problems I encountered back when I developed for Windows.
I often run across Android layouts which use hard-coded margins, padding, and font sizes, like this:
Doing this often leads to inconsistency. Different layouts end up hard-coding different font sizes and margins, making the app appear less polished.
To avoid this, I recommend defining the sizes in values.xml like this:
And then referring to these sizes in your layouts like this:
If every layout uses only the sizes defined in values.xml, then not only will your app appear more consistent but it will also make it much easier to adjust sizes application-wide.
Making a ListView scroll smoothly is a bit of a black art for Android developers, but there are a few simple rules:
Use the View Holder pattern
Do as little work as possible in getView()
Reduce unnecessary overdraw
Flatten the view hierarchy
The View Holder pattern is well known, but that second rule often gets ignored despite having the biggest impact.
Because getView() is called every time a cell is drawn, any extra work done there will slow things down. Things like formatting dates, manipulating bitmaps, querying SQLite, or loading image resources should be moved out of getView() and instead computed and cached prior to the list being populated.
Unnecessary overdraw can be caused when one view covers another one. If both views have a background, both backgrounds will be drawn even if the first is completely covered. The simplest way to find overdraw issues is to enable “Show GPU Overdraw” in the device’s developer options. If you see dark red blocks behind your ListView text after enabling that option, it’s time to work on overdraw. Simply getting rid of unnecessary background colors/drawables can make a huge difference. If you have an activity whose background is completely covered by another view, you may be able to get rid of one layer of overdraw by calling getWindow().setBackgroundDrawable(null) after setContentView() in the activity’s creation.
Flattening the view hierarchy in your layouts not only helps reduces overdraw but also means less work has to be done when the layout is inflated and drawn. When I create an XML layout, I’ll often use a ton of parent views (RelativeLayouts, LinearLayouts, etc.), to make it easier to group things and move them around. But once I’m happy with the layout, I try to remove as many of those parent views as possible.
A huge pet peeve of mine is mobile apps which make you to wait after you do something that requires a server API call. For example, you tap a “Like” button and are forced to look at a modal “Liking…” dialog that doesn’t go away until the app knows the like has been received by the backend.
Apps which do this are unnecessarily pessimistic about connectivity. Why make the user wait when the most likely outcome will be that the API call succeeds? I think it’s better for the app to show the new “Like” state immediately, and then deal with the rare failure in the background.
This optimistic approach is one that the folks at Instagram have touted, and I’ve followed it in all of my mobile apps.
Sometimes, though, you really do want to make the user wait, at least a little bit. In these cases, it’s often better to resort to sleight of hand which distracts the user instead of blocks them the way a modal dialog does.
I’ve found animation to be the most effective form of this trickery.
Suppose it really is important to make the user wait a couple of seconds after clicking a “Like” button to give the API call a little time. In this situation, animate the “like” button for a second or two – have it bounce, or spin, or zoom in and out.
Users will wait for the animation to end before doing something else in the app, and by the time the animation is done there’s a good chance the API call has completed. The user still waited, but because they waited by choice it doesn’t feel the same as being so obviously blocked by an annoying modal dialog.
PS: I should add that I only recommend this approach when making very lightweight requests. For heavier requests (especially ones that upload large amounts of data), a background service is a far better choice.
If you’ve been reading this blog for a while, you probably know I’m a fan of Android.
It wasn’t always that way. I was an early iPhone adopter who reluctantly switched to Android after getting a job as an Android developer.
That was in the Android 2.x days, when Android was still crap. Back then I felt so limited using Android instead of iOS, but Android 4.x reversed that. These days I can’t use an iPhone without feeling limited.
But you know what? Both iPhone and Android are amazing. You’ll get a great experience regardless of which one you choose.
Yet every article I read that mentions either Android or iPhone ends up getting a slew of comments from angry mobile fanboys. As far as these dweebs are concerned, there’s a religious battle being fought for mobile supremacy and only one mobile OS can survive.
We saw the same silliness with the “native vs. web” battle, where geeks took sides as though only one side could win. Now, of course, we see that both have won.
So it is with mobile. Both iPhone and Android have won.
If you’re one of those people who reads an article about iPhone or Android and feels compelled to comment about how one of them sucks, please do everyone – including yourself – a favor and don’t do it. The rest of the world wants you to stop filling tech blogs with your overzealous comments. You may think you’re fighting the good fight, but the reality is most of us look at you the same way we would if we heard you arguing about the best Star Trek captain.
Earlier this week I announced a new version of Glassboard for Android which supports Glassboard premium. What I didn’t mention is that this new version is also optimized for tablets like the Nexus 7.
If you used an earlier version of Glassboard on your new tablet, chances are you were disappointed by how photos didn’t resize to fill the larger display. And if your eyes are like mine, you probably squinted to read anything. You may also have noticed that scrolling wasn’t as smooth as it should be.
The latest version changes all that. Photos are now big and bold, text is much more readable, and scrolling is buttery smooth.
If you’re one of the many folks who bought a Nexus 7 and are annoyed by how few apps take advantage of it, give the latest version of Glassboard a try. It’s a much better experience than before.