Android JNI method - Is the second parameter jclass or jobject? - android-ndk

Folks,
In my Android Java code, I have a declaration as follows:
public class SurfacePanelNative extends SurfaceView implements SurfaceHolder.Callback {
...
private static native void native_render();
}
In my native code, I have the function declared as:
void native_render(JNIEnv *env, jobject javaSurface) {
ANativeWindow* window = ANativeWindow_fromSurface(env, javaSurface);
...
}
Looking at some examples on the net, it appears that the function should be declared as:
void native_render(JNIEnv *env, jclass clazz) {
...
}
I am wondering which declaration is the right one.
I am thinking the first one is the right one. Otherwise, I don't have enough information to obtain javaSurface.
I would appreciate it if someone can shed some light on this.
Thank you in advance for your help.
Regards,
Peter

It is jclass if the method is static, otherwise jobject. If you use javah, as the JNI designers intended, you will always get the right answer.

Related

what are override methods and how do they work?

I was doing some comp sci homework, and realized I had forgotten the concept of overriding a method. I have to override the equals method, in this code:
public boolean equals( Object b )
{
if ( ! (b instanceof Employee) )
return false;
So, I have to add in code that overrides a method, but I forgot what override means. Could someone explain it as a concept a little better? How does it apply to this code?
When you are overriding, you are basically taking the function that is it is using by the class that implements it, and making it better. For example, when using the paintComponent method, you usually have the #override above it like:
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
notice that you have to call the super.paintComponent(g); inside the method. This is how the overriding is done, is by using the super implementation to start it, and then using your own code to increase the uniqueness about it.
hope that helps

What does it mean for void to be a "first class type"?

As the title says, and what are the benefits of this? The question was inspired by Microsoft's research language.
Being a first-class type means void could be used anywhere a type annotation is allowed. In C#, void can only be used as a return type for a method, but all of the following are illegal:
// A void parameter type.
int SomeMethod(void parameter) { ... }
// A void type argument.
List<void>
// A void variable.
void Main()
{
void someVar;
}
Java does have a first-class void type, spelled Void (note the capital "V"). It's useful sometimes in generics. It only has one value, null.
If void is a first class type then you can use it when defining variables. I think a void variable could be used as a pointer to pass a something like a function or an object if you recast it I guess. It would give you an ability to do dynamic type casts.

Subclass a C++ abstract class in Java using JNI

I have a C++ library that I have to use in an existing Android implementation. I'm using Android NDK and using the C++ classes via JNI.
However, I am not able to find how to subclass a C++ abstract class in Java using JNI.
Problems I face:
My aim is to provide Java implementation for the virtual methods in C++ by subclassing the abstract C++ class.
I have loaded the native library and I'm trying to declare the native methods.
The C++ methods have keyword 'virtual'. When I declare the native functions in Java after loading the C++ library, 'virtual' is not recognized. What is wrong here?
Any help is appreciated. I'm a newbie to JNI. Thanks in advance.
Let's consider we have a C++ class:
class iVehicle
{
public:
virtual void Run() {}; // not-pure virtual here for simplicity of a wrapper, but could be pure (see the end of the post)
virtual int GetSize() const; // we want to reuse it in Java
};
We want to create a class Bot in Java that extends class iVehicle in the sense that calls to super invoke the C++ code from iVehicle::GetSize() and, from the C++ point of view, we can use the instances of Bot as iVehicle* variables. That's tough since C++ provides no good built-in functionality for reflection.
Here is one possible solution.
To use C++ class in Java we need to generate a Java wrapper, i.e:
class iVehicle
{
public void Run() { Native_Run(); }
public int GetSize() { return Native_GetSize(); }
private native void Native_Run();
private native int Native_GetSize();
// typecasted to pointer in C++
private int NativeObjectHolder;
// create C++ object
native static private int CreateNativeObject();
}
The usage in Java is simple:
class Bot extends iVehicle
{
public int GetSize()
{
if ( condition ) return 0;
// call C++ code
return super.GetSize();
}
}
However, there is a C++ part to this code:
static jfieldID gNativeObjectHolderFieldID;
JNIEXPORT void JNICALL Java_com_test_iVehicle_Run( JNIEnv* env, jobject thiz )
{
int Value = env->GetIntField(thiz, gNativeObjectHolderFieldID);
iVehicle* Obj = (iVehicle*)Obj;
// todo: add checks here, for NULL and for dynamic casting
Obj->Run();
}
The similar code is for GetSize().
Then creating an instance of Java's Bot you have to call CreateNativeObject() and assign the returned value to the NativeObjectHolder field.
JNIEXPORT int JNICALL Java_com_test_iVehicle_CreateNativeObject( JNIEnv* env, jobject thiz )
{
iVehicle* Obj = new iVehicle;
return (int)Obj;
}
So, this is the scheme. To make this work you will need to add the destruction code and to parse C++ classes to generate all this glue code.
Added:
In case where iVehicle is actually abstract you will have to generate a non-abstract wrapper that you are able to instantiate:
class iVehicle
{
virtual void Run() = 0;
}
class iVehicle_Wrapper: public iVehicle
{
virtual void Run() { ERROR("Abstract method called"); };
}
And instantiate iVehicle_Wrapper in CreateNativeObject(). Vuala! You have inherited an abstract C++ class in Java.

C++.net Delegate not working - compiler error

Right I created a new thread from a static function from the same class.
Inside the same class I try to call a delegate to update the GUI.
I get a compiler error saying:
Invalid delegate initializer - an object is needed in addition to a function.
At &MainUi::AddListItemMethod.
delegate void AddListItem(void);
public: void AddListItemMethod(String^ myString)
{
ListView1->Items->Add(myString);
}
private: static void SecondThread()
{
AddListItem^ del = gcnew AddListItem(&MainUI::AddListItemMethod);
del->Invoke("test");
}
I don't know why it doesn't work. I also tried this and still failed. Any help please?
Invoke(gcnew AddListItem(MainUI::&AddListItemMethod), "test");
Either You have to make Listview1 static to work or you should create an instance/object of MainUI class to access a non static method of that class.
Thank you and Happy coding.

how to pass java class instance as a parameter to JNI method?

I'd like to pass java class object to JNI method,
And I want to call few methods in JNI method like below.
Is there anyone who have some example like below?
class JavaClassParameter{
void javaMethodTobeCalledInJNI(){
...java source...
}
}
class MainJavaClass{
void somemethod(){
JavaClassParameter object = new JavaClassParameter();
JNIMethod(object);
}
native void JNIMethod(JavaClassParameter object);
}
// C++ code
void JNIMethod(object){
object->javaMethodTobeCalledInJNI();
}
Your method declaration:
class MainJavaClass {
native void JNIMethod(JavaClassParameter object);
}
means javah should generate a forward declaration like the following:
JNIEXPORT void JNICALL Java_MainJavaClass_JNIMethod(JNIEnv* env, jobject mainJavaClass);
In the implementation of that, you have a few things to do:
Find JavaClassParameter
Use FindClass, which takes a string name:
jclass cls = env->FindClass("JavaClassParameter");
Find javaMethodTobeCalledInJNI()
Use GetMethodID, which takes the class to check, the string name of the method, and its signature. Since this is a void function with no arguments, its signature is just ()V:
jmethodID method = env->GetMethodID(cls, "javaMethodTobeCalledInJNI", "()V");
Call javaMethodTobeCalledInJNI()
Use CallVoidMethod, which takes the object instance, the method ID, and any arguments (none in this case):
env->CallVoidMethod(mainJavaClass, method);
You should check for NULL results after each step; if you get a NULL back from one JNI function and pass it to another, you'll usually crash the JVM

Resources