24 May 2012 Easing the Pain of Android Software Fragmentation
Software fragmentation is a common concern for Android developers. Right now, supporting all versions down to Android 2.2 (Froyo) will make your application available to 93.5% of Google Play users. However, doing so also means you miss out on APIs that were released in the last 2 years.
In this post I’ll talk about this problem in detail, and highlight a few libraries available that help you develop an Android 2.2 application without limiting yourself to old APIs.
The Problem
Google releases a major update to the Android OS approximately every year. These updates contain new user features, as well as new APIs to make developer’s jobs easier and more fun-filled.
Generally these updates first go out to Google-branded phones (known as the Nexus series) within a month or so. However, other manufacturers may be another 6 months behind, or never even bother with the update.
There are a range of reasons for this. Some manufacturers have their own version of the home screen/launcher that they need to modify to work with the update (and make new features available). Each version would also presumably have to go through the manufacturers own QA departments.
Here’s a breakdown of some statistics I found, showing the percentage of total users on each Android version:
Platform | Codename | API Level | Distribution |
---|---|---|---|
Android 1.5 | Cupcake | 3 | 0.3% |
Android 1.6 | Donut | 4 | 0.7% |
Android 2.1 | Eclair | 7 | 5.5% |
Android 2.2 | Froyo | 8 | 20.9% |
Android 2.3 – Android 2.3.2 | Gingerbread | 9 | 0.5% |
Android 2.3.3 – Android 2.3.7 | 10 | 63.9% | |
Android 3.0 | Honeycomb | 11 | 0.1% |
Android 3.1 | 12 | 1.0% | |
Android 3.2 | 13 | 2.2% | |
Android 4.0 – Android 4.0.2 | Ice Cream Sandwich | 14 | 0.5% |
Android 4.0.3 – Android 4.0.4 | 15 | 4.4% |
You can see that most phones are at 2.3.3+, which was released at the beginning of 2011.
There is also still a noteworthy percentage running 2.2, which at this point is around 2 years old.
The way I read this is that to target the majority of Android users you should still aim for supporting 2.2 and above. However, if you code only towards 2.2 without thinking about future API’s, you miss out on a bunch of features. Specifically:
Loaders
Loaders are an easy way to load data for an Activity or Fragment that survives configuration changes, and updates for data changes. They’re best thought of as a framework-managed AsyncTask, with some extra niceties.
Fragments
Fragments are a reusable behaviour or UI component. You can build an activity (or screen) out of multiple visible fragments that handle their own lifecycle and interact with each other. This is gives you a way to support phones and tablets in a single application package.
The image below is an example of how you would use fragments to support different devices without wasting screen real estate. We see that the tablet displays both the list and the selected items content, while a small screen such as a phone shows the list which clicks into the content.
The Action Bar
The Action Bar is a way to provide consistent branding and navigation across all screens of your application. Here’s an example of one in action:
Think of the Action Bar as a suped-up title bar that can contain a logo, buttons, tabs, spinners, and custom views. Most applications are adopting Action Bars, and the Android Design Guidelines intend on them becoming one of the primary ways to navigate your application.
In short, without things like Action Bars, Fragments and Loaders, it becomes nearly impossible to fit in with the design guidelines at all.
Possible Solutions
Fortunately, there are a few ways to support multiple Android versions, while still using new APIs on supporting devices (with varying levels of ickyness):
- Use Reflection to either detect what’s available at runtime and then conditionally call newer APIs, or to lazy-load classes calling out to the APIs
- Release Multiple APKs for your application (market supported) for different Android versions
- Use compatibility libraries that support subsets of the newer APIs
Compatibility Libraries
Both Google and third-parties provide compatibility libraries for making some of the new Android APIs available to older devices. I’m going to focus on the Google Support Package and ActionBarSherlock, as they both support most of the major API additions moving from 2.2 to 4.x.
Support Package
The Google Support Package, currently at revision 8, is a Google-supported library that makes important API changes such as Fragments and Loaders available to older devices (Android 1.6 and above).
You can download it via the Android SDK Manager, or if you’re using the ADT Plugin in Eclipse, you can add it to your project with a couple of clicks.
ActionBarSherlock
ActionBarSherlock is a library that adds support for the Ice Cream Sandwich (ICS, Android 4.0) Action Bar to Android versions 2.x and above. It’s basically a backport of the Action Bar classes from the Android Open Source Project (AOSP), but will use the native classes on an Android 4.0+ phone.
You include it into your project as an Android Library Project. Full instructions are here, but basically you download their source package and refer to it in your Android project properties. This will make all of the classes and resources available to you.
Steps: Making your Android 4.0.3 project work in 2.2
I switched a toy 4.0.3 project to support 2.2 and onwards. After I had added ActionBarSherlock as a library to my project, I then had to do the following:
- Switch all Loader imports to their support package equivalents. To do this, I switched android.* package references to android.support.v4.*. For example:
// Before Support Package import android.app.LoaderManager.LoaderCallbacks; import android.content.Loader; import android.content.AsyncTaskLoader; import android.app.FragmentManager; import android.app.FragmentTransaction; // After import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.Loader; import android.support.v4.content.AsyncTaskLoader; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction;
- Switch all Fragment, Activity and FragmentActivity references to SherlockFragment, SherlockActivity and SherlockFragmentActivity references. These use the support package, but also allow for ActionBarSherlock to do it’s magic:
// Before ActionBarSherlock public class NewsListFragment extends ListFragment {} public class NewsActivity extends FragmentActivity {} // After public class NewsListFragment extends SherlockListFragment {} public class NewsActivity extends SherlockFragmentActivity {}
- Switch Action Bar layouts to their Sherlock equivalents, e.g. spinner_dropdown_item becomes sherlock_spinner_dropdown_item. It mightn’t be immediately obvious to do this, but it can cause funky UI issues if you don’t – for example, spinner items with radio buttons.
// Before ActionBarSherlock ArrayAdapter.createFromResource(this, R.array.news_navigation_list, android.R.layout.spinner_dropdown_item); // After ArrayAdapter.createFromResource(this, R.array.news_navigation_list, R.layout.sherlock_spinner_dropdown_item);
After making these changes to my toy application, it looked mostly the same on both an Android 2.2 emulator and my Android 4.0.4 phone, the main difference being the default font switch for ICS:
Things to think about
While these libraries allow you to use some of the new APIs in applications targetting older devices, you still need to keep in mind issues on earlier devices. For instance it is generally recommended that you use HTTPClient in Froyo (2.2) and below due to bugs in URLConnection, whereas URLConnection works fine in Gingerbread (2.3) and onwards.
Conclusion
The Support Package and ActionBarSherlock make a lot of the big API/UI changes from ICS available to developers targetting 2.2. Making your 4.0+ code compatible with these libraries is simple to do and guarantees forward-compatibility.
However, you may run into issues trying to hit new APIs that haven’t been made available to the Support Package. There’s even the possibility that you could come across Android bugs that were fixed after 2.2!
The degree to which software fragmentation affects you really depends on what your application is trying to do. You may need a mixture of different solutions to find your happy place. For example, you could employ the support libraries to use the ActionBar and loaders, then reflection to determine if a certain feature your application wants is available.
Software fragmentation is always going to be painful, but these libraries will stick some bandaids on and help kiss it better.
Samir
Posted at 23:33h, 09 Novemberi cant complete this example on android 2.2 can you tell me how to solve error of theme like holo.Light.Dialog ?