Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

android compatibility. I am confused when using Build.VERSION_CODES

Tags:

android

Log.d(TAG, "Build.VERSION_CODES.ICE_CREAM_SANDWICH: " + Build.VERSION_CODES.ICE_CREAM_SANDWICH);

I write code like this, I used the sdk4.0 to compile this android program, so it didn't cause compile error. When I run this program in my phone that running android 2.3.4, it run well.

Why? I am confused that version 2.3.4 (api level 10) has Build.VERSION_CODES.ICE_CREAM_SANDWICH property? And when I used sdk2.3.4 will cause compile error.

More

I test some code like these below,

private ScaleGestureDetector mScaleGestureDetector;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR_MR1) {
    mScaleGestureDetector = new ScaleGestureDetector(this, new MyOnScaleGestureListener());
}

this code will run well on android 1.6 api level 4, but

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR_MR1) {
    Log.d(TAG, "getx(0): " + event.getX(0));
}

this program run failed on android 1.6 api level 4.

They both run on android 2.3.4 well.

why? (In ScaleGestureDetector class use the event.getX(0) (since api level 5) too)

I test some code more..

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    Fragment f = new Fragment();

}

When I run it on android 1.6 emulator it throw java.lang.VerifyError, but on my phone running android 2.3.4 it throws java.lang.NoClassDefFoundError.

Why??

like image 418
HiMing Avatar asked Nov 20 '11 09:11

HiMing


1 Answers

It's not as strange as it seems. It has to do with how Java treat constant values of primitives. During compilation, the value of the constant is put in the byte code, not a reference to the actual constant.

For example:

Log.d(TAG, "Build.VERSION_CODES.ICE_CREAM_SANDWICH: " + Build.VERSION_CODES.ICE_CREAM_SANDWICH);

will actucally be translated by the compiler to:

Log.d(TAG, "Build.VERSION_CODES.ICE_CREAM_SANDWICH: " + 14);

so the reference to the actual constant (and class) is removed.

Regarding the code that doesn't run for you, it has to do with that the MotionEvent.getX(int n) method wasn't available until api level 5. Before that, multitouch wasn't supported and thus no need for any other method than getX().

It doesn't matter if you actually call the method that doesn't exist. The error is appearing while the class is being loaded and verified by the platform. You most likely get a VerifyError in the log, since it will discover that you're trying to call a non-existent method during the verification.

On the other hand, if you try to use a class that doesn't exist, you will get a ClassNotFoundException instead. Note that sometimes, a class exists in Android even if the documentation doesn't say so. Some classes existed in early versions of Android but weren't exposed until later. Some have even gone the other way.

So:

Trying to use a class that doesn't exist - ClassNotFoundException Trying to use a method that doesn't exist on a class that exists - VerifyError

(When it comes to using Fragments, they are available for earlier versions with the standalone Android Support Library)

like image 147
Albin Avatar answered Sep 21 '22 13:09

Albin