I am trying to build an application that runs under JavaSE and Android. Most of the code is the same between the two, but there are some specific functions that need to be separated. I use Eclipse. So I decided to put the shared code in a separate project, and then build one more project for Android and one for Java, which reference the shared project. I put all Java and Android specific functions in one class residing in the Java and Android specific projects. These classes are called UtilsJ (for Java) and UtilsA (for Android). The code in the shared project uses a factory to determine at runtime which version it needs to pick, and then calls the class loader to load the right class. Essentially: if property java.vm.name equals Dalvik, load UtilsA, else load UtilsJ (and of course cast to the Utils interface before returning).
My question is simply if this is a good idea or is something going to eventually break? I've never used class loader before. Any other suggestions how to implement this sharing would also be appreciated.
Generating an interface implementation dynamically is certainly a valid technique. For instance, having a data access interface that has multiple implementations; one each for flat files, MySQL and WebDAV. The program can pick an implementation at run time based on system/platform properties.
But this feels different. If I saw that I had a Java app and an Android app that had a lot of common code, my goal would be to create an Eclipse project that generates a jar file that I could just drop into the libraries of both projects. In that case, the jar file wouldn't contain any code that was incompatible with one platform or the other. So there wouldn't be any reason to have a platform-specific implementation.
Let's take your example some code reading an initialization file. If it's common code, you have an input parameter which is a file. On Android, maybe it's "/data/data/com.whatever.blahblahblah" and on Java you're getting the "user.dir" system parameter for the top level directories. But one way or another, it's a File, and you hand it to your common setup method. That's okay. But if your initialization file read code e.g. needs a Context to get a Resource to read the file for Android, then it's not common code. And it doesn't belong in a library jar for a JVM-hosted app.
So I think that in your case the platform-specific implementation classes are overkill. If it's common code, it's the same code — period.
Let's talk about another example in your comment. If you are using desktop Java, then you are probably using Swing or AWT, so you still have the same issue of running some network task off the UI thread, notifying when it completes, maybe even updating some progress indicator UI while it's processing. Same function, same operation, but the code is so different that I can't see how having it in the same library next to an AsyncTask version could be of any benefit.
And testing might get tricky. Obviously JUnit will work for everything, but some tests would need to run on a device or emulator.
I stated that it was a valid technique, and of course you may have other compelling reasons to choose the multi-platform option. You asked the question; is anything going to break? My answer is: Probably not, but why risk dealing with some heartburn down the road? Speaking for myself, I wouldn't do it. If I had to support multiple MVC apps, my common library would have nothing but M.
Related
I am working on my Android game called Flat Out Hockey using eclipse as an IDE, Java and native C++.
My issue is with the Java part of the code.
Since I need to build my game for both FireTV, Google Play and OUYA I have different ways to deal with gamepad input on each platform.
One issue is that FireTV uses a different "Project Build Target" than Google Play and OUYA, something specifically made for FireTV by Amazon.
This means I need to use imports and classes that are available under one build target but not on the other and keep switching between them when I build for each platforms.
The issue is that as far as I know there is no preprocessor in Java?
So I just can't do #ifdef like in C++.
This makes the amount of code I need to comment/uncomment or change the values more than it should be.
One "trick" I did was to create a kind of a mimic class for the Amazon gamepad class so I would just change the imports and have a class with the same name but different functionality.
But there are other issues, like the Immersive attribute which is only available on Android OS 5.
And other stuff.
So maybe I am missing some feature in Java, but I would really like to just have to set a single value in a single place to switch between different builds.
Is there anything like that in Java/eclipse?
One approach would be to split your project into several components: a "core" module that defines the main implementation in terms of common interfaces (which it defines), and then a module per target that declares implementations of those interfaces.
So for instance, your core module may define a GamePad interface, and then your FireAdapter module would depend on both the core and Fire's API to create a FireGamePad (which implements GamePad).
Each module then becomes it own build, with its own deliverable.
you could try to use java Comment Preprocessor https://github.com/raydac/java-comment-preprocessor , I made some experiments with usage for Android https://github.com/raydac/java-comment-preprocessor/wiki/AndroidGradlePreprocessing but not very deeply, the preprocessor was developed in 2002 specially for small changes in J2ME projects to avoid huge number of the classes with the same functionality but with small differences for vendor specific parts
When distributing a Java application to others, it can be deployed as a JAR file for easy execution.
But is there a way to change a Java class / part of the code after deployment without having to rebundle the whole application again?
If you have an app with say 10 classes where 9 are finalized but one needs to be adjusted according to the individual case. What would be the easiest way to change just one class in an app?
Probably you want to use java web start. If your user starts application via java web start it is automatically being updated if updates are available.
EDIT
It does not provide class-based granularity, but I believe this is not the real issue. It however provides the jar-based granularity, i.e. the newer version of jar is being downloaded only if it was changed.
No, there's not.
You should repackage OR design the one that should be adjusted to be configurable at runtime. If you can modify it using a configuration database and factory that would be the only way to do it without repackaging.
In theory you could create another jar for the customized classes and put it into the classpath before the old jar, and the JVM will load the customized classes. But this is simply looking for trouble...
Better to build two jars, one with the non changing classes and another with the customized classes and rebuild the later when you need it.
I have written a common class which I want to use in separate Blackberry applications. This class is not in a separate project but just at a common location and I have linked the path of the common class in Java Build Path. I have added same common path to both of my BB applications and they builds and installs without any problem. When I run one application, it start running but when I run the other application, it gives error message "class xxx multiply defined" error and exits.
Any idea what is going wrong here. Thanks in advance
Regards,
Braj
BlackBerry doesn't work as other Java platforms. In BB Java, you can't have two classes with the same full qualified name, even if they live in different projects.
You'll have to rename one of them (either change the class name or the package name) for it to work.
In fact, the only platform where I have seen this restriction is BB. It is a real pain in the ass since you can't reuse a jar library in different projects without renaming it.
UPDATE:
This is the official article on the topic:
http://supportforums.blackberry.com/t5/Java-Development/Application-throws-quot-multiply-defined-quot-error-at-start-up/ta-p/501498
All applications in RIM OS run under one instance of Java Virtual Machine. And therefore it is allowed only one class with particular full qualified name. Adding another class with the same name will lead to failure upon running both of these classes.
There is a library thing, supported in RIM OS, but I do not recommend to use libraries in your project, unless it is very necessary.
It is because if you have several apps with the same library, but with different versions of libraries you may get the same error you reported in your question. And it is hard to manage libraries when you have many applications which use these libraries.
I recommend to copy source code of your library to the project you are working on. Copy via refactoring, to change all full qualified names of classes included in that library.
Thanks guys for replying. I have created a common library and put common code in that. Now I can use this library in different applications without any problem.
However, when I install my applications using BB desktop Manager, the library appears as part of first application but not in second application. I assume it is because, second application realizes that the library is already been included so doesn't need to include it again.
When writing code in an Eclipse project, I'm usually quite messy and undisciplined in how I create and organize my classes, at least in the early hacky and experimental stages. In particular, I create more than one class with a main method for testing different ideas that share most of the same classes.
If I come up with something like a useful app, I can export it to a runnable jar so I can share it with friends. But this simply packs up the whole project, which can become several megabytes big if I'm relying on large library such as httpclient.
Also, if I decide to refactor my lump of code into several projects once I work out what works, and I can't remember which source files are used in a particular run configuration, all I can do it copy the main class to a new project and then keep copying missing types till the new project compiles.
Is there a way in Eclipse to determine which classes are actually used in a particular run configuration?
EDIT: Here's an example. Say I'm experimenting with web scraping, and so far I've tried to scrape the search-result pages of both youtube.com and wrzuta.pl. I have a bunch of classes that implement scraping in general, a few that are specific to each of youtube and wrzuta. On top of this I have a basic gui common to both scrapers, but a few wrzuta- and youtube-specific buttons and options.
The WrzutaGuiMain and YoutubeGuiMain classes each contain a main method to configure and show the gui for each respective website. Can Eclipse look at each of these to determine which types are referenced?
Take a look at ProGuard, it is a "java shrinker, optimizer, obfuscator, and preverifier". I think you'll mainly be interested in the first capability for this problem.
Yes it's not technically part of Eclipse, as you requested, but it can be run from an Ant script, which can be pretty easily run in Eclipse.
I create more than one class with a main method for testing different ideas that share most of the same classes.
It's better to be pedantic than lazy, it saves you time when coding :-)
You can have one class with a main method that accepts a command-line argument and calls a certain branch of functionality based on its value.
I'm trying to develop an external library (not sure if that's the right term) to provide prepackaged functionality in Android projects. Working in Eclipse, I've added the appropriate android.jar file to the build path, and everything is happy both while editing and upon compilation.
However, when I use Android's Handler and Message classes (android.os.Handler, android.os.Message) for inter-thread communication, I get exceptions unless I'm running within an Android app, on the emulator or a device. I can no longer test my library in a "standalone" way without having to go through a running Android target.
Is there any way for me to include these two Android classes and still be able to test my library standalone? Do I need to have the Android source available? Or would it require some sort of conditional compilation hand-waving?
Is there any way for me to include
these two Android classes and still be
able to test my library standalone?
Not readily, by any means I can think of.
Do I need to have the Android source
available?
I don't know where else you would get the implementation from. But, more importantly, those things are not designed to work in isolation outside of the OS, any more than you could just grab a Cocoa class or two and pull them into your Objective-C library and expect them to run on a Windows box.
Off the cuff, knowing nothing about what you're building, I would make whatever dependency you are introducing on Handler and Message be more pluggable. Test outside of Android using a pure-Java implementation, perhaps even just some mocks. Test inside of Android using the real implementation.
You could try the lib Robolectric, that implements the android API so you would be able to create JUnit tests for some isolated code you have:
http://robolectric.org/