JNI之------C调用java接口

主要是分调用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 <jni.h>
#include <assert.h>

#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 <jni.h>
#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, "<init>", "()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 <jni.h>
#include <stdio.h>
#include <string.h>

#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 <jni.h>
#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, "<init>", "()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, "<init>", "()V");//默认构造函数,不传参数

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-

 

 

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

私房菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值