I am developing an Android app in Eclipse. I would like to target a wide variety of devices and SDK versions (for example, I can optionally support multi-touch). I understand the recommended approach of isolating all the new functionality to a separate class and leveraging lazy loading to only load that class at run-time if the host device actually supports the feature.
The downside of this approach is that I have to compile all of my code with the SDK of the newest feature I want to use. Which means if some new feature leaks into my "version neutral" code, the compiler can no longer catch it.
I would like the ability, within Eclipse, to compile my project against an older Android SDK to make sure my "version neutral" code is fine. I'd like to avoid moving my build system out of Eclipse, if possible. I'm okay with this old-SDK build being a bit awkward to run.
I think this boils down to doing some conditional compliation (or conditional "linking") inside Eclipse? For example, in my project when building against SDK-1.6 I'd like to leave the "MultiTouchHandler.java" source out of the build. I'm not sure if its possible to express "build types" like this in Eclipse, though.
The hacky solution seem to be just manually changing the project's SDK version, rebuilding, and looking through the errors, and ignore 'expected' errors. The overkill solution seems to be writing my own ant/maven/make build scripts.
Related Questions
This question:
Versioning and common code-bases with Eclipse
covers similar ground, but would involve moving all of the version-specific classes into separate "libraries". (And I would still have the problem of multiple build types in Eclipse, I think.)
This question:
Build multiple project configurations with eclipse implies that I should move to an external build system (like ant or maven), but that's a lot more work than just trying a build with an old SDK from time to time.
The February 2012 (v17) updates to the Lint Tool in the ADT should help address this without requiring multiple builds. When an app targets an old minimum SDK, but is compiled against the newest SDK (as is the recommended practice), the lint tool will notice if calls to the newer SDK are invoked. If you're confident the call is okay (Because you've hidden it behind a run-time SDK_INT check, or whatever), you can Quick-Fix an annotation to prevent the warning.
For example, in my code I have a call to View.setSystemUiVisibility, which was introduced in API 11, but I'm targetting API 8. Running Lint shows:
Call requires API level 11 (current min is 8): android.view.View#setSystemuiVisibility
The QuickFix suggests two kinds of fixes, either adding an annotation that suppresses the warning or adding an annotation that declares a chunk of code as working at API 11.
More details here: http://tools.android.com/recent/lintapicheck
A somewhat less clean/less performant method would be to use reflection to access the newer apis that you need, rather than trying to reference them directly with lazy loading. This should allow you to compile against a lower sdk level.
Related
I came upon this simple Library that someone wrote in java GetImageText.java for OCR in images so i tried compiling it on my Ubuntu via terminal but i get several error as shown below in this paste :
Compilation Errors
Can Someone help me with it , it is absolute necessity that i test this code , its explanation can be found here
I think the problem is that i do not have com.sun.image.code.jpeg in my system, although java is definitely installed. Although I am not sure how to import this package without using an IDE.
The problem is that the library you are trying to recompile depends on INTERNAL classes1. Portable libraries are not supposed to do that!
What has happened is that the class has been removed or replaced. This happens from time to time, and that is the reason that people are not supposed to write code that depends on INTERNAL classes.
Solutions:
Bug the authors of the library to fix the problem.
Figure out which version(s) of Java that the library supports, and stick with those.
Find an alternative library that supports the version(s) of Java that you need.
Non-solution: Compiling the library on an older version of Java and running on a newer one is likely to fail. The class needs to be present at runtime, as well as at compile time.
1 - Anything in the "com.sun" tree counts as INTERNAL. Sometimes people have no choice but to have such a dependency. However, they still needs to deal with the potential consequences for portability.
What is the best way to migrate Java code of an older jdk (1.5) to a more recent Java version (1.8) to provide from its new features and improvements.
We have a large Java jdk 5 code base and want to migrate to jdk 8.
There are a lot of compiler warnings and hints (e.g. diamond operator, multicatch, unnecessary (un)boxing, etc) which will improve the performance, code readability, etc.
We are using Netbeans IDE. Are there any plugins which we can use or are there migration scripts?
The likelihood of your code being incompatible with Java 8 is slim, since Java has taken great strides to ensure backwards compatibility with all previous versions.
The issues that you'll likely run into lie much deeper, likely in implementations of collections or methods who have changed over the years.
If you don't have a test suite that covers the critical paths of your code, start there. You'll need that test suite to ensure that the migration hasn't horribly broken anything.
Next, peruse the compatibility guides for Java 1.7 and Java 1.8 and be sure that nothing that you're using in particular is impacted by those changes.
Lastly, the code cleanup piece can be tackled, but it shouldn't be addressed right now. The only thing you need to concern yourself with is to get the platform running on the new version of Java. As you work in the code base, discipline yourself and the team to use the newer Java idioms, such as the diamond notation, and try-with-resources where applicable.
Unfortunately, there are no magical ways to achieve what you are asking, but here are a few pointers that can make it easier for you to migrate the code to JDK 1.7 (note that JDK 1.8 has been out for some time now, and 1.7 is already out of support officially by Oracle):
Use checkstyle or a similar plugin in Eclipse to find the problems
Build your project with JDK compiler level 1.7 in Eclipse; warnings given by Eclipse are much more user friendly than the warnings printed on console by command line compiler
In theory, JDK 1.7 is backwards compatible with 1.5. The only exceptions are assert and enum keywords. If you used these words as user defined type/method names, you'll get a compilation error. So for most part, you can get right down to warnings. If push comes to shove, you can choose to ignore many of these warnings (of course, only if you must)
Found what I was looking for: Netbeans offers Inspect and Transform.
This can be used to transform your complete code base (or parts of it) with a configuration of changes.
This is how it works:
select your project
click Refactor menu
click Inspect and Transform menu item
select configuration and configure it using the Manage button
choose your desired transformations (e.g. Can Use Diamond, Join catch sections using multicatch, unnecessary boxing, etc.)
click Inspect
Review proposed refactoring suggestions and click Do Refactoring
Your complete code base is refactored and uses your selected new features and new idioms.
IntelliJ IDEA has a similar feature. See Analyze > Inspect Code ...
In Eclipse this is called clean up in code style (configuration) or source (menu).
What is the best way to handle situation, when a Java desktop application (executable JAR) requires specific (or newer) version/update of Java, to not get some NoClassDef exceptions?
Details: I have JavaFX 8 desktop application, build with Maven and com.zenjava.javafx-maven-plugin to executable JAR. I'm using new features of JDK 8u40. I would like to nicely handle situation, when someone is trying to run it with older Java version.
First, most low-end approach is to check
System.getProperty("java.version");
at the start of main function, parse it with a couple of "ifs" to extract is it major >= 8 and update >= 40, if not show some popup instead of app. But it seems to me like mediocre solution.
I wonder are there better ways? I'd love to know more about direct code solutions, external libs, additional jar launchers or Maven options for this purpose.
Edit: additional info - I would like to avoid platform-specific solutions
The solution which mostly works: just create a native bunde with included JRE. This is the default when calling mvn jfx:native, so you shouldn't worry about the class being there, because you bundled that specific version.
That is the main reason why some are using that option. Just imagine the situation you are require Java 8 but the user just uses Java 7 and so on, it makes the bundle bigger, indeed, but it preserves you from such problems.
Disclaimer: I'm the maintainer of the javafx-maven-plugin, there are example-projects ;) but no cookies yet.
I am trying to use preprocessor like #ifdef in my Android project in Eclipse. I did some research on this topic and found this link: Java Preprocessing Using Eclipse, which could potentially let me use preprocessor in Android project.
However, after I tried to build the project, it claimed something like package android.* does not exist. So, none of the android APIs could be found.
So, how should I add those libraries in the build path? Actually, android.jar file is under the Java Build Path already. Why does Eclipse still claims that?
Is there any other way to let me use the preprocessor in Android Project built in Eclipse?
You are programming in Java, not C/C++. Android development does not require the use of a preprocessor.
Edit:
My problem is we developed an Android app with USB functionality which is supported only by Android 3.1+. So, some of the USB libraries are imported, what I want is those imported libraries could be commented out using #ifdef, if we could, when we build the project for Android 2.2 or 2.3, etc. Is there any other workaround for this?
To make use of the classes/methods you mentioned, you'll have to build your application against the Android SDK version 3.1 or higher. However, you must also ensure that devices running version 3.0 or lower don't make use of these classes/methods during runtime, since doing so will result in a ClassNotFound exception.
The key take-away here is that you need to perform these checks at run-time. Since your application is compiled only once for all devices, a preprocessor could do nothing to prevent such an event from occurring. Instead, you need to explicitly protect against this in your code. This is usually done with a basic if-else statement. For example,
if (Build.VERSION_CODES.HONEYCOMB_MR1 >= Build.VERSION.SDK_INT) {
// then you are on a device running android 3.1+ and it is
// safe to make use of the new classes/methods
} else {
// otherwise, you are running on a device running android 3.0
// or lower. you should not make use of the new classes/methods.
}
Edit #2:
In response to bill's comment, which read:
Thank you, Alex. I built my project agaist 3.1, deployed it on 2.2 and run it. One last thing I am not quite sure I understand is I could debug the part of the code referred by the Android 3.1 on the Android 2.2 OS. Here is my explanation: after being built against 3.1, Java code is converted to machine code and HONEYCOMB_MR1 is just an integer although HONEYCOMB_MR1 is not present in 2.2, when I debugged it, the debugger goes to the line of HONEYCOMB_MR1, fetches that integer and compares with SDK_INT. In this way, the code could still be debugged although HONEYCOMB_MR1 is only in 3.1 SDK. Is that correct? Thanks.
I think you are understanding correctly. The more exact reasoning is that HONEYCOMB_MR1 is marked static final. Since the variable is an immutable constant (i.e. its value will never change), the integer is hard-coded into the bytecode when you compile the .apk. In So when your 2.2 device reaches the if statement, it checks to see if 12 > 8, thus avoiding a (failed) runtime search for HONEYCOMB_MR1.
This sort of thing actually happens quite frequently when you develop your Android application. For instance, this behavior also explains why you can use MATCH_PARENT (introduced in 2.2) on devices that should "technically" only support FILL_PARENT. Both constants have value -1; thus, when you run an app that uses MATCH_PARENT on a pre-Froyo device, all works as expected.
As I am very pissed off of using the emulator to develop any Java class, I thought of setting up a project in Eclipse and instead of the usual JRE I linked to the Android.jar (version 2.1) that usually the Android projects link to. I don't mean to use this to develop Layouts or other specific platform things, I was just trying to create a class that uses HttpClient. It miserably crashes like this.
Exception in thread "main"
java.lang.RuntimeException: Stub! at
org.apache.http.impl.client.AbstractHttpClient.(AbstractHttpClient.java:5)
at
org.apache.http.impl.client.DefaultHttpClient.(DefaultHttpClient.java:7)
at
AdsCatcher.(AdsCatcher.java:26)
at TestAll.main(TestAll.java:10)
Stub! I mean I'd like to develop libraries (and test them) so that when I go to the emulator I don't have to deal with them. Is there a good way to do this? This seems not to work for some reason.
This will not work, sorry. The android.jar file, as the error message indicates, contains only stubs of the Android API. This makes sense, since that API cannot work outside of Android -- the android.jar file is just there for compilation.
For class libraries you are working on that have no dependencies on Android, you are welcome to create a standard JRE Eclipse project that generates a JAR that you then use in your Android project.
In your case, you may be able to create a class library using the JRE that uses HttpClient. The latest version from Apache may differ slightly from the version in Android, though, so while probably you will be OK, there's a chance you will run into runtime errors due to changes in method signatures and such (VerifyError).