[fpc-pascal] JNI/Android: Java events calling pascal code
patspiper
patspiper at gmail.com
Wed Apr 23 13:28:40 CEST 2014
On 23/04/14 12:31, Felipe Monteiro de Carvalho wrote:
> On Wed, Apr 23, 2014 at 6:10 AM, leledumbo<leledumbo_cool at yahoo.co.id> wrote:
>> Hmm...that's beyond my Java skill. Since Felipe who started the topic, you
>> can try PM him instead.
> So looking at what he originally posted:
>
> setOnCompletionListener(MediaPlayer.OnCompletionListener listener)
>
> And looking into the documentation:
>
> http://developer.android.com/reference/android/media/MediaPlayer.OnCompletionListener.html
>
> you need to provide a class which implements the
> MediaPlayer.OnCompletionListener interface:
>
> There is nothing in JNI unfortunately which would allow us to create
> new classes. JNI is very limited, unlike objc runtime which gives us
> access to everything, JNI gives us a limited access to the Java world.
>
> I already asked in the past in Java/Android groups about this, how to
> get rid of Java when you need to pass a class which implements and
> interface.
>
> The answer is that it is possible: You need to create the class in
> ...... java bytecode =D And then pass it to Java.
>
> At this point I gave up, considering it too awkward and wrote my
> software part in Java and part in Pascal.
>
> Ideally it would not be so hard if we had a bytecode generator which
> accepts as input things like classname, which interfaces it will
> implement, list of functions and address to their implementation, etc,
> etc. But we don't have at the moment AFAIK.
>
> So maybe someone braver will actually do this, since it is possible =D
> But I didn't for my Android app in the app store (True Democracy)....
Now that I have re-read the (your) thread I had pointed out in my post,
and went through a lot of googling, I think it is possible to create one
static bit of java code (dynamic proxy) and instantiate that class from
pascal/jni:
The java code:
public class NativeInvocationHandler implements InvocationHandler {
public NativeInvocationHandler(long ptr) {
this.ptr = ptr;
}
public static Object newInstance(Class clazz, long ptr) {
return java.lang.reflect.Proxy.newProxyInstance(
clazz.getClassLoader(),
clazz.getInterfaces(),
new NativeInvocationHandler(ptr));
}
Object invoke(Object proxy, Method method, Object[] args) {
return invoke0(proxy, method, args);
}
native private Object invoke0(Object proxy, Method method, Object[] args);
private long ptr;
}
Pascal:
function invoke0(env: PEnv; thiz: jobject; method: jmethod; args:
jobjectArray): jobject;
var
ptrField: jFieldID;
jptr: jlong;
lMediaPlayerEvent: TMediaPlayerEvent
begin
ptrField := GetFieldID(GetObjectClass(thiz), 'ptr', 'J');
jptr := GetLongField(thiz, ptrField);
lMediaPlayerEvent := TMediaPlayerEvent(jptr);
result := lMediaPlayerEvent.invoke(env, method, args);
end;
TMediaPlayerEvent = class(TObject)
public
function invoke(env: PEnv; method: jmethod; args: jobjectArray): jobject;
end;
TMediaPlayerEvent.function invoke(env: PEnv; method: jmethod; args:
jobjectArray): jobject;
begin
// code to handle events
end;
Then:
- gMediaPlayerEvent := TMediaPlayerEvent.create;
- create the java media player
- call static method
NativeInvocationHandler.newInstance(javamediaplayerclass, gMediaPlayerEvent)
- set the java media player's setOnCompletionListener(result of
NativeInvocationHandler.newInstance)
Now java media player events will be channelled to gMediaPlayerEvent.invoke
The code above is untested and written hastily for the purpose of this
email. I plan to test it today if I have enough time.
Comments/corrections are welcome.
Stephano
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freepascal.org/pipermail/fpc-pascal/attachments/20140423/69380222/attachment.html>
More information about the fpc-pascal
mailing list