主要是分调用java中的static函数和非static函数。
本地activity code:
public class TestJNIActivity extends Activity {
private static final String TAG = "TestJNIActivity";
static{
System.loadLibrary("shift_jni");
}
TestJNI jni = new TestJNI();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button test1 = (Button)findViewById(R.id.test1);
test1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
test1();
}
});
Button test2 = (Button)findViewById(R.id.test2);
test2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
test2();
}
});
Button test3 = (Button)findViewById(R.id.test3);
test3.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
test3();
}
});
}
private void test1(){
Log.d(TAG, "=====call c method======"+jni.test1());
}
private void test2(){
Log.d(TAG, "=====c call java static method======"+jni.test2());
}
private void test3(){
Log.d(TAG, "=====c call java not static method======");
jni.test3();
}
}
本地java code:
public class TestJNI {
private static final String TAG = "TestJNI";
public native int printJNI();
public native int callJavaMethod1();
public native void callJavaMethod2();
/**
* java call c method by jni
*/
public int test1(){
return printJNI();
}
public int test2(){
return callJavaMethod1();
}
public void test3(){
callJavaMethod2();
}
/**
* c call java static method by jni
*/
public static int method1(){
Log.d(TAG, "===method1=====");
return 0;
}
public void method2(String msg){
Log.d(TAG, "===method2===="+msg);
}
}
native code:
#include
#include
#include "test_jni.h"
#include "c2java.h"
/*
#include "com_shift_testjni_TestJNI.h"
JNIEXPORT jint JNICALL Java_com_shift_testjni_TestJNI_printJNI (JNIEnv *env, jobject obj)
{
ALOGE("====jni test successfully===");
return 0;
}*/
JNIEXPORT jint JNICALL printForTest (JNIEnv *env, jobject obj)
{
LOGD("====printForTest===");
return 0;
}
JNIEXPORT jint JNICALL callStaticMethod (JNIEnv *env, jobject obj)
{
int ret = c_2_static_java(env);
LOGD("====callStaticMethod==%d===", ret);
return ret;
}
JNIEXPORT void JNICALL callNonstaticMethod (JNIEnv *env, jobject obj)
{
LOGD("====callNonstaticMethod==%d===", c_2_nonstatic_java(env));
}
static JNINativeMethod methods[] = {
{ "printJNI", "()I", (void*)printForTest},
{ "callJavaMethod1", "()I", (void*)callStaticMethod},
{ "callJavaMethod2", "()V", (void*)callNonstaticMethod},
};
/*
* Register methods for one class.
*/
static int registerNativeMethods(JNIEnv* env, const char* className,
const JNINativeMethod* methods, int numMethods)
{
int rc;
jclass clazz;
clazz = (*env)->FindClass(env, className);
if (clazz == NULL) {
LOGE("Native registration unable to find class '%s'\n", className);
return JNI_FALSE;
}
if (rc = ((*env)->RegisterNatives(env, clazz, methods, numMethods)) < 0) {
LOGE("RegisterNatives failed for '%s' %d\n", className, rc);
return JNI_FALSE;
}
return JNI_TRUE;
}
/*
* Register methods for all classes.
*
* returns JNI_TRUE on success.
*/
static int registerNatives(JNIEnv* env)
{
if (!registerNativeMethods(env, "com/shift/testjni/TestJNI", methods, NELEM(methods))){
return JNI_FALSE;
}
return JNI_TRUE;
}
/*
* Called by the VM when the shared library is loaded.
*/
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv* env = NULL;
jint result = -1;
LOGD("=====JNI_OnLoad=====\n");
if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK)
goto bail;
assert(env != NULL);
if (!registerNatives(env))
goto bail;
/* success -- return valid version number */
result = JNI_VERSION_1_6;
bail:
LOGE("Leaving JNI_OnLoad (result=0x%x)\n", result);
return result;
}
之前的code都是很ok的,之前Android基础总结九:JNI详解已经有过介绍。
但是实现部分的code在书写调试过程中出现了问题:
#include
#include "c2java.h"
#include "test_jni.h"
jclass TestJNI;
jobject mTestJNI;
jmethodID c2static;
jmethodID c2nonstatic;
int init(JNIEnv *env)
{
LOGD("====init=====");
if(TestJNI == NULL)
{
TestJNI = (*env)->FindClass(env, "com/shift/testjni/TestJNI");
if(TestJNI == NULL)
return -1;
}
if(mTestJNI == NULL)
{
if(getInstance(env) != 1)
{
(*env)->DeleteLocalRef(env, TestJNI);
return -2;
}
}
if(c2static == NULL)
{
c2static = (*env)->GetStaticMethodID(env, TestJNI, "method1", "()I");
if(c2static == NULL)
{
(*env)->DeleteLocalRef(env, TestJNI);
(*env)->DeleteLocalRef(env, mTestJNI);
return -3;
}
}
if(c2nonstatic ==NULL)
{
c2nonstatic = (*env)->GetMethodID(env, TestJNI, "method2", "(Ljava/lang/String;)V");
if(c2nonstatic == NULL)
{
(*env)->DeleteLocalRef(env, TestJNI);
(*env)->DeleteLocalRef(env, mTestJNI);
(*env)->DeleteLocalRef(env, c2static);
return -4;
}
}
return JNI_OK;
}
int getInstance(JNIEnv *env){
LOGD("====getInstance====");
jmethodID id = (*env)->GetMethodID(env, TestJNI, "", "()V");//默认构造函数,不传参数
if(id == 0)
return -1;
mTestJNI = (*env)->NewObject(env, TestJNI, id);//通过NewObject来创建对象
if(mTestJNI == NULL)
return -2;
return 1;
}
int c_2_static_java(JNIEnv *env)
{
int result = -1;
if(env == NULL)
{
return result;
}
if(TestJNI==NULL || c2static==NULL)
{
result = init(env);
if(result != JNI_OK)
return result;
}
jint java_ret = (*env)->CallStaticIntMethod(env, TestJNI, c2static);//CallStatic***Method,关键字static,***代表返回类型
LOGD("==c_2_static_java==%d=", java_ret);
return JNI_OK;
}
int c_2_nonstatic_java(JNIEnv *env)
{
int result = -1;
if(env == NULL)
{
return result;
}
if(TestJNI==NULL || mTestJNI==NULL || c2nonstatic==NULL)
{
result = init(env);
if(result != JNI_OK)
return result;
}
jstring jstrMSG = NULL;
jstrMSG =(*env)->NewStringUTF(env, "I'm From C");
(*env)->CallVoidMethod(env, mTestJNI, c2nonstatic, jstrMSG);//Call***Method,***代表返回类型
(*env)->DeleteLocalRef(env, jstrMSG);
return JNI_OK;
}
c2java中如果这样写的话,会出现一个问题,第一次调用java函数时是ok的,但是第二次调用就会出现:
05-20 07:01:50.048: D/Shift_Test_JNI(13050): ====printForTest===
05-20 07:01:50.048: D/TestJNIActivity(13050): =====call c method======0
05-20 07:01:50.958: D/Shift_Test_JNI(13050): ====init=====
05-20 07:01:50.978: D/Shift_Test_JNI(13050): ====getInstance====
05-20 07:01:50.978: D/TestJNI(13050): ===method1=====
05-20 07:01:50.978: D/Shift_Test_JNI(13050): ==c_2_static_java==0=
05-20 07:01:50.978: D/Shift_Test_JNI(13050): ====callStaticMethod==0===
05-20 07:01:50.978: D/TestJNIActivity(13050): =====c call java static method======0
05-20 07:01:54.568: E/dalvikvm(13050): JNI ERROR (app bug): accessed stale local reference 0xd7d0001d (index 7 in a table of size 7)
05-20 07:01:54.568: W/dalvikvm(13050): JNI WARNING: jclass is an invalid local reference (0xd7d0001d) (CallStaticIntMethod)
05-20 07:01:54.568: W/dalvikvm(13050): in Lcom/shift/testjni/TestJNI;.callJavaMethod1:()I (CallStaticIntMethod)
05-20 07:01:54.578: I/dalvikvm(13050): "main" prio=5 tid=1 RUNNABLE
05-20 07:01:54.578: I/dalvikvm(13050): | group="main" sCount=0 dsCount=0 obj=0xb3b03ca8 self=0xb8e0c398
05-20 07:01:54.578: I/dalvikvm(13050): | sysTid=13050 nice=0 sched=0/0 cgrp=apps handle=-1224810156
05-20 07:01:54.578: I/dalvikvm(13050): | state=R schedstat=( 960000000 1800000000 263 ) utm=65 stm=31 core=0
05-20 07:01:54.578: I/dalvikvm(13050): at com.shift.testjni.TestJNI.callJavaMethod1(Native Method)
05-20 07:01:54.618: I/dalvikvm(13050): at com.shift.testjni.TestJNI.test2(TestJNI.java:19)
05-20 07:01:54.618: I/dalvikvm(13050): at com.shift.testjni.TestJNIActivity.test2(TestJNIActivity.java:53)
05-20 07:01:54.618: I/dalvikvm(13050): at com.shift.testjni.TestJNIActivity.access$1(TestJNIActivity.java:52)
05-20 07:01:54.618: I/dalvikvm(13050): at com.shift.testjni.TestJNIActivity$2.onClick(TestJNIActivity.java:34)
05-20 07:01:54.618: I/dalvikvm(13050): at android.view.View.performClick(View.java:4438)
05-20 07:01:54.618: I/dalvikvm(13050): at android.view.View$PerformClick.run(View.java:18422)
05-20 07:01:54.618: I/dalvikvm(13050): at android.os.Handler.handleCallback(Handler.java:733)
05-20 07:01:54.628: I/dalvikvm(13050): at android.os.Handler.dispatchMessage(Handler.java:95)
05-20 07:01:54.628: I/dalvikvm(13050): at android.os.Looper.loop(Looper.java:136)
05-20 07:01:54.628: I/dalvikvm(13050): at android.app.ActivityThread.main(ActivityThread.java:5017)
05-20 07:01:54.628: I/dalvikvm(13050): at java.lang.reflect.Method.invokeNative(Native Method)
05-20 07:01:54.628: I/dalvikvm(13050): at java.lang.reflect.Method.invoke(Method.java:515)
05-20 07:01:54.628: I/dalvikvm(13050): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
05-20 07:01:54.628: I/dalvikvm(13050): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
05-20 07:01:54.628: I/dalvikvm(13050): at dalvik.system.NativeStart.main(Native Method)
05-20 07:01:54.628: E/dalvikvm(13050): VM aborting
05-20 07:01:54.648: A/libc(13050): Fatal signal 6 (SIGABRT) at 0x000032fa (code=-6), thread 13050 (m.shift.testjni)
后来查了很多资料,才弄清楚,在c返回java的时候LocalRef都会释放。这样导致了指针的游离,下一次使用就不行了。
后来只能采用GlobalRef,试验证明这样做是ok的。
code如下:
#include
#include
#include
#ifndef _C_TO_JAVA_H_
#define _C_TO_JAVA_H_
struct fields_t {
jclass TestJNI;
jobject mTestJNI;
jmethodID c2static;
jmethodID c2nonstatic;
};
int c_2_static_java(JNIEnv *env);
int c_2_nonstatic_java(JNIEnv *env);
#endif
#include
#include "c2java.h"
#include "test_jni.h"
static struct fields_t fields;
int getInstance(JNIEnv *env)
{
LOGD("====getInstance====");
jmethodID id = (*env)->GetMethodID(env, fields.TestJNI, "", "()V");
if(id == 0)
return -1;
jobject temp = (*env)->NewObject(env, fields.TestJNI, id);
if(temp == NULL)
return -2;
fields.mTestJNI = (*env)->NewGlobalRef(env, temp);
(*env)->DeleteLocalRef(env, temp);
return 1;
}
int native_init(JNIEnv *env)
{
LOGD("====init=====");
if(fields.TestJNI == NULL)
{
jclass temp = (*env)->FindClass(env, "com/shift/testjni/TestJNI");
if(temp == NULL)
return -1;
fields.TestJNI = (jclass)(*env)->NewGlobalRef(env, temp);
(*env)->DeleteLocalRef(env, temp);
}
if(fields.mTestJNI == NULL)
{
if(getInstance(env) != 1)
{
(*env)->DeleteGlobalRef(env, fields.TestJNI);
return -2;
}
}
if(fields.c2static == NULL)
{
fields.c2static = (*env)->GetStaticMethodID(env, fields.TestJNI, "method1", "()I");
if(fields.c2static == NULL)
{
(*env)->DeleteGlobalRef(env, fields.TestJNI);
(*env)->DeleteGlobalRef(env, fields.mTestJNI);
return -3;
}
}
if(fields.c2nonstatic ==NULL)
{
fields.c2nonstatic = (*env)->GetMethodID(env, fields.TestJNI, "method2", "(Ljava/lang/String;)V");
if(fields.c2nonstatic == NULL)
{
(*env)->DeleteGlobalRef(env, fields.TestJNI);
(*env)->DeleteGlobalRef(env, fields.mTestJNI);
(*env)->DeleteLocalRef(env, fields.c2static);
return -4;
}
}
return JNI_OK;
}
int c_2_static_java(JNIEnv *env)
{
int result = -1;
if(env == NULL)
{
return result;
}
if(fields.TestJNI==NULL || fields.c2static==NULL)
{
result = native_init(env);
if(result != JNI_OK)
return result;
}
jint java_ret = (*env)->CallStaticIntMethod(env, fields.TestJNI, fields.c2static);
LOGD("==c_2_static_java==%d=", java_ret);
return JNI_OK;
}
int c_2_nonstatic_java(JNIEnv *env)
{
int result = -1;
if(env == NULL)
{
return result;
}
if(fields.TestJNI==NULL || fields.mTestJNI==NULL || fields.c2nonstatic==NULL)
{
result = native_init(env);
if(result != JNI_OK)
return result;
}
jstring jstrMSG = NULL;
jstrMSG =(*env)->NewStringUTF(env, "I'm From C");
(*env)->CallVoidMethod(env, fields.mTestJNI, fields.c2nonstatic, jstrMSG);
(*env)->DeleteLocalRef(env, jstrMSG);
return JNI_OK;
}
注意:
1. jmethodID id = (*env)->GetMethodID(env, TestJNI, "
2. mTestJNI = (*env)->NewObject(env, TestJNI, id);//通过NewObject来创建对象
3. jint java_ret = (*env)->CallStaticIntMethod(env, TestJNI, c2static);//CallStatic***Method,关键字static,***代表返回类型
4. (*env)->CallVoidMethod(env, mTestJNI, c2nonstatic, jstrMSG);//Call***Method,***代表返回类型
5. 前面的几个函数中都会涉及到变量env,而env是java调用c函数时的第一个参数,这意味着c调用java函数只能在java调用c函数中进行,否则无法获取env变量。也就是说c是不能主动调用java函数的。
参考:
http://www.ibm.com/developerworks/cn/java/j-lo-jnileak/index.html?ca=drs-