android NDK开发 静态/动态注册 jni

关于jni有两种方法注册 分别为 静态注册和动态注册
首先 来看看静态注册 所谓的静态注册 就是直接在Java文件里写个native方法 然后再c/c++文件中实现这个方法就行了!来看看代码:

package com.example.ndk_test;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;

public class MainActivity extends ActionBarActivity {
	
	//调用加载LIB库
	static{
		System.loadLibrary("ndk_test");
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		//调用方法 该方法是c或者c++实现
		testJni();
		
	}
//声明为本地方法
	public native void testJni();
}
看看本地方法的实现  这里为了测试 直接打印一个 “hello”

#include <jni.h>
#include <stdlib.h>
#include<android/log.h>//包含Android log打印   需要再make文件中添加  LOCAL_LDLIBS := -llog
#include"com_example_ndk_test_MainActivity.h"

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "NDK_TEST", __VA_ARGS__)//为了使用方便 直接定义一个宏
/*
 * Class:     com_example_ndk_test_MainActivity  类名
 * Method:    testJni    方法名
 * Signature: ()V        方法签名
 */
JNIEXPORT void JNICALL Java_com_example_ndk_1test_MainActivity_testJni
  (JNIEnv * env, jobject clazz){
       //直接打印hello
	LOGD("hello");

}
再来看看make文件

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := ndk_test
LOCAL_SRC_FILES := ndk_test.cpp
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)

运行来测试下 看看效果如何:


是不是很简单


然后我们再看看怎么用c/c++代码调用Java代码呢 :

再原有的代码上继续

package com.example.ndk_test;

import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.os.Bundle;

public class MainActivity extends ActionBarActivity {
	private static final String LOG ="NDK_TEST";
	
	//调用加载LIB库
	static{
		System.loadLibrary("ndk_test");
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		//调用方法 该方法是c或者c++实现
		testJni();
		
	}
     //声明为本地方法
	public native void testJni();
	//声明一个Java方法 用本地方法来调用
	public void getName(){
		Log.i(LOG, "调用了getName()");
	}
}

再看看本地方法的实现 


#include <jni.h>
#include <stdlib.h>
#include<android/log.h>//包含Android log打印   需要再make文件中添加  LOCAL_LDLIBS := -llog
#include"com_example_ndk_test_MainActivity.h"

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "NDK_TEST", __VA_ARGS__)//为了使用方便 直接定义一个宏

jmethodID getNameID;
jclass mainActivity;

	void callJava(JNIEnv *env,jobject obj){
		    mainActivity= env->FindClass("com/example/ndk_test/MainActivity");
			getNameID=env->GetMethodID(mainActivity,"getName","()V");
			env->CallVoidMethod(obj,getNameID);
	}

/*
 * Class:     com_example_ndk_test_MainActivity  类名
 * Method:    testJni    方法名
 * Signature: ()V        方法签名
 */
JNIEXPORT void JNICALL Java_com_example_ndk_1test_MainActivity_testJni
  (JNIEnv * env, jobject obj){
       //直接打印hello
	LOGD("hello");
	callJava(env,obj);
}

看看执行结果

这样的话 本地代码和Java就可以相互调用了!

那如果我现在要调用Java的静态方法呢 ?

 直接使用 void CallStaticVoidMethod(jclass clazz, jmethodID methodID)

如果调用有返回值的方法呢?

好了直接看这里:CallXXXMethod 函数和CallStaticXXXMethod函数,XXX表明了方法的返回值类型。这些函数的变体允许传递数组参数 (CallXXXMethodA and CallStaticXXXMethodA)或者传递一个可变大小的列表(CallXXXMethodV and CallStaticXXXMethodV)。

那怎么获取/设置Java代码里面的全局变量呢?

//获取Java全局变量
void getFild(JNIEnv *env,jobject obj){
	ifild= env->GetFieldID(mainActivity,"ifiled","I");
	 jint fid=env->GetIntField(obj,ifild);//获取
	 LOGI("%d",fid);
        env->SetIntField(obj,ifild,10);//修改变量的值
}

现在来看看动态注册jni

动态注册好处是不要写很长的方法名,用jni_onload方法实现预注册 即当执行system.loadLibrary()方法时候就把需要调用的方法给注册了,效率要高 Android就是采用此方法;

  那么首先得重写jni_onload方法了

//实现jni_onload 动态注册方法
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
	JNIEnv* env = NULL;
	if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
		return -1;
	}
	if(registerNativeMeth(env)!=JNI_OK){//注册方法
		return -1;
	}
        return JNI_VERSION_1_4;//必须返回这个值
}

再来看看注册的方法:

 //注册Java端的方法  以及本地相对应的方法
 JNINativeMethod method[]={{"test2","()V",(void*)native_test2},{"test3","()I",(int*)native_test3}};

 //注册相应的类以及方法
 jint registerNativeMeth(JNIEnv *env){
     jclass cl=env->FindClass("com/example/ndk_test/MainActivity");
     if((env->RegisterNatives(cl,method,sizeof(method)/sizeof(method[0])))<0){
    	 return -1;
     }
       return 0;
 }
这样的话就是当 Java端调用test2的时候就会调用到本地方法的 native_test2方法了  同理 test3也是一样的,注册方法主要是调用虚拟机的 RegisterNatives方法 

现在来看看 完整的代码:

首先是Java端:

package com.example.ndk_test;

import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.os.Bundle;

public class MainActivity extends ActionBarActivity {
	private static final String LOG ="NDK_TEST";
	private int ifiled=3;
	private String name;
	
	//调用加载LIB库
	static{
		System.loadLibrary("ndk_test");
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		//调用方法 该方法是c或者c++实现
		testJni();
		Log.i(LOG,"java變量--"+ifiled);
		Log.i(LOG,"test3执行="+test3());
	}
     //声明为本地方法
	public native void testJni();
	//声明一个Java方法 用本地方法来调用
	public void getName(){
		Log.i(LOG, "调用了getName()");
		test2();
	}
	//声明为本地方法
	public native void test2();
	public native int test3();
	
}

再来是cpp的代码:

#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include<android/log.h>//包含Android log打印   需要再make文件中添加  LOCAL_LDLIBS := -llog
#include"com_example_ndk_test_MainActivity.h"

#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "ndk_test", __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO  , "ndk_test", __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN  , "ndk_test", __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR  , "ndk_test", __VA_ARGS__)
jmethodID getNameID;
jfieldID ifild;
jclass mainActivity;

//調用Java方法
void callJava(JNIEnv *env, jobject obj) {
	mainActivity = env->GetObjectClass(obj); //("com/example/ndk_test/MainActivity");
	getNameID = env->GetMethodID(mainActivity, "getName", "()V");
	env->CallVoidMethod(obj, getNameID);
}

//获取Java全局变量
void getFild(JNIEnv *env, jobject obj) {
	ifild = env->GetFieldID(mainActivity, "ifiled", "I");
	jint fid = env->GetIntField(obj, ifild);
	LOGI("%d", fid);
	env->SetIntField(obj, ifild, 10); //修改变量的值

}

/*
 * Class:     com_example_ndk_test_MainActivity  类名
 * Method:    testJni    方法名
 * Signature: ()V        方法签名
 */JNIEXPORT void JNICALL Java_com_example_ndk_1test_MainActivity_testJni(
		JNIEnv * env, jobject obj) {
	//直接打印hello
	LOGI("hello");
	callJava(env, obj);
	getFild(env, obj);
}
//替换java端的test2
 void native_test2(){
	 LOGI("native_test2");
 }
 //替换java端的test3
 int native_test3(){
	 return 190;
 }
 //注册Java端的方法  以及本地相对应的方法
 JNINativeMethod method[]={{"test2","()V",(void*)native_test2},{"test3","()I",(int*)native_test3}};

 //注册相应的类以及方法
 jint registerNativeMeth(JNIEnv *env){
     jclass cl=env->FindClass("com/example/ndk_test/MainActivity");
     if((env->RegisterNatives(cl,method,sizeof(method)/sizeof(method[0])))<0){
    	 return -1;
     }
       return 0;
 }
//实现jni_onload 动态注册方法
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
	JNIEnv* env = NULL;
	if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
		return -1;
	}
	if(registerNativeMeth(env)!=JNI_OK){//注册方法
		return -1;
	}
        return JNI_VERSION_1_4;//必须返回这个值
}

最终结果:



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值