One benefit of using separate projects is that I can write a second version of the application that runs on a website instead of on a handheld without having to rewrite the bulk of the code.
But there's a catch: when the Android-specific unit tests are moved into a separate Eclipse project, the loader reports "Class resolved by unexpected DEX error" and the unit tests fail with "java.lang.IllegalAccessError: cross-loader access from pre-verified class". (In 2.1 the error remains, but the message has changed to "Class ref in pre-verified class resolved to unexpected implementation".)
I first ran into this problem in 1.5 Android, and upgraded to 1.6 hoping it would go away, because in 1.6 using separate Eclipse projects for unit tests is recommended:
There is even a toolbar icon and wizard to create an Android test project that points to a separate Android project to be tested.
Googling around, I found other programmers having the same or similar problems:
But googling also found programmers with multiple projects but not the problem:
What makes some programmers have no problem using multiple Eclipse projects to separate Android application code from Android unit-test code, while other programmers get the loader errors?
The problem shows up when the loader sees the same class loaded more than once:
which can happen if the main Android code and the Android unit tests share code from another Eclipse project:
which is the setup I have.
To reproduce the problem:
- Create an ordinary Java project called LoaderProblemCommon, and create this class in it:
- Create an Android project called LoaderProblem, add the LoaderProblemCommon project to its build path, and create this class in it:
- Add LoaderProblem to the Android manifest.
- Create an ordinary Java project called LoaderProblemTestUtils, and create this class in it:
- Create an Android test project called LoaderProblemTests, add the other three projects to its build path, and create this class in it:
public class LoaderLogger
public static void log(String message)
public class Hello extends Activity
public void onCreate(Bundle savedInstanceState)
public static void logHello()
public class TestUtil
public static final void doNothing()
public class LogHelloTest extends AndroidTestCase
public void testLogHello()
Compile all four projects, create a brand-new AVD, and run LoaderProblem as an Android application. It should deploy and display:
Now try to run LoaderProblemTests as an Android JUnit test. It will fail with:
Or, for 2.1, it will fail with:
I first tried to fix this problem by editing the build path for LoaderProblemTests so it only depends on the LoaderProblemTestUtils Eclipse project, and then adding back the necessary classes by adding dependencies on the other projects' class folders:
This "worked", but it introduced several unwanted side effects:
- Now that the dependent project's source is seen as a class folder, one can no longer smoothly refactor across projects or navigate into classes (via F3, for instance), because these files are now treated as a compiled objects. Attaching the source to the classfolder library sort of works, but then it brings up an uneditable version of the source. [reported by a reader]
- It screws up EclEmma. For details see https://sourceforge.net/tracker/?func=detail&atid=883351&aid=2934081&group_id=177969.
- In the build path for LoaderProblem, click on "Order and Export".
- Check the box for LoaderCommon, to let LoaderProblem export the LoaderCommon classes as well as its own.
- In the build path for LoaderProblemTests, remove the dependency on the LoaderCommon project. The dependency is already now covered by the LoaderProblem dependency.
- Clean, build, rerun LoaderProblem, then rerun LoaderProblemTests.