LinkageError and Your Android Code

I received a couple of reports of a java.lang.LinkageError when using my older CWAC-Camera library on apps with a compileSdkVersion set to 23. My resulting investigation points out an interesting problem in Android development, particularly for those of us publishing libraries.

What happened was that API Level 23 added a getHost() method to Fragment. That’s all fine and well, but my library ships a subclass of Fragment (CameraFragment), and I had my own getHost() implementation, dating back a year or two. Mine returns a CameraHost, while the framework’s one returns an Object. They also have distinctly different roles.

If you open up the class (CameraFragment) in Android Studio, you now get a Lint message, indicating that “This method is not overriding anything with the current build target, but will in API level 23”. That’s useful, but it does not help with existing compiled code.

If your compileSdkVersion is 21 or higher, and you have an incompatible override like this, you will get the LinkageError. My guess is that this is somehow related to ART, as I cannot understand why API Level 21 would otherwise be a magic API level here (the source history shows that getHost() was definitely added in Android 6.0). As it turns out, if you leave your compileSdkVersion at something lower (e.g., 19), not only do you compile cleanly, but you appear to run OK, so long as the accidental override is not being used by the framework (I guess).

In my case, the problem is compounded by two things:

  1. The method (getHost()) is part of the library’s public API, meaning that fixing this “for realz” requires a breaking API change

  2. This is a library that I have replaced due to a poor job implementing the original library

The moral of this story: when a new API level comes out, and you publish a library, double-check your existing code to see whether or not you get these Lint messages… even for code that otherwise should be unaffected by the API level. This is especially true where you are subclassing Activity, Fragment, or other BFCs (Big Frakkin’ Classes), where Google is likely to add new methods that might collide with ones in your subclasses.