How to communicate with java in Android (working in v11.171-beta).

Previous topic - Next topic

hardyx

Quote from: spacefractal on 2012-Oct-15
Here is some java calls I use
.................
WOW! Now I see the power of your glb_JAVACALL.

spacefractal

I have updated the first post, because there was still some strange issue I never have found out why. Its seen Java Visual Machine does NOT correctly remove reference to pointers from c++, but you need to remove them manally from c++.

This is something documents not said, which statemeted java visual machine should garbage collect it by its self. but its dosent do that with java variable, called from c++. So you need to free them using DeleteLocalRef command, which I have added.

This should ben now much more stable rather than crash out after about 120+ java calls.
Genius.Greedy Mouse - Karma Miwa - Spot Race - CatchOut - PowerUp Elevation - The beagle Jam - Cave Heroes 2023 - https://spacefractal.itch.io/

hardyx

Quote from: spacefractal on 2012-Nov-04
I have updated the first post, because there was still some strange issue I never have found out why. Its seen Java Visual Machine does NOT correctly remove reference to pointers from c++, but you need to remove them manally from c++.

This is something documents not said, which statemeted java visual machine should garbage collect it by its self. but its dosent do that with java variable, called from c++. So you need to free them using DeleteLocalRef command, which I have added.

This should ben now much more stable rather than crash out after about 120+ java calls.

Maybe you must to release manually the java objects you use in the c++ part. BTW, it is called java virtual machine, not visual. Thanks for the fix.

spacefractal

yes its was required and releasing the java objects I called from c++? Its fixed in the c++ code with few lines (but took hours to find out about that). That could been why some people have cancelled some orders due this? Damn, but finally I did fixed that. I could now do 1000+ calls without crashing. So I guess even KEYPRESSES thing now can been monited, those glbasic sometimes skips? I look on the screen keyboard which could been fun to add (but AMBOS have a nice onscreen keyboard rutine to been used).

Anyway I have cleanup the post about the java calls which one I use, but its can of course expand much more. Etc I explain how to fix the ORIENTATION issues. Due that I have removed the thread from the bug section, because its not needed anymore and required to been fixed by Gernot. Its easy to fix that one by your self.

I hope Gernot add those code and the fix to your build. Fell free to do that :-D.

Genius.Greedy Mouse - Karma Miwa - Spot Race - CatchOut - PowerUp Elevation - The beagle Jam - Cave Heroes 2023 - https://spacefractal.itch.io/

Crivens

QuoteI look on the screen keyboard which could been fun to add (but AMBOS have a nice onscreen keyboard rutine to been used).
The Ampos keyboard was really good, and a lot of us make our own. Most of the time it's fine for games, but for example my latest project is an app for a company (ie. not a game) and while they like my own keyboard it was mentioned that it would be nice for the proper Android keyboard to be used. It shows that for apps (rather than games) then the actual Android/iOS keyboard is preferable. My iOS keyboard is orange (Jailbroken), for example, and it's really glaring when it looks different in certain apps (including Cydia amusingly).

So go on, you know you want to implement the keyboard! =D I would owe you a bevvy of beers and build a statue of you in my lounge  :nw: Seriously though, would be quite an addition.

Cheers
Current fave quote: Cause you like musicians and I like people with boobs.

spacefractal

You can trying your self. I might look later right now, by now the biggest issue with keyboard, is GlBasic does not using the GUI, but using a SDLSurface, that is the issue. Its nothing problem to open the keyboard, but there is no commands to get input from it directly with inputMethodManager method. Also I do thinks its might have issues with languages with other than english, due glbasic not supports unicode. But I do try later this week.

By now the most important thing using java here is fixing the orientation issue that might been happens on some devices. SETORIENTATION 0 is not allways default....
Genius.Greedy Mouse - Karma Miwa - Spot Race - CatchOut - PowerUp Elevation - The beagle Jam - Cave Heroes 2023 - https://spacefractal.itch.io/

fivesprites

This is really handy, but be warned:

- check for exceptions!  This could cause all sorts of strange behaviour if you don't - if you're lucky enough for your app to continue working!  You must always check and clear exceptions
- release strings you have created.  If you don't you will eventually get memory leaks and heap overflow
- there's no reason to cast retJava to another jstring (res). 
- Don't rely on strncpy in this case - I've seen memory leaks with its use.  It's better to get the length of the string you are copying and use that - then apply a null character

Here's an updated segment from the sdlmain.cpp:

Code (glbasic) Select


const char* android_JAVACALL(const char* url)
{
const char *textString = NULL;

strcpy(g_androidJAVACALL, "-1");
if (cls==NULL)
{
cls = gJNIenv->FindClass("org/libsdl/app/SDLActivity");
if (cls == NULL)
{
return "Invalid class";
}
mid = gJNIenv->GetStaticMethodID(cls,
   "glb_JAVACALL",
   "(Ljava/lang/String;)Ljava/lang/String;"); // (params;..)return_type
}

if (mid==NULL)
{
return "Invalid method";
}

jstring mystr = gJNIenv->NewStringUTF(url);
if (NULL == mystr)
{
return g_androidJAVACALL;
}
jstring retJava = (jstring)gJNIenv->CallStaticObjectMethod(cls, mid, mystr);
if (gJNIenv->ExceptionCheck()) {
gJNIenv->ExceptionClear();
gJNIenv->DeleteLocalRef(mystr);
return "Exception calling method";
}
if (retJava == NULL)
{
gJNIenv->DeleteLocalRef(mystr);
return g_androidJAVACALL;
}
textString = gJNIenv->GetStringUTFChars(retJava, 0);
if (gJNIenv->ExceptionCheck()) {
gJNIenv->ExceptionClear();
gJNIenv->DeleteLocalRef(mystr);
gJNIenv->DeleteLocalRef(retJava);
return "Exception getting textString";
}

int len = gJNIenv->GetStringLength(retJava);
if (gJNIenv->ExceptionCheck()) {
gJNIenv->ExceptionClear();
gJNIenv->ReleaseStringUTFChars(retJava, textString);
gJNIenv->DeleteLocalRef(mystr);
gJNIenv->DeleteLocalRef(retJava);
return "Exception getting length of return string";
}

strncpy(g_androidJAVACALL, textString, len);
g_androidJAVACALL[len] = 0x00;

gJNIenv->ReleaseStringUTFChars(retJava, textString);
gJNIenv->DeleteLocalRef(mystr);
gJNIenv->DeleteLocalRef(retJava);

return g_androidJAVACALL;
}


The above still isn't perfect, but should provide a bit more protection.

//Andy

spacefractal

There should not need to release them when you uses global string variables, not local (which im did not trust on that when you sharing memory with other threads), which is property why om not releasing them. Howover im are no c++ expert, so im did just want the communication to work and prevent memory sharing confict between c++ and java.

No the code was not perfect, but worked nicely and have used long time now (even the first one crashed allready abit over 60-100 calls, which im got fixed that and updated the thread after that fix).

Howover thanks for the update  :)
Genius.Greedy Mouse - Karma Miwa - Spot Race - CatchOut - PowerUp Elevation - The beagle Jam - Cave Heroes 2023 - https://spacefractal.itch.io/

fivesprites

Hi Spacefractal,

Wasn't being critical of your code - it's a really helpful routine to get access to otherwise hidden Android tasks and I've recently used it for a project I'm working on.  The updated code I posted helps to prevent against some problems which you may not have detected yet.

The JNI documentation states that you must check for exceptions after calling certain JNI routines (use ExceptionCheck). You must then clear any pending exception with ExceptionClear.  As your code doesn't do this, one mistake can result in an instant crash.  (This also applies to other code in sdlmain.cpp!)

Note: if you detect an exception - don't continue, but do ensure you release any strings/local references before returning

Also, when you call:

strncpy(g_androidJAVACALL, gJNIenv->GetStringUTFChars(res,  0L), 512);

you aren't releasing (or unpinning) the reference from the GetStringUTFChars call.  Again, according to the JNI documentation, you must always call ReleaseStringUTFChars().

If you examine the Android logs (adb shell logcat) then you will most likely see that the garbage collection keeps kicking in - and often.  You can also check memory usage stats using adb - check out the (dumpsys meminfo) adb command. 

Keep up the good work  :good:

//Andy

spacefractal

I checkout later and update the thread soon. howover its was not a major issue.

If you uses other primary calls than I'm using, I can update the javacall function as well.

I'm primary created this one to do my own assets loader, so it's diddent crash under loading.

I'm happy to see what you using this code too and hope gernot add those code as well. Good luck with your project : :good:
Genius.Greedy Mouse - Karma Miwa - Spot Race - CatchOut - PowerUp Elevation - The beagle Jam - Cave Heroes 2023 - https://spacefractal.itch.io/

r0ber7

Hi. I'm trying to set this up but I've run into a problem I don't understand.

I've modified sdl_main to include android_JAVACALL:

Code (glbasic) Select

const char* android_JAVACALL(const char* url)
{
return "Well the C part works.";
        }


And that works. But when I try to set up the Java part, I get this message from adb shell logcat.

Code (glbasic) Select
I/glbasic (13754): Invalid method

Which I assume is done because mid == NULL

Code (glbasic) Select

mid = gJNIenv->GetStaticMethodID(cls,
   "glb_JAVACALL",
   "(Ljava/lang/String;)Ljava/lang/String;"); // (params;..)return_type
}

if (mid==NULL)
{
return "Invalid method";
}



But as far as I know, I've placed everything in its right place. This has been added to SDLActivity:

Code (glbasic) Select


   // Java functions called from C
public static String glb_JAVACALL(String url)
{ Log.i("glbasic", "calltest");
return "works";
}


Why doesn't it see the method? I'm not using V11 by the way. Any ideas or suggestions are welcome. Trying to get an Android keyboard up and running.

spacefractal

did you tried to put the java stump to the templateproj\src\com\glbasic\test folder (in glbasic folder), not in distribute\Android\src\com\glbasic\test? the templateproj\src\com\glbasic\test one should replace that one in the distribute when you change the file.

Its look like its could not find your java metode, even its seen the code was correct.

For testing you could also use the method im did, before fivesprites changed its for more protectio. That just for tetsing, but then when its works, then uses fivesprites method again, which is better than mine (just edited my main post to point to that code FiveSprite have made).
Genius.Greedy Mouse - Karma Miwa - Spot Race - CatchOut - PowerUp Elevation - The beagle Jam - Cave Heroes 2023 - https://spacefractal.itch.io/