Lập trình Androi part 56 ppsx

7 210 0
Lập trình Androi part 56 ppsx

Đang tải... (xem toàn văn)

Thông tin tài liệu

CHAPTER 38: Handling Platform Changes 362 Handling API Changes The core Android team has generally done a good job of keeping APIs stable, and supporting a deprecation model when they change APIs. In Android, being deprecated does not mean it is going away—just that its continued use is discouraged. And, of course, new APIs are released with every new Android update. Changes to the APIs are well documented with each release via an API differences report. Unfortunately, the Android Market (the primary distribution channel for Android applications) allows you to upload only one APK file for each application. Hence, you need that one APK file to deal with as many Android versions as possible. Many times, your code will “just work” and not require changing. Other times, though, you will need to make adjustments, particularly if you want to support new APIs on new versions while not breaking old versions. Let’s examine some techniques for handling these cases. Detecting the Version If you just want to take different branches in your code based on version, the easiest thing to do is inspect android.os.VERSION.SDK_INT. This public static integer value will reflect the same API level as you use when creating AVDs and specifying API levels in the manifest. So, you can compare that value to, say, android.os.VERSION_CODES.DONUT to see whether you are running on Android 1.6 or newer. Wrapping the API So long as the APIs you try to use exist across all Android versions you are supporting, just branching may be sufficient. Where things get troublesome is when the APIs change, such as when there are new parameters to methods, new methods, or even new classes. You need code that will work regardless of Android version, yet lets you take advantage of new APIs where available. There is a recommended trick for dealing with this: reflection, plus a wee bit of caching. For example, back in Chapter 8, we used getTag() and setTag() to associate an arbitrary object with a View. Specifically, we used this to associate a wrapper object that would lazy-find all necessary widgets. You also learned that about the new versions of getTag() and setTag() that are indexed, taking a resource ID as a parameter. However, these new indexed methods do not exist on Android 1.5. If you want to use this new technique, you need to wait until you are willing to support only Android 1.6 and beyond, or you will need to use reflection. Specifically, on Android 1.5, you could associate an ArrayList<Object> as the tag, and have your own getTag()/setTag() pair that takes the index. This seems straightforward enough, so let’s look at APIVersions/Tagger. Our activity has a simple layout, with just a TextView: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" CHAPTER 38: Handling Platform Changes 363 android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/test" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout> The source code to our Tagger activity looks at the API version we are running, and routes our getTag() and setTag() operations to either the native indexed one (for Android 1.6 and above) or to the original nonindexed getTag() and setTag(), where we use a HashMap to track all of the individual indexed objects: package com.commonsware.android.api.tag; import android.app.Activity; import android.os.Build; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.TextView; import java.util.HashMap; import java.util.Date; public class Tagger extends Activity { private static final String LOG_KEY="Tagger"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView view=(TextView)findViewById(R.id.test); setTag(view, R.id.test, new Date()); view.setText(getTag(view, R.id.test).toString()); } public void setTag(View v, int key, Object value) { if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.DONUT) { v.setTag(key, value); } else { HashMap<Integer, Object> meta=(HashMap<Integer, Object>)v.getTag(); if (meta==null) { meta=new HashMap<Integer, Object>(); } meta.put(key, value); } } CHAPTER 38: Handling Platform Changes 364 public Object getTag(View v, int key) { Object result=null; if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.DONUT) { result=v.getTag(key); } else { HashMap<Integer, Object> meta=(HashMap<Integer, Object>)v.getTag(); if (meta==null) { meta=new HashMap<Integer, Object>(); } result=meta.get(key); } return(result); } } This looks great, and if we build it and deploy it on a Android 1.6 or greater emulator or device, it runs like a champ, showing the current time in the activity. If we build it and deploy it on an Android 1.5 emulator or device, and try to run it, it blows up with a VerifyError. VerifyError, in this case, basically means we are referring to things that do not exist in our version of Android, specifically:  We are referring to SDK_INT, which was not introduced until Android 1.6.  We are referring to the indexed versions of getTag() and setTag(). Even though we will not execute that code, the classloader still wants to resolve those methods and fails. So, we need to use some reflection. Take a look at APIVersions/Tagger2. This is the same project with the same layout, but we have a more elaborate version of the Java source: package com.commonsware.android.api.tag; import android.app.Activity; import android.os.Build; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.TextView; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Date; public class Tagger extends Activity { private static final String LOG_KEY="Tagger"; private static Method _setTag=null; private static Method _getTag=null; CHAPTER 38: Handling Platform Changes 365 static { int sdk=new Integer(Build.VERSION.SDK).intValue(); if (sdk>=4) { try { _setTag=View.class.getMethod("setTag", new Class[] {Integer.TYPE, Object.class}); _getTag=View.class.getMethod("getTag", new Class[] {Integer.TYPE}); } catch (Throwable t) { Log.e(LOG_KEY, "Could not initialize 1.6 accessors", t); } } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView view=(TextView)findViewById(R.id.test); setTag(view, R.id.test, new Date()); view.setText(getTag(view, R.id.test).toString()); } public void setTag(View v, int key, Object value) { if (_setTag!=null) { try { _setTag.invoke(v, key, value); } catch (Throwable t) { Log.e(LOG_KEY, "Could not use 1.6 setTag()", t); } } else { HashMap<Integer, Object> meta=(HashMap<Integer, Object>)v.getTag(); if (meta==null) { meta=new HashMap<Integer, Object>(); v.setTag(meta); } meta.put(key, value); } } public Object getTag(View v, int key) { Object result=null; if (_getTag!=null) { try { CHAPTER 38: Handling Platform Changes 366 result=_getTag.invoke(v, key); } catch (Throwable t) { Log.e(LOG_KEY, "Could not use 1.6 getTag()", t); } } else { HashMap<Integer, Object> meta=(HashMap<Integer, Object>)v.getTag(); if (meta==null) { meta=new HashMap<Integer, Object>(); v.setTag(meta); } result=meta.get(key); } return(result); } } First, when the class is initially loaded, the static initialization routines run. Here, we see what version of Android we are running, using the old SDK String instead of the new SDK_INT integer. If we are on Android 1.6 or newer, we use reflection to attempt to find the indexed getTag() and setTag() methods, and we cache those results. Since those methods should not change during the lifetime of our application, it is safe to cache them in static variables. Then, when it comes time to actually use getTag() or setTag(), we look to see if the cached Method objects exist or are null. If they are null, we assume we need to use the old versions of those methods. If the Method objects exist, we use them instead, to take advantage of the native indexed versions. This version of the application works fine on Android 1.5 and above. Android 1.6 and above uses the built-in indexed methods, and Android 1.5 uses our fake version of the indexed methods. There is a little extra overhead for going through the Method-based reflection, but it may be worth it in some cases, to access APIs that exist in newer versions of Android, rather than restricting ourselves to only the older APIs There are even ways to use this technique for cases where entire classes are new to newer Android versions (see http://android-developers.blogspot.com/2009/04/backward-compatibility-for- android.html). 367 367 Chapter Where Do We Go from Here? Obviously, this book does not cover everything. And while your main resource (besides the book) is the Android SDK documentation, you are likely to need more information. Searching online for “android” and a class name is a good way to turn up tutorials that reference a given Android class. However, bear in mind that tutorials written before late August 2008 are probably written for the M5 SDK and, as such, will require considerable adjustment to work properly in current SDKs. Beyond randomly hunting around for tutorials, you can use some of the resources outlined in this chapter. Questions—Sometimes with Answers The official places to get assistance with Android are the Android Google Groups. With respect to the SDK, there are three to consider:  android-beginners, a great place to ask entry-level questions  android-developers, best suited for more complicated questions or ones that delve into less-used portions of the SDK  android-discuss, designed for free-form discussion of anything Android-related, not necessarily for programming questions and answers You might also consider these resources:  The Android tutorials and programming forums over at http://anddev.org  The Open Mob for Android wiki (http://wiki.andmob.org/)  The #android IRC channel on freenode 39 CHAPTER 39: Where Do We Go from Here? 368  StackOverflow’s android and android-sdk tags  The Android board on JavaRanch Heading to the Source The source code to Android is now available. Mostly, this is for people looking to enhance, improve, or otherwise fuss with the insides of the Android operating system. But it is possible that you will find the answers you seek in that code, particularly if you want to see how some built-in Android component does its thing. The source code and related resources can be found at http://source.android.com. Here, you can do the following:  Download or browse the source code.  File bug reports against the operating system itself.  Submit patches and learn about the process for how such patches are evaluated and approved.  Join a separate set of Google Groups for Android platform development. Rather than download the multigigabyte Android source code snapshot, you may wish to use Google Code Search instead (http://www.google.com/codesearch). Just add the android:package constraint to your search query, and it will search only in Android and related projects. Getting Your News Fix Ed Burnette, a nice guy who happened to write his own Android book, is also the manager of Planet Android (http://www.planetandroid.com/), a feed aggregator for a number of Android-related blogs. Subscribing to the planet’s feed will let you monitor Android-related blog posts, though not exclusively related to programming. To try to focus more on programming-related, Android-referencing blog posts, you can search DZone for “android” and subscribe to a feed based on that search. . com.commonsware.android.api.tag; import android.app.Activity; import android.os.Build; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.TextView;. com.commonsware.android.api.tag; import android.app.Activity; import android.os.Build; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.TextView; import. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" CHAPTER 38: Handling Platform Changes 363 android:orientation="vertical" android:layout_width="fill_parent"

Ngày đăng: 01/07/2014, 21:20

Từ khóa liên quan

Mục lục

  • Prelim

  • Contents at a Glance

  • Contents

  • About the Author

  • Acknowledgments

  • Preface

  • The Big Picture

    • Challenges of Smartphone Programming

    • What Androids Are Made Of

    • Stuff at Your Disposal

    • Projects and Targets

      • Pieces and Parts

      • Creating a Project

      • Project Structure

        • Root Contents

        • The Sweat Off Your Brow

        • And Now, the Rest of the Story

        • What You Get Out of It

        • Inside the Manifest

          • In the Beginning, There Was the Root, And It Was Good

          • Permissions, Instrumentations, and Applications (Oh My!)

          • Your Application Does Something, Right?

          • Achieving the Minimum

          • Version=Control

Tài liệu cùng người dùng

Tài liệu liên quan