android Java与JNI层互相调用

来源:互联网 发布:在线视频转码 知乎 编辑:程序博客网 时间:2024/05/17 03:48

Java层调用JNI中的函数

首先在TextJNI.java层创建一个类TextJNI,类中使用一些native方法

package com.example.androidjni;import android.util.Log;public class TextJNI {    static {        System.loadLibrary("jniInterface");    }    public static int test_jni_getInt() {        return getInt();    }    public static String test_jni_getString() {        return getString();        }    public static native int getInt();    public static native String getString();    public static native int nativeCallBack(String str);}

在别的java类中就可以有如下两种形式去调用这边的函数
1、调用TextJNI类中的函数,从而间接调用native方法
TextJNI.test_jni_getInt()
TextJNI.test_jni_getString()

2、直接调用TextJNI类中引用的native方法
TextJNI.nativeCallBack(“ok”)

二、生成对应的.h文件,并在.cpp文件中实现.h文件申明的方法
这里写图片描述
得到com_example_androidjni_TextJNI.h,然后需要实现com_example_androidjni_TextJNI.cpp如下:

#include "com_example_androidjni_TextJNI.h"#include <stdio.h>#include <stdlib.h>#include "jni.h"int sum(){    int x, y;    x = 100;    y = 100;    x = x + y;    return x;}JNIEXPORT jint JNICALL Java_com_example_androidjni_TextJNI_getInt  (JNIEnv *, jclass){    return sum();}JNIEXPORT jstring JNICALL Java_com_example_androidjni_TextJNI_getString  (JNIEnv *env, jclass){    env->NewStringUTF("HelloNDK");}JNIEXPORT jint JNICALL Java_com_example_androidjni_TextJNI_nativeCallBack  (JNIEnv *env, jclass cls, jstring str){    jclass clz = env->FindClass("com/example/androidjni/MainActivity");    jmethodID mid = env->GetMethodID(clz, "callback_func", "(Ljava/lang/String;)I");    jobject obj = env->NewObject(clz, mid);    return env->CallIntMethod(obj, mid, str);}

三、编译生成jni库文件.so
这里写图片描述

具体详细的步骤可以参考:http://blog.csdn.net/luckywang1103/article/details/46958409


JNI层调用Java中的函数

获取类名:

jclass clz = env->FindClass(“com/example/androidjni/MainActivity”);
“”里面是包名+类名,都是以/分隔
jclass clz = env->GetObjectClass(obj);

获取类方法:

jmethodID mid = env->GetMethodID(clz, “callback_func”, “(Ljava/lang/String;)I”);
callback_func是类clz中的函数,()里面的Ljava/lang/String是callback_func函数的参数类型,I是callback_func函数的返回值类型
这里写图片描述
说明:
1、参数或者返回值为java中的对象时,签名中必须以”L”加上其路径,路径以”/分隔”,最后以”;”结尾
比如说java.lang.String为”Ljava/lang/String;”
2、参数或者返回值为数组类型时,前面加上[
比如[I代表int [],[[D代表double[][]

举个例子:
“(II)V”表示 void func(int, int)
“()Ljava/lang/String;” 表示String func()
“([B)V” 表示func(byte[])

生成类对象:

jobject obj = env->NewObject(jclass clz, jmethodID mid)

调用类成员方法:

env->CallxxxMethod(jobject obj, jmethodID mid, parameters)
类似的有
CallVoidMethod CallStaticVoidMethod
CallIntMethod CallStaticVoidMethod
CallBooleanMethod CallStaticVoidMethod
CallByteMethod CallStaticVoidMethod

操作java的String对象

从java程序中传过去的String对象在本地方法中对应的是jstring类型,jstring类型和c中的char 不同,所以如果直接当作char 使用的话,就会出错。因此在使用之前需要将jstring转换为c/c++中的char *,这里使用JNIEnv提供的方法进行转换。
const char *str = env->GetStringUTFChars(jstr, 0);
env->ReleaseStringUTFChars(jstr, str);
这里使用GetStringUTFChars方法将传进来的prompt(jstring类型)转换成UTF-8的格式,就能在本地方法中使用了。
注意:在使用完你所转换之后的对象之后,需要显示调用ReleaseStringUTFChars方法,让JVM释放转换成UTF-8的string的对象的空间,如果不显示的调用的话,JVM中会一直保存该对象,不会被垃圾回收器回收,因此就会导致内存溢出。

下面是Jni访问String对象的一些方法:
GetStringUTFChars 将jstring转换成为UTF-8格式的char*
GetStringChars 将jstring转换成为Unicode格式的char*
ReleaseStringUTFChars 释放指向UTF-8格式的char*的指针
ReleaseStringChars 释放指向Unicode格式的char*的指针
NewStringUTF 创建一个UTF-8格式的String对象
NewString 创建一个Unicode格式的String对象
GetStringUTFLength 获取UTF-8格式的char*的长度
GetStringLength 获取Unicode格式的char*的长度

下面提供两个String对象和char*互转的方法:

    /* c/c++ string turn to java jstring */      jstring charToJstring(JNIEnv* env, const char* pat)      {          jclass     strClass = (*env)->FindClass(env, "java/lang/String");          jmethodID  ctorID   = (*env)->GetMethodID(env, strClass, "", "([BLjava/lang/String;)V");          jbyteArray bytes    = (*env)->NewByteArray(env, strlen(pat));          (*env)->SetByteArrayRegion(env, bytes, 0, strlen(pat), (jbyte*)pat);          jstring    encoding = (*env)->NewStringUTF(env, "UTF-8");          return (jstring)(*env)->NewObject(env, strClass, ctorID, bytes, encoding);      }      /* java jstring turn to c/c++ char* */      char* jstringToChar(JNIEnv* env, jstring jstr)      {                 char* pStr = NULL;          jclass     jstrObj   = (*env)->FindClass(env, "java/lang/String");          jstring    encode    = (*env)->NewStringUTF(env, "utf-8");          jmethodID  methodId  = (*env)->GetMethodID(env, jstrObj, "getBytes", "(Ljava/lang/String;)[B");          jbyteArray byteArray = (jbyteArray)(*env)->CallObjectMethod(env, jstr, methodId, encode);          jsize      strLen    = (*env)->GetArrayLength(env, byteArray);          jbyte      *jBuf     = (*env)->GetByteArrayElements(env, byteArray, JNI_FALSE);          if (jBuf > 0)          {              pStr = (char*)malloc(strLen + 1);              if (!pStr)              {                  return NULL;              }              memcpy(pStr, jBuf, strLen);              pStr[strLen] = 0;          }          env->ReleaseByteArrayElements(byteArray, jBuf, 0);          return pStr;      }  

以上有部分转自:http://zhiweiofli.iteye.com/blog/1830321

举个例子

MainActivity.java

protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    /*     * 1\ Java call function from JNI(nativeCallBack)    * 2\ JNI then will call function from java(callback_func)    * */    int ret = TextJNI.nativeCallBack("ok");    if (ret == 1)        ((TextView)findViewById(R.id.text2)).setText("nativecallback ok");}public int callback_func(String str){    Log.v("va", "hello" + str);    return 1;}

TextJNI.java

public class TextJNI {    static {        System.loadLibrary("jniInterface");    }    public static native int nativeCallBack(String str);}

com_example_androidjni_TextJNI.cpp

JNIEXPORT jint JNICALL Java_com_example_androidjni_TextJNI_nativeCallBack  (JNIEnv *env, jclass cls, jstring str){    jclass clz = env->FindClass("com/example/androidjni/MainActivity");    jmethodID mid = env->GetMethodID(clz, "callback_func", "(Ljava/lang/String;)I");    jobject obj = env->NewObject(clz, mid);    return env->CallIntMethod(obj, mid, str);}
0 0
原创粉丝点击