一个初级例子讲述C和CPP在JNI中调用安卓Java代码

一般使用JNI都是调用C/C++代码的函数,但是很多时候在JNI中调用Java代码也是家常便饭。然后JNI中的C和C++的用法又略有不同,也在本博文中进行一次片段性的说一下。

目录结构就微微分为:
Java代码的实现
C代码的实现
CPP代码的实现
本案例中C和CPP代码的语法区别

Java代码的实现


其中jni.h是我拷贝进来做对比的。

MainActivity.java

public class MainActivity extends Activity {

	private Button button1;
	private TextView text1;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		button1 = (Button) findViewById(R.id.button1);
		text1 = (TextView) findViewById(R.id.text1);
		text1.setText("");
		final Jni jni = new Jni();
		jni.setJniCall(new onJniCall() {

			@Override
			public void onListenerJniCall(String str) {
				text1.append("#JniCall=" + str + "\n");
			}
		});
		button1.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				jni.call();
			}
		});
	}
}

Jni.java

public class Jni {

	private onJniCall jniCall;
	public native void call();

	public void setJniCall(onJniCall jniCall) {
		this.jniCall = jniCall;
	}

	public Jni() {
		System.loadLibrary("hello-jni");
	}

	private void onNative(String str) {
		if (jniCall != null) {
			jniCall.onListenerJniCall(str);
		}
	}

}


onJniCall.java

public interface onJniCall {

	public void onListenerJniCall(String str);
	
}
AndroidManifest.xml没有进行修改

生成头文件

com_jni_Jni.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_jni_Jni */

#ifndef _Included_com_jni_Jni
#define _Included_com_jni_Jni
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_jni_Jni
 * Method:    call
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_jni_Jni_call
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

C代码的实现

com_jni_Jni.c

#include <jni.h>

JNIEXPORT void JNICALL Java_com_jni_Jni_call
(JNIEnv * env, jobject obj) {

	jclass ClassCJM = (*env)->FindClass(env, "com/jni/Jni");
	jmethodID MethodDisplayMessage = (*env)->GetMethodID(env, ClassCJM, "onNative", "(Ljava/lang/String;)V");
	jstring value = (*env)->NewStringUTF(env, "Hello World!-I am Native Jni (C-Language)");
	(*env)->CallVoidMethod(env, obj, MethodDisplayMessage, value);

}


CPP代码的实现

com_jni_Jni.cpp

#include <jni.h>

extern "C" { //或者使用#include"com_jni_Jni_call.h"代替extern"C"
	JNIEXPORT void JNICALL Java_com_jni_Jni_call
	(JNIEnv * env, jobject obj) {
		//jclass ClassCJM = env->GetObjectClass(obj);//效果一样
		jclass ClassCJM = env->FindClass("com/jni/Jni");
		jmethodID MethodDisplayMessage = env->GetMethodID(ClassCJM, "onNative", "(Ljava/lang/String;)V");
		jstring value = env->NewStringUTF("Hello World!-I am Native Jni(CPP)");
		env->CallVoidMethod(obj, MethodDisplayMessage, value);		
	}
}

 关于这里的extern“C”的问题,引入头文件是因为头文件用了。不引入头文件的话,就手动在CPP代码中实现。 

百度了一段关于extern "C"的说法extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码

加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。 这个功能十分有用处,因为在C++出现以前,很多代码都是C语言写的,而且很底层的库也是C语言写的,为了更好的支持原来的C代码和已经写好的C语言库,需要在C++中尽可能的支持C,而extern "C"就是其中的一个策略。 

这个功能主要用在下面的情况:1、C++代码调用C语言代码2、在C++的头文件中使用3、在多个人协同开发时,可能有的人比较擅长C语言,而有的人擅长C++

如果没有用到extern "C",就会报错:

运行效果:

使用CPP文件进行的。

本案例中C和CPP代码的语法区别

C语言 :(*env)-> FindClass(env,"java/lang/ClassLoader");

CPP   : env->FindClass("java/lang/ClassLoader");

就这个简单的例子可以看出在CPP省略了一个参数,下面看一下原因:

在jni.h文件中看到:

#ifdef __cplusplus 
jmethodID GetMethodID(jclass clazz, const char *name,
		  const char *sig) {
return functions->GetMethodID(this,clazz,name,sig);
}
这里就是调用了C语言中的functions的方法,然后加入自己的参数this,所以虽然都是调用同一个函数,但是在CPP中调用的时候可以省略一个参数,这个省略的参数已经由CPP在jni.h中代劳了。

下面看一下env的指针问题:

(*env)-> FindClass(env,"java/lang/ClassLoader");
env->FindClass("java/lang/ClassLoader");

可以看到原因是:

struct JNIEnv_;

#ifdef __cplusplus
typedef JNIEnv_ JNIEnv;
#else
typedef const struct JNINativeInterface_ *JNIEnv;
#endif
OK,自我理解一下就好。C++的知识丢了很多,所以以后再把解释补上。

题外话:今天周五,接下来迎来中秋3天小假期,公司发福利,心情愉悦。

本文来自CSDN博客,转载请联系作者注明出处http://blog.csdn.net/dreamintheworld


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值