非虫——JNI实例
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; } }
声明:该文观点仅代表作者本人,入门客AI创业平台信息发布平台仅提供信息存储空间服务,如有疑问请联系rumenke@qq.com。
- 上一篇:没有了
- 下一篇:没有了