Using implement an AndroidJavaClass in unity - java

I have a java object that gets a listener object as a parameter. This listener should implement a certain java abstract class.
I'm trying to prevent writing this in java, because I use an SDK that comes in a jar file, and to call a jar file from a java file, I'll need to create one jar file that includes them both (see Unity3D with multiple jars (android jar + pure java lib))
This answer explains my error but doesn't give a solution.
AndroidJavaProxy is not an interface
I'll try to be more detailed:
I've got the Listener class (which is inside the jar file):
public abstract class AttachCallback {
public AttachCallback();
public void onAttached(Sdk sdk);
}
My c# code is currently (and doesn't work):
public class AttachCallback : AndroidJavaProxy
{
public AttachCallback() : base("com.example.AttachCallback")
{
}
public void onAttached(AndroidJavaObject sdk)
{
Debug.Log("-----Attached------");
}
}
Currently, I get java.lang.IllegalArgumentException: com.example.AttachCallback is not an interface
So, is there a way to do this?
Thanks in advance,
Chaim

First: read this article. Android Java Proxy can implement only interfaces. So you should create interface in java. Something like:
public interface IAttachable
{
public void onAttached(Sdk sdk);
}
In your AttachCallback class you add this interface like:
public abstract class AttachCallback implements IAttachable {
public IAttachable unityCallback;
public void onAttached(String sdk)
{
unityCallback.onAttached(sdk);
}
}
Then in your unity class, create JavaProxy
public class AttachCallback : AndroidJavaProxy
{
public AttachCallback() : base("com.example.IAttachable")
{
}
public void onAttached(AndroidJavaObject sdk)
{
Debug.Log("-----Attached------");
}
}
For attaching your Unity Proxy you should pass your AttachCallback to java, something like:
public void AddAttachToJava()
{
AttachCallback callback = new AttachCallback();
//Passing to activity, but you can do whatever you want
using (AndroidJavaClass javaClass = new AndroidJavaClass("your activity class name"))
{
using (AndroidJavaObject activity = javaClass.GetStatic<AndroidJavaObject>("mContext"))
{
activity.Call("attachUnityCallback", callback);
}
}
}
Your java method in activity should look like this:
public void attachUnityCallback(IAttachable attachable)
{
// if AttachCallback is created
attachCallback.unityCallback = attachable;
attachCallback.onAttached(sdk);
}

Related

JNI Unsatisfied Link Error when calling the methods of one class but not the other

I want to wrap a C++ library (PCL) in Java code using JNI, but I am having inconsistent results. I have first created a PointXYZ class for testing and it looks like this:
package pcl;
public class PointXYZ extends NativeObject {
PointXYZ() { }
#Override
public native void alloc(); // creates pointer + handle on the native side
#Override
public native void dispose(); // sets handle to 0 and deletes pointer
public native float getX();
// ...
}
I have generated the C header for this class using javah, compiled everything using CMake, tested it using its getters and setters and everything works perfectly.
static {
System.setProperty("java.library.path", System.getProperty("user.dir") + "/lib");
System.loadLibrary("pcl_java_common");
}
#Test
void attributeAccessTest() {
PointXYZ p = new PointXYZ();
p.alloc();
p.setX(3);
assertEquals(p.getX(), 3);
p.dispose();
// all is good
}
Now I have done the exact same steps for a PointXYZRGB class which inherits from PointXYZ and when I try to test that it throws java.lang.UnsatisfiedLinkError. Here is the class:
package pcl;
public class PointXYZRGB extends PointXYZ {
public PointXYZRGB() { }
#Override
public native void alloc();
#Override
public native void dispose();
public native short getR();
// ...
}
I have checked the generated .dll using Dependency Walker and the PointXYZRGB methods are all present. Anyone knows what the problem could be?
UPDATE: Here are the .dll functions as requested in the comment:
The problem was that System.setProperty("java.library.path", System.getProperty("user.dir") + "/lib"); does not actually make Java look for .dll files in the given path. It essentially does nothing. Then why do the tests work for PointXYZ? This is was my mistake of having put an older .dll into the project root folder, so it was essentially looking for methods in that.

How to define more generic classes and interface when using realm?

I am trying to write a function that gets a list of games and use a callback to load the results. This is what i have right now:
public void getAllGames(OrderedRealmCollectionChangeListener<RealmResults<Game>> callback) {
realm.where(Game.class).findAllSortedAsync("startTime").addChangeListener(callback);
}
I want to make decouple Realm(OrderedRealmCollectionChangeListener and RealmResults) from this function, but I don't know how. I tried creating a listener that extends the OrderedRealmCollectionChangeListener but I am still stuck with the RealmResults, and when I try to extend that it said BaseRealm is private so it is impossible for me to create a constructor for that. How can I make it look like this:
public void getAllGames(SomeListener<SomeList<Game>> callback) {
realm.where(Game.class).findAllSortedAsync("startTime").addChangeListener(callback);
}
Derp, all I should have done is write the callback behaviour inside the getAllGames function:
public void getAllGames(SomeListener<List<Game>> callback) {
realm.where(Game.class).findAllSortedAsync("startTime").addChangeListener(new OrderedRealmCollectionChangeListener<RealmResults<Game>>() {
#Override
public void onChange(RealmResults<Game> collection, OrderedCollectionChangeSet changeSet) {
callback.callback(collection);
}
});
}

GWT Interface woes : Breaking on exception: TypeError: Cannot read property 'getRestWrapper' of undefined

I am writing a GWT app using Libgdx & having some difficulties loading the correct rest library at runtime.
In my core gradle project, I have defined a "RestWrapper" Interface that grants access to platform specific REST functions (in the case of GWT, RestyGWT). When the HTML5 launcher is run, it passes it's implementation to the LibGDX game class in the Core Project.
However when the HTML5 Project is run this error is raised by the compiled JS:
Breaking on exception: TypeError: Cannot read property 'getRestWrapper' of undefined
The issue appears to be with the first interface (PlatformWrapper).
I understand the GWT compiler is a bit ham-fisted when it comes to interfaces, Should I be taking a different approach to running GWT specific code from my core project?
Calling code (In core Project:)
UserSessionToken token =client.getPlatform().getRestWrapper().getRestLogin().attemptLogin(userNameBox.getText(),passwordBox.getText());
Interfaces (In core Project):
PlaformWrapper
public interface PlatformWrapper {
public RestWrapper getRestWrapper();....
RestWrapper
/* Platform independent wrapper for REST services */
public interface RestWrapper {
public RestLogin getRestLogin();....
Implementations (In HTML5 Project):
PlatformWrapper (Top level)
public class GWTWrapper implements PlatformWrapper {
public RestWrapper gwtRestWrapper;
public GWTWrapper(){
gwtRestWrapper = new GWTRestWrapper();
}
#Override
public RestWrapper getRestWrapper() {
return gwtRestWrapper;
}
GWTRestWrapper:
public class GWTRestWrapper implements RestWrapper {
public RestLogin restLogin;
public RestPortal restPortal;
public RestRegister restRegister;
public GWTRestWrapper(){
restLogin = new GWTRestLogin(); //GWTRest Logic
restRegister = new GWTRestRegister();
restPortal = new GWTRestPortal();
}
#Override
public RestLogin getRestLogin() {
return restLogin;
}
Cheers.
Working change:
public ApplicationListener getApplicationListener () {
setLoadingListener(new LoadingListener(){
#Override
public void beforeSetup() {
// TODO Auto-generated method stub
}
#Override
public void afterSetup() {
// TODO Auto-generated method stub
wrapper = new GWTWrapper();
client.setPlatform(wrapper);
}
});
return client;

Android: working with interface and WeakHashMap

After a whole night spent in test (without any luck) I need some support with my interface.
I'm working directly on the Android frameworks and I created a class that works as a Binder with a WeakHashMap to control the callbacks.
Here is the code:
MyCallback:
public interface MyCallback {
public void fire();
}
MyBinder:
public static WeakHashMap<String, MyCallback> mCallbacks =
new WeakHashMap<String, MyCallback>();
public static void setup(MyCallback callback) {
if(mCallbacks.get(callback.getClass().getName()) == null) {
mCallbacks.put(callback.getClass().getName(), callback);
}
}
public static void letsgo() {
Log.d("size", " " + mCallbacks.size()); // IMPORTANT
for (MyCallback cb : mCallbacks.values()) {
cb.fire();
}
}
These 2 classes are written into frameworks so I created 2 test applications with a simple class that implements my interface:
public class FirstApp implements MyCallback {
public FirstApp() {
MyBinder.setup(this);
}
#Override
public void fire() {
Log.d("app1", "fired");
}
}
public class SecondApp implements MyCallback {
public SecondApp() {
MyBinder.setup(this);
}
#Override
public void fire() {
Log.d("app2", "fired");
}
}
Ok at this point I made another class (all these 3 classes, so the 2 that implements the interface and the following one are written into different packages)
In this third class i just call: MyBinder.letsgo();
The issue I'm facing, and that I'm trying to solve since... 8/9 hours is that: If i run letsgo() on the third pack the logs shown 0 for the callbacks WeakHashMap size. if i run letsgo() on the second package it works but it only fires the callback in the same package. the same if i run it on the first package.
I tried also with HashMap instead of WeakHashMap since i red that objects must be referenced but without any luck. I wonder if someone can help me and let me go sleep :D Thanks!

Java structure/pattern(s) to return specific field from subclasses

For a project we have a requirement to create an interfacedefinition that will return all available filetype extensions that our component can export...
The problem is that we want avoid configuration/properties files. We don't want to edit our configuration/propertie file when another filetype is added (in the future). The structure of this part of our component is as follows:
public abstract class FileType {
protected String filetype;
public FileType(String filetype){
this.filetype = filetype;
}
public abstract void export(String path, Object information);
}
public class PdfExport extends FileType {
public PdfExport() {
super("pdf");
}
public void export(String path, Object information){
//pdf specific logic
}
}
But how do we solve this when another component calls the interfacedefinition getExportTypes()? (How do we get a list of all available filetypes?) Taking into account the requirement to add in the future new classes that extend abstract class filetype (add new filetypes)?
Does anyone has suggestions, maybe another structure of above example? Or any (design) that discuss above issue?
Thanks in advance!
You could do something like this:
public interface FileType {
public String getFileType();
public void export(String path, Object info);
}
public enum DefaultFileType implements FileType {
PDF(".pdf"){
public void export(String path, Object info) {
// do pdf stuff
}
}, TXT(".txt"){
public void export(String path, Object info) {
//do txt stuff
}
};
private final String fileType;
private DefaultFileType(String fileType) {
this.fileType = fileType;
}
public String getFileType() {
return fileType;
}
public abstract void export(String path, Object info);
}
Then you can have a Set<FileType> in your class of all the supported FileTypes. This way anyone who wants to add a supported FileType but cannot edit your enum can still do so.
This is the exact purpose of the strategy pattern. The strategies here are the FileTypes that encapsulate an algorithm that exports a file.
In the following example:
public class Application{
List<FileType> exporters = new ArrayList<FileType>();
public void addExporter(FileType fileExporter){
exporters.add(fileExporter);
}
public void exportData(Object information){
for(FileType exporter : exporters){
exporter.export("d:\Export", information);
}
}
}
The Application class holds a list of exporters that can be filled out on the go. The Application class does not have to know what type of file exporter is registered nor how the file can be exported. When the data is exported, the Applicaiton class loops through registered exporters and delegates the export task to each one of them.
EDIT Below is an example of the Application class usage.
// Define a pdf exporter
PdfExport pdfExport = new pdfExport();
Application app = new Application();
// Register the new exporter
app.addExporter(pdfExport);
// Export some data...
app.export(information);
EDIT How to avoid configuration files and changing the code everytime you have a new FileType?
You can load the exporters at runtime using reflexion (see this link for details)
You can use reflection to scan classes which implement your interface.
Have a look at similar question: At runtime, find all classes in a Java application that extend a base class

Categories