Android(安卓)NDK 学习之传递类对象
16lz
2021-12-04
本博客主要是在Ubuntu 下开发,且默认你已经安装了Eclipse,Android SDK, Android NDK, CDT插件。
在Eclipse中添加配置NDK,路径如下Eclipse->Window->Preferences->Android->NDK ,选择NDK的路径,然后Apply即可。
新建一个名为AndroidJNI_Object的Android工程,新建一个jni的文件夹,其目录下文件树列表如下:
├── jni
│ ├── Android.mk
│ ├── Application.mk
│ └── object
│ ├── Android.mk
│ ├── logger.h
│ └── object_jni.c
jni/Application.mk文件内容如下:
APP_ABI := all
jni/Android.mk,主要用来指定顺序执行所有子文件夹下面的makefile文件,内容如下:
include $(call all-subdir-makefiles)
jni/object/Android.mk,主要用来指定需要编译出的动态库的名称,以及需要编译的源文件,内容如下:
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := object_jniLOCAL_SRC_FILES := object_jni.cLOCAL_LDLIBS := -lloginclude $(BUILD_SHARED_LIBRARY)
jni/object/logger.h主要用来在JNI层打印日志,内容如下:
#include <jni.h>#include <android/log.h>/** * 定义log标签 */#define TAG "jni_logger"/** * 定义info信息 */#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)/** * 定义debug信息 */#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)/** * 定义error信息 */#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
jni/object/object_jni.c,主要用来注册绑定java函数和native函数,以及java函数在c中相应函数的具体实现, 内容如下:
#include "logger.h"#ifndef NULL#define NULL ((void *) 0)#endif/** * 获取数组的大小 */#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))/** * 指定要注册的类,对应的完整的java类名 */#define JNIREG_CLASS "com/clarck/jni/MainActivity"#define JNIPAR_CLASS "com/clarck/jni/Person"struct PersonOffsets{ jfieldID name; jfieldID age; jfieldID height;} gPersonOffsets;typedef struct tagPerson{ char mName[10]; int mAge; float mHeight;} Person;static Person gPersons[] = { {"clarck", 25, 175}, {"lilei", 30, 166}, {"hanmeimei", 51, 172},};#define GPERSON_NUM NELEM(gPersons)JNIEXPORT jint JNICALL native_object(JNIEnv *env, jobject clazz, jobject person, jint index) { if ((int) index < 0 || (int) index >= GPERSON_NUM) return -1; //将Person数组中的第index个成员赋值给pPerson指针 Person *pPerson = &gPersons[index]; //设置java对象的person的mName jstring name = (*env)->NewStringUTF(env, pPerson->mName); (*env)->SetObjectField(env, person, gPersonOffsets.name, name); //设置java对象person的mAge (*env)->SetIntField(env, person, gPersonOffsets.age, pPerson->mAge); //设置java对象person的mHeight (*env)->SetFloatField(env, person, gPersonOffsets.height, pPerson->mHeight); LOGD("%s index-%d mName:%s, mAge:%d, mHeight:%f\n", __func__, index, pPerson->mName, pPerson->mAge, pPerson->mHeight); return 0;}static void nativeClassInit(JNIEnv *env) { jclass personClass = (*env)->FindClass(env, JNIPAR_CLASS); gPersonOffsets.name = (*env)->GetFieldID(env, personClass, "mName", "Ljava/lang/String;"); gPersonOffsets.age = (*env)->GetFieldID(env, personClass, "mAge", "I"); gPersonOffsets.height = (*env)->GetFieldID(env, personClass, "mHeight", "F");}/** * Java和JNI函数绑定 */static JNINativeMethod method_table[] = { { "getPersonInfoByIndex", "(Lcom/clarck/jni/Person;I)I", (void*) native_object },};/** * 注册native方法到java中 */static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods, int numMethods) { jclass clazz; clazz = (*env)->FindClass(env, className); if (clazz == NULL) { return JNI_FALSE; } if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) { return JNI_FALSE; } return JNI_TRUE;}/** * 调用注册方法 */int register_ndk_load(JNIEnv* env) { nativeClassInit(env); return registerNativeMethods(env, JNIREG_CLASS, method_table, NELEM(method_table));}JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL; jint result = -1; if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) { return result; } register_ndk_load(env); //返回jni的版本 return JNI_VERSION_1_4;}
接着在Project中右键Android Tools->Add Native Support,最后java层调用如下:
package com.clarck.jni;import android.app.Activity;import android.os.Bundle;import android.util.Log;public class MainActivity extends Activity { private Person mPerson = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d("Test", "onCreate"); mPerson = new Person(); for (int i = 0; i < 3; i++) { getPersonInfoByIndex(mPerson, i); Log.d("Test", "mPersion[" + i + "] -- " + mPerson); } } private native int getPersonInfoByIndex(Person person, int index); static { System.loadLibrary("object_jni"); } }
package com.clarck.jni;public class Person { private String mName; private int mAge; private float mHeight; @Override public String toString() { return "mName: " + mName + ", mAge: " + mAge + ", mHeight: " + mHeight; } }
运行结果如下:
04-15 15:37:30.916: D/Test(31477): onCreate04-15 15:37:30.916: D/jni_logger(31477): native_object index-0 mName:clarck, mAge:25, mHeight:175.00000004-15 15:37:30.916: D/Test(31477): mPersion[0] -- mName: clarck, mAge: 25, mHeight: 175.004-15 15:37:30.916: D/jni_logger(31477): native_object index-1 mName:lilei, mAge:30, mHeight:166.00000004-15 15:37:30.916: D/Test(31477): mPersion[1] -- mName: lilei, mAge: 30, mHeight: 166.004-15 15:37:30.916: D/jni_logger(31477): native_object index-2 mName:hanmeimei, mAge:51, mHeight:172.00000004-15 15:37:30.916: D/Test(31477): mPersion[2] -- mName: hanmeimei, mAge: 51, mHeight: 172.0
更多相关文章
- Android(安卓)远程调试 JNI 实现
- Android中RemoteViews的实现
- android IP
- Android(安卓)Service总结06 之AIDL
- Android(安卓)Service总结06 之AIDL
- 什么是Android内核
- Android(安卓)Studio下“Error:Could not find com.android.tool
- Android中JNI的使用方法
- Android(安卓)支持 Java8