jni_method.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_jnitest_TestJniMethods */
#ifndef _JNI_METHOD_H_
#define _JNI_METHOD_H_
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_jnitest_TestJniMethods
* Method: test
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_example_jnitest_TestJniMethods_test
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
#include <jni.h>
#include <string.h>
#include <android/log.h>
#include "jni_method.h"
#include <pthread.h>
/*
* 定义LOG函数
*/
#define TAG "JniMethod"
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL, TAG, __VA_ARGS__)
#ifndef NELEM
#define NELEM(x) ((int)(sizeof(x) / sizeof((x)[0])))
#endif
// 全局变量
JNIEnv *g_env;
jclass native_class;
JavaVM *g_vm;
pthread_mutex_t thread_mutex;
/*
* Class: com_example_jnitest_TestJniMethods
* Method: test
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_example_jnitest_TestJniMethods_test(JNIEnv *env, jobject object)
{
int version = env->GetVersion();
LOGV("GetVersion() --> jni version:%2x", version);
jclass build_class = env->FindClass("android/os/Build"); // 加载一个本地类
jfieldID brand_id = env->GetStaticFieldID(build_class, "MODEL", "Ljava/lang/String;"); // 获取类的静态字段ID
jstring brand_obj = (jstring)env->GetStaticObjectField(build_class, brand_id); // 获取类的静态字段的值
const char* nativeString = env->GetStringUTFChars(brand_obj, 0); // 通过jstring生成char*,转成UTF-8格式
LOGV("GetStringUTFChars() --> MODEL:%s", nativeString);
env->ReleaseStringUTFChars(brand_obj, nativeString); // 释放GetStringUTFChars()生成的char*
jclass test_class = env->FindClass("com/example/jnitest/TestClass");
if(env->ExceptionCheck())
{
env->ExceptionDescribe(); // 输出异常
env->ExceptionClear(); // 清除异常
LOGE("ExceptionCheck()");
LOGE("ExceptionDescribe()");
LOGE("ExceptionClear()");
return;
}
jmethodID constructor = env->GetMethodID(test_class, "<init>", "()V"); // 获取构造函数
/*
* 创建对象的第一种方法,调用NewObject,把构造函数当成参数传递进去
*/
jobject obj = env->NewObject(test_class, constructor); // 创建一个对象,当构造函数当成参数传递进去
jthrowable throwable = env->ExceptionOccurred(); // 获取异常对象,如果没异常发生返回NULL
if (throwable) // 有异常发生,也可以使用ExceptionCheck()函数来判断
{
env->ExceptionDescribe();
env->ExceptionClear();
LOGE("ExceptionOccurred()");
}
if (obj)
{
env->MonitorEnter(obj); // 同步操作
jfieldID stringfieldID = env->GetFieldID(test_class, "aStringField", "Ljava/lang/String;"); // 获取String类型的字段aStringField
jstring stringfieldValue = (jstring)env->GetObjectField(obj, stringfieldID); // 获取aStringField字段的值
const char *stringValue = env->GetStringUTFChars(stringfieldValue, 0);
LOGV("GetObjectField() --> aStringField:%s", stringValue);
env->ReleaseStringUTFChars(stringfieldValue, stringValue);
const char* myValue = "def";
env->SetObjectField(obj, stringfieldID, env->NewStringUTF(myValue)); // 设置字段的值
LOGV("SetObjectField() --> aStringField:def");
jfieldID intfieldID = env->GetFieldID(test_class, "aIntField", "I"); // 获取int类型的字段aIntField
jint fieldValue = env->GetIntField(obj, intfieldID); // 获取aIntField字段的值
LOGV("GetIntField() --> aField:%d", fieldValue);
env->SetIntField(obj, intfieldID, (jint)123); // 设置int字段的值
fieldValue = env->GetIntField(obj, intfieldID);
LOGV("SetIntField() --> aField:%d", fieldValue);
jclass parent_class = env->GetSuperclass(test_class); // 获取父类
LOGV("GetSuperClass() --> ");
if (JNI_OK == env->EnsureLocalCapacity(5)) // 检测是否还可以创建5个局部引用
{
LOGV("EnsureLocalCapacity() --> ensure 5 locals");
jmethodID obj2_voidmethod = env->GetMethodID(test_class, "aVoidMethod", "()V"); // 获取一个void方法
env->CallVoidMethod(obj, obj2_voidmethod);
LOGV("CallVoidMethod()");
jmethodID obj2_Staticmethod = env->GetStaticMethodID(test_class, "aStaticMethod", "(Ljava/lang/String;)V"); // 获取一个static方法
LOGV("GetStaticMethodID()");
const char* fromJni = "this string from jni";
jstring jstr_static = env->NewStringUTF(fromJni); // char*转jstring
env->CallStaticVoidMethod(test_class, obj2_Staticmethod, jstr_static); // 调用一个静态方法
jmethodID obj2_chinesemethod = env->GetMethodID(test_class, "getChineseString", "()Ljava/lang/String;"); // 传递中文字符串
jstring obj2_chinesejstring = (jstring)env->CallObjectMethod(obj, obj2_chinesemethod);
jsize chinese_size = env->GetStringLength(obj2_chinesejstring); // 返回Java字符串的长度(Unicode 字符数)
LOGV("GetStringLength() --> %d", chinese_size);
jchar buff_jchar[4] = {0};
env->GetStringRegion(obj2_chinesejstring, 0, 3, buff_jchar); // bufchar的值是啥
LOGV("GetStringRegion() --> 特别关注");
const jchar* obj2_chinesechars = env->GetStringChars(obj2_chinesejstring, NULL); // jstring转char*,转成Unicode格式
jstring new_chinesestring = env->NewString(obj2_chinesechars, chinese_size);
env->CallStaticVoidMethod(test_class, obj2_Staticmethod, new_chinesestring);
env->ReleaseStringChars(obj2_chinesejstring, obj2_chinesechars); // 释放GetStringChars获取的jchar*
LOGV("CallStaticVoidMethod()");
jmethodID obj2_sqrtmethod = env->GetStaticMethodID(test_class, "sqrt", "(I)I");
jint int_sqrt = env->CallStaticIntMethod(test_class, obj2_sqrtmethod, (jint)5); // 计算5的平方
LOGV("CallStaticIntMethod() -->5 sqrt is:%d", int_sqrt);
}
if (JNI_TRUE == env->IsAssignableFrom(test_class, parent_class)) // 判断test_class类型是否可安全地强制转换为parent_class类型
{
LOGV("IsAssignableFrom() --> yes");
}
else
{
jclass newExceptionClazz = env->FindClass("java/lang/RuntimeException"); // 获取一个异常类型
if (newExceptionClazz != NULL)
{
env->ThrowNew(newExceptionClazz, "这里不会被执行"); // 实例化异常对象并抛出该异常
LOGE("ThrowNew()");
}
}
jclass obj_clazz = env->GetObjectClass(obj); // 获取对象的类型
if (JNI_TRUE == env->IsInstanceOf(obj, obj_clazz)) // 测试对象是否为某个类的实例
{
LOGV("IsInstanceOF() --> Yes");
}
else
{
env->FatalError("fatal error!"); // 抛出致命错误并且不希望虚拟机进行修复
LOGE("FatalError()");
}
env->PushLocalFrame(2); // 申请局部引用空间
jobject obj_localref = env->NewLocalRef(obj); // 创建一个局部引用
jobject obj_globalref = env->NewGlobalRef(obj); // 创建一个全局引用
LOGV("PushLocalFrame()");
LOGV("NewLocalRef()");
LOGV("NewGlobalRef()");
if (JNI_TRUE == env->IsSameObject(obj_localref, obj_globalref)) // 测试两个引用是否引用同一个Java对象
{
LOGV("IsSameObject() --> Yes");
}
env->DeleteLocalRef(obj_localref); // 删除一个局部引用
env->DeleteGlobalRef(obj_globalref); // 删除一个全局引用
env->PopLocalFrame(NULL); // 释放前面申请的局部引用空间
LOGV("DeleteLocalRef()");
LOGV("DeleteGlobalRef()");
LOGV("PopLocalFrame()");
env->MonitorExit(obj); // 离开临界区
}
jclass sub_class = env->FindClass("com/example/jnitest/TestSubClass");
/*
* 创建对象的第二种方法,直接给对象分配内存,(再手动调用构造函数,也可以不调用)
*/
jobject sub_obj = env->AllocObject(sub_class); // 分配内存
jmethodID sub_methodID = env->GetMethodID(sub_class, "aVoidMethod", "()V");
env->CallNonvirtualVoidMethod(sub_obj, sub_class, sub_methodID); // 调用子类里的方法
env->CallNonvirtualVoidMethod(sub_obj, test_class, sub_methodID); // 根据调用类的不同调用父类的方法
jfieldID sub_fieldID = env->GetStaticFieldID(sub_class, "subFloatField", "F"); // 获取子类静态字段
env->SetStaticFloatField(sub_class, sub_fieldID, (jfloat)33.88f);
LOGV("SetStaticFloatField() --> %.2f", env->GetStaticFloatField(sub_class, sub_fieldID));
jclass class_string = env->FindClass("java/lang/String");
jobjectArray string_array = env->NewObjectArray(3, class_string, 0); // 创建String数组
LOGV("NewObjectArray()");
jsize array_size = env->GetArrayLength(string_array); // 获取数组中元素的个数
LOGV("GetArrayLength() --> %d", array_size);
jstring array_string1 = env->NewStringUTF("one");
char buff_char[4] = {0};
env->GetStringUTFRegion(array_string1, 0, 3, buff_char);
LOGV("GetStringUTFRegion() --> %s", buff_char);
env->SetObjectArrayElement(string_array, 0, array_string1); // 设置数组元素的值
LOGV("SetObjectArrayElement() --> one");
array_string1 = (jstring)env->GetObjectArrayElement(string_array, 0); // 获取数组元素的值
const char* array_elemchars = env->GetStringUTFChars(array_string1, NULL);
LOGV("GetObjectArrayElement() --> %s", array_elemchars);
env->ReleaseStringUTFChars(array_string1, array_elemchars);
jintArray int_array = env->NewIntArray(5); // 创建int数组
LOGV("NewIntArray() --> %d", env->GetArrayLength(int_array)); // 获取数组长度
const jint ints[] = {11, 12, 13, 14, 15};
env->SetIntArrayRegion(int_array, 0, 5, ints); // 设置数组一个范围的值
LOGV("SetIntArrayRegion() --> %d,%d,%d,%d,%d",
ints[0], ints[1], ints[2], ints[3], ints[4]);
jint ints2[2] = {0, 0};
env->GetIntArrayRegion(int_array, 1, 2, ints2); // 获取数组一个范围的值
LOGV("GetIntArrayRegion() --> %d,%d", ints2[0], ints2[1]);
jint* array_ints = env->GetIntArrayElements(int_array, NULL); // 返回指向所有元素的指针
LOGV("GetIntArrayElements() --> %d,%d,%d,%d,%d",
array_ints[0], array_ints[1], array_ints[2], array_ints[3], array_ints[4]);
env->ReleaseIntArrayElements(int_array, array_ints, 0); // 释放指向所有元素的指针
LOGV("ReleaseIntArrayElements()");
}
JNIEXPORT jstring nativeMethod(JNIEnv* env, jobject object)
{
const char* chs = "你好!NativeMethod";
return env->NewStringUTF(chs);
}
// 线程函数
void* thread_func(void *arg)
{
JNIEnv *env;
pthread_mutex_lock(&thread_mutex); // 锁定互斥锁
if (JNI_OK != g_vm->AttachCurrentThread(&env, NULL)) // 附加当前线程到Java(Dalvik)虚拟机,一个线程必须附加到虚拟机,在任何其他JNI可调用之前
{
LOGE("AttachCurrentThread() failed");
return NULL;
}
LOGV("AttachCurrentThread() --> thread:%d", (jint)arg);
g_vm->DetachCurrentThread(); // 分离当前线程,退出虚拟机之前,线程必须被分离
LOGV("DetachCurrentThread() --> thread:%d", (jint)arg);
pthread_mutex_unlock(&thread_mutex); // 释放互斥锁
pthread_exit(0);
return NULL;
}
JNIEXPORT void newJniThreads(JNIEnv* env, jobject obj, jint nums)
{
env->GetJavaVM(&g_vm); // 获取和当前线程相关的JavaVM
pthread_t* pt = (pthread_t*)malloc(sizeof(pthread_t) * nums); // 分配空间
pthread_mutex_init(&thread_mutex, NULL); // 初始化线程互斥锁
int i;
for (i = 0; i < nums; ++i)
{
pthread_create(&pt[i], NULL, &thread_func, (void*)i); // 创建线程
}
free(pt);
}
JNIEXPORT jobject allocNativeBuffer(JNIEnv* env, jobject obj, jlong size)
{
void* buffer = malloc(size);
jobject directBuffer = env->NewDirectByteBuffer(buffer, size);
LOGV("NewDirectByteBuffer() --> %d",(int)size);
return directBuffer;
}
JNIEXPORT void freeNativeBuffer(JNIEnv* env, jobject obj, jobject bufferRef)
{
char *buffer = (char*)env->GetDirectBufferAddress(bufferRef);
strcpy(buffer, "123");
LOGV("GetDirectBufferAddress() --> %s", buffer);
free(buffer);
}
static JNINativeMethod g_methods[] = {
{"nativeMethod", "()Ljava/lang/String;", (void*)nativeMethod},
{"newJniThreads", "(I)V", (void*)newJniThreads},
{"allocNativeBuffer", "(J)Ljava/lang/Object;", (void*)allocNativeBuffer},
{"freeNativeBuffer", "(Ljava/lang/Object;)V", (void*)freeNativeBuffer}
};
/*
* System.loadLibrary() 时调用
* 如果成功返回 JNI 版本,失败返回 -1
*/
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
if(JNI_OK != vm->GetEnv((void**)&g_env, JNI_VERSION_1_6)) // 加载指定版本的JNI
{
return -1;
}
LOGV("JNI_OnLoad()");
native_class = g_env->FindClass("com/example/jnitest/TestJniMethods");
if (JNI_OK == g_env->RegisterNatives(native_class, g_methods, NELEM(g_methods))) // 注册未声明的本地方法
{
LOGV("RegisterNatives() --> nativeMethod() ok");
}
else
{
LOGE("RegisterNatives() --> nativeMethod() failed");
return -1;
}
return JNI_VERSION_1_6;
}
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS := -llog
LOCAL_MODULE := jnitest
LOCAL_SRC_FILES := jni_method.cpp
include $(BUILD_SHARED_LIBRARY)
MainActivity.java
package com.example.jnitest;
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TestJniMethods methods = new TestJniMethods();
methods.test();
setTitle(methods.nativeMethod());
methods.newJniThreads(5); // 创建5个线程
Object obj = methods.allocNativeBuffer(16L); // 分配字节缓冲区
Toast.makeText(this, obj.getClass().getName(), Toast.LENGTH_LONG).show();
methods.freeNativeBuffer(obj); // 释放字节缓冲区
}
}
package com.example.jnitest;
public class TestJniMethods {
public native void test();
public native String nativeMethod();
public native void newJniThreads(int i);
public native Object allocNativeBuffer(long size);
public native void freeNativeBuffer(Object obj);
static {
System.loadLibrary("jnitest");
}
}
TestClass.java
package com.example.jnitest;
import android.util.Log;
public class TestClass {
protected static final String TAG = "JniMethod";
private int aIntField;
private String aStringField;
public TestClass() {
aIntField = 0;
aStringField = "abc";
}
public int getIntField() {
return aIntField;
}
public void setIntField(int aIntField) {
this.aIntField = aIntField;
}
public String getStringField() {
return aStringField;
}
public void setStringField(String aStringField) {
this.aStringField = aStringField;
}
public String getChineseString() {
return "你好,安卓!";
}
public void aVoidMethod() {
Log.v(TAG, "jni test a void method, this run in java");
}
public static void aStaticMethod(String str) {
Log.v(TAG, "jni test a static Method -->" + str);
}
public static int sqrt(int x) {
return x * x;
}
}
TestSubClass.java
package com.example.jnitest;
import android.util.Log;
public class TestSubClass extends TestClass{
private static float subFloatField = 3.8f;
public void aVoidMethod() {
Log.v(TAG, "jni test a void subclass method, this run in java");
}
public static void aStaticMethod(String str) {
Log.v(TAG, "jni test a static subclass Method -->" + str);
}
public static float getSubIntField() {
return subFloatField;
}
public static void setSubIntField(float subFloatField) {
TestSubClass.subFloatField = subFloatField;
}
}