Android NDK JNI C++ <5> callback java code & swig

下面我有两个样例,这两个样例在调用上互逆的,一个是功能是在jni中的C/C++语言中实现的,一个是功能用java实现的,但是调用(或者说使用这个功能)是在jni中的C/C++语言实现的(仅仅调用而已),

样例一:jni调用java实现的功能method:

<1> :

java实现的如下:

package nativejni;

import android.content.Context;
import android.widget.Toast;

public class CallNativeFromJni {
    
    static{
        System.loadLibrary("nativelibs");
    }
    
    static Context mContext;
    
    public CallNativeFromJni(Context ctx){
        
        mContext=ctx;
        Toast.makeText(mContext, "CallNativeFromJni Construction !", Toast.LENGTH_SHORT).show();
        
        nativeInit();
        
    }
    
    public void CallNonStaticMethod(int value){
        
        Toast.makeText(mContext, "non static method : "+value, Toast.LENGTH_SHORT).show();
        
    }
    
    public static void CallStaticMethod(int value){
        
        Toast.makeText(mContext, "static method :"+value, Toast.LENGTH_SHORT).show();
        
    }
    
    public native void nativeInit();
    public native void callNonStaticMethod();
    public native void callStaticMethod();
    
}

上面的代码基本上分成三部分:
第一部分:加载库

static{
        System.loadLibrary("nativelibs");
    }

第二部分:本地java实现功能部分:

static Context mContext;
    
    public CallNativeFromJni(Context ctx){
        
        mContext=ctx;
        Toast.makeText(mContext, "CallNativeFromJni Construction !", Toast.LENGTH_SHORT).show();
        
        nativeInit();
        
    }
    
    public void CallNonStaticMethod(int value){
        
        Toast.makeText(mContext, "non static method : "+value, Toast.LENGTH_SHORT).show();
        
    }
    
    public static void CallStaticMethod(int value){
        
        Toast.makeText(mContext, "static method :"+value, Toast.LENGTH_SHORT).show();
        
    }

第三部分:在jni中需要调用的方法名:

public native void nativeInit();
    public native void callNonStaticMethod();
    public native void callStaticMethod();

第三部分的callNonStaticMethod()等将会调用java代码写CallNonStaticMethod(int value)等方法.

<2> : javah生成头文件以后,

javah -classpath nativejni.CallNativeFromJni

执行上面命令行之前,首先新建jni文件夹,执行后,它会自动在jni文件夹中生成nativejni_CallnativeFromJni.h的头文件,自行修改一下头文件的名字成CallNativeFromJni.h.

<3> : 新建CallNativeFromJni.c文件,编写头文件方法的具体实现:

#include "CallNativeFromJni.h"
#include<string.h>
jclass mClass;
jobject mObject;
jmethodID mNonStaticMethodID,mStaticMethodID;

JNIEXPORT void JNICALL Java_nativejni_CallNativeFromJni_nativeInit
  (JNIEnv *env, jobject thiz){

    jclass clazz=(*env)->GetObjectClass(env,thiz);
    mClass=(jclass)(*env)->NewGlobalRef(env,clazz);

    mObject=(jobject)(*env)->NewGlobalRef(env,thiz);

    mStaticMethodID=(*env)->GetStaticMethodID(env,mClass,"CallStaticMethod","(I)V");

    mNonStaticMethodID=(*env)->GetMethodID(env,mClass,"CallNonStaticMethod","(I)V");

}

JNIEXPORT void JNICALL Java_nativejni_CallNativeFromJni_callNonStaticMethod
  (JNIEnv *env, jobject thiz){
    (*env)->CallVoidMethod(env,mObject,mNonStaticMethodID,100);
    return ;    
}

JNIEXPORT void JNICALL Java_nativejni_CallNativeFromJni_callStaticMethod
  (JNIEnv *env, jobject thiz){
    (*env)->CallVoidMethod(env,mObject,mStaticMethodID,200);    
    return ;
}

上面mClass获取方式,还有一种非常常见的:

mClass=(*env)->FindClass(env,"nativejni.CallNativeFromJni");
    /* check exception */
    if((*env)->ExceptionCheck(env)){
        return ;//ERR_FIND_CLASS_FAILED;
    }

获取后,必须要检查是否成功.

要回调java编写的方法,首先要获得三个字段,jclass,jobject,jmethodID.

API 参考:

http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html

API样例:

http://www.ibm.com/developerworks/library/j-jni/index.html

 

jni这一段只能做桥梁连接作用,如果功能使用jni的语法来操作和实现,不是太实际,实际功能实现部分还是用C/C++实现的,可以在这个工程中继续添加fun.c和fun.h两个文件:

fun.h

#ifndef _FUN_HEADER_C__
#define _FUN_HEADER_C__

int addc(int,int);

#endif

fun.c

#include "fun.h"
int addc(int a,int b){
    return a+b;
}

让后在上面的CallNativeFromJni.c中添加:

#include "fun.h"


然后在调用本地代码传入参数100改成如下:

(*env)->CallVoidMethod(env,mObject,mNonStaticMethodID,addc(122,1));

即可以了.
当然在Android.mk的LOCAL_SRC_FILES :=字段后面要把所有*.c或者*.cpp的文件包含进来.

<4> 执行ndk-build后,如不出意外,即生成so库文件.

下面介绍通过jni实现功能,java调用,这种有两种方法,一个是从java开始先定义出接口方法名,另外一种是jni先定义出接口,这种方式一般是采用CPlusPlus完成的.

这里面一般采用第二种,这一种直接采用C++和swig生成jni的相关文件方法是最快和最便捷的,不需要去操作j开头的jni开发了,只需要熟悉C++语言即可,查看前面的文章内容即可.

 

 

 

 

 

 

 

 

posted @ 2014-05-14 14:09  MMLoveMeMM  阅读(962)  评论(0)    收藏  举报