开发者

How to support multiple android version in your code?

Take accessing contacts 开发者_开发问答in android android.jar for versions 1.6 has People.CONTENT_URI for invoking contacts related info whereas in later versions we need to have api support for RawContacts.CONTENT_URI.

Same thing is true for accessing calendar for instance as its URI is changed in android 2.2.

Is there a best practice to manage all different changes without adding additional application or build separately for each version of changes?


For my money, a very good answer is at http://android-developers.blogspot.co.uk/2010/07/how-to-have-your-cupcake-and-eat-it-too.html. However, the example there is a little more complicated than need be, so based on that, here is an example of how to cope with it when building notifications. The underlying reason this works is a consequence of how java engines interpret classes: it only looks at them when needed, so if you wrap version specific code up in a class and only create it when you know you are using that version, it all works ...

There are, as far as I can tell, two generations of approaches to creating notification, and a naming change along the way in the second. So that gives three ways to do it. For each way, create a class with the notification generation in it:

The first approach (used through to Gingerbread):

public class MyNotificationBuilderToGingerBread {
Notification notification = null;

MyNotificationBuilderToGingerBread(Context myContext, int icon, String ticker, String title, String info, Long timeStamp, PendingIntent pendingIntent, int flags) {
    notification = new Notification(R.drawable.ic_sb, ticker, timeStamp);
    notification.setLatestEventInfo(myContext, title, info, pendingIntent);
    notification.flags |= flags;        
}

Notification get() {
    return notification;
}
}

The second approach, Honeycomb to IceCreamSandwich:

public class MyNotificationBuilderHoneyCombToIceCreamSandwich {
Notification.Builder mb = null;

MyNotificationBuilderHoneyCombToIceCreamSandwich(Context myContext, int icon, String ticker, String title, String info, Long timeStamp, PendingIntent pendingIntent, boolean onGoing) {
    mb = new Notification.Builder(myContext);
    mb.setSmallIcon(icon);
    mb.setContentIntent(pendingIntent);
    mb.setContentTitle(title);
    mb.setContentText(info);
    mb.setWhen(timeStamp);
    if (ticker != null) mb.setTicker(ticker);       
    mb.setOngoing(onGoing);
}

Notification get() {
    return mb.getNotification();
}   
}

The second generation, with the name change, Jellybean (onwards, so far ...):

public class MyNotificationBuilderJellyBean {

Notification.Builder mb = null;

MyNotificationBuilderJellyBean(Context myContext, int icon, String ticker, String title, String info, Long timeStamp, PendingIntent pendingIntent, boolean onGoing) {
    mb = new Notification.Builder(myContext);
    mb.setSmallIcon(icon);
    mb.setContentIntent(pendingIntent);
    mb.setContentTitle(title);
    mb.setContentText(info);
    mb.setWhen(timeStamp);
    if (ticker != null) mb.setTicker(ticker);       
    mb.setOngoing(onGoing);
}

Notification get() {
    return mb.build();
}   
}

Then, you just need to pick which class to instantiate on the fly:

// System information
private final int sdkVersion = Build.VERSION.SDK_INT;
// If you want to go really old:
    // (actually, there is a question about how this issue should be handled
    // systematically. Suggestions welcome.)
// final int sdkVersion = Integer.parseInt(Build.VERSION.SDK);

    // This is for a permanent notification. Change the final argument (flags or boolean) if it isn't meant ot be
    // For meaning of other variable, see notification documentation on the android website.
    if (sdkVersion < Build.VERSION_CODES.HONEYCOMB) {
        MyNotificationBuilderToGingerBread mnb = new MyNotificationBuilderToGingerBread(myContext, R.drawable.notification_icon, ticketText, title, infoText, timeStampMillis, pendingIntentForTapOnFullNotitifcation, Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR);
        notification = mnb.get();
    }
    else if (sdkVersion < Build.VERSION_CODES.JELLY_BEAN) {
        MyNotificationBuilderHoneyCombToIceCreamSandwich mnb = new MyNotificationBuilderHoneyCombToIceCreamSandwich(myContext, R.drawable.notification_icon, ticketText, title, infoText, timeStampMillis, pendingIntentForTapOnFullNotitifcation, true);
        notification = mnb.get();
    }
    else {
        MyNotificationBuilderJellyBean mnb = new MyNotificationBuilderJellyBean(myContext, R.drawable.notification_icon, ticketText, title, infoText, timeStampMillis, pendingIntentForTapOnFullNotitifcation, true);
        notification = mnb.get();
    }

    // Send the notification.
    notificationManager.notify(idForNotificationManager, notification);

Hope this helps!


There are many resources for you to utilize to help support multiple versions of android.

  1. Read this blog post here and then read this one here, they will help you address API level version support issues.
  2. Read this blog post on multiple screen support, especially how the asset hierarchy in parsed in res folder. This will help you understand and design how to do asset folder structure to support different screen size/densities and android versions.
  3. Lastly write your own custom ant build scripts so that you can compile with all versions of android.


Quite Honestly, it's a pain.

I usually, just isolate parts of code that are different and access them using abstract classes. So technically creating different version for different OS.

But there are other ways. The best one i've seen involves using reflection.


  • If you don't really need the new functionnalities, and really have to support old Android versions, drop it. Build your app for the oldest version, and don't bother with this kind of thing.
  • In the other case, you can detect the version using Build, and use reflection to load the classes you need. An example of that can be found in the source code of the K9Mail app


There's a nice article on android.com about it: http://developer.android.com/resources/articles/backward-compatibility.html

Personally I would suggest the wrapper class or wrapper library solution. But in small cases the reflection should be fine (and in case performance is not a problem for you).

If you need more info, ask in comments.


This is a great article for when you have to do reflection in Android (to support multiple API levels).

And when you have to have different resources for different API Levels, this is the reference to use (see the section on "Platform Version (API level)").


If on Eclipse, from ADT version 17 you can specify code to run with some version simply as described in Lint API Check. The code word is @TargetAPI(XX)

Hope it helps


Best practice (though not for Android, but for J2ME) to my knowledge is to use preprocessing C/C++ styled statements, like:

//#if S40
    ...
//#else
    ...
//#endif

Some IDE's support these kind of preprocessing, e.g. Netbeans. To my knowledge Eclipse has some plugins to enable preprocessing also. I don't really know are they applicable to Android development. Try to google yourself.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜