1

I have recently been looking at handling API levels fragmentation and found a great tutorial on supporting different API Levels in your source code:

As stated in the tutorial, in order to avoid run-time error of using newer classes/methods than the API Level ones should check the API level and use lazy loading.

I have checked the code and can confirm that on Android <2.0 you must use lazy loading to avoid VerifyError. What was a huge surprise for me was that in 2.1 the lazy loading is not necessary anymore.

I will use the Camera.setDisplayOrientation method to demonstrate the issue. The method was introduced in Froyo 2.2.

import android.hardware.Camera;
...
public class CameraActivity extends Activity implements SurfaceHolder.Callback{
   Camera mCamera;

   ...

   public void surfaceChanged(SurfaceHolder holder, int format, int w, int h){
      final int APIversion = Integer.parseInt(Build.VERSION.SDK);
      if (APIversion >= Build.VERSION_CODES.FROYO){
         camera.setDisplayOrientation(90);
      }
      ...
   }
}

The code is compiled using the Froyo Compiler (API 8)

As suspected if I run the APK on a Android version <2.0 I will receive an VerifyError exception when starting the CameraActivity.

But what amazes me is that when I run the same APK on Eclair 2.1 the application is loaded without any problem. And I have double checked the Camera interface, and found that the setDisplayOrientation method was only introduced in Froyo 2.2.

On the contrary if I try to call the method I will get an exception, i.e.

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h){    
    final int APIversion = Integer.parseInt(Build.VERSION.SDK);
    camera.setDisplayOrientation(90);
}

On Eclair this will throw NoSuchMethodError.

Why does it work? Does it have anything to do with class verification being turned off?

PS: I have checked that the setDisplayOrientation indeed doesn't exist in Eclair 2.1. I did it by trying to remove the Build Version SDK check before calling the method. If I just call the method I will receive NoSuchMethod exception. But if the IF is there I don't get the VerifyError!

Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
hnviet
  • 1,747
  • 1
  • 18
  • 22

1 Answers1

3

Starting with Android 2.0 the Dalvik verifier is smarter about only checking classes that are actually used while running.

That said, the code you show here would only work if you never touch the CameraActivity class when running on older versions of the platform. Given that isn't what you are showing, an explanation may be that on some older builds of the platform that API was there but not yet available in the SDK.

hackbod
  • 90,665
  • 16
  • 140
  • 154
  • Thanks for quick response. The concern I have here is that the CameraActivity can actually start and runs well on Eclair 2.1. On Donut(1.6) or Cupcake(1.5) the CameraActivity would crash at the beginning with VerifyError issue. – hnviet Sep 01 '11 at 02:18
  • As I said, there could be an early version of this method on some older devices. In general if you have a class that is using APIs of a newer version of the platform, you need to make sure that you never cause any code of that class to be executed on older versions of the platform (which will cause the class to be initialized and at that point result in an exception). – hackbod Sep 01 '11 at 02:53
  • Yes, I do understand the issue of handling the library/API unavailability on older platforms. My concern here is not why it doesn't work on version prior to 2.0, because it is exactly how it should be. My question is why it WORKS on 2.1 when it SHOULDN'T. I have been researching this issue but couldn't find the answer. – hnviet Sep 02 '11 at 00:33
  • 1
    As I said, it is possible that the method happens to exist (hidden) on the build of the platform you are running it on. – hackbod Sep 02 '11 at 02:32
  • OK, I got it. Do you know how can I check it? Thanks a lot anyway – hnviet Sep 02 '11 at 06:52
  • You could try doing this with a different API. Also you could try using reflection to see if you can find that method. – hackbod Sep 02 '11 at 21:43
  • Hi. I was trying again and I can confirm that the method doesn't exist. If I call it directly from the code I will get a No Such Method exception - so the method is not there. But as I said earlier I don't get the VerifyError if I protect the method call in a IF condition. I have changed the question to reflect that. So still don't get it ...:/ – hnviet Sep 03 '11 at 12:08
  • @hnviet: I think I am asking a similar thing here :http://stackoverflow.com/questions/20271593/is-checking-sdk-int-enough-or-is-lazy-loading-needed-for-using-newer-android-api – Mr_and_Mrs_D Nov 28 '13 at 17:41