Android JNI和NDK学习(09)JNI实例二 传递类对象

摘要:
*Person:输入参数,java对象*索引:输入参数,序列号*/JNIEXPORTjintJNICALLgetPersonInfoByIndex{//如果索引无效,则直接返回-1。

Android JNI和NDK学习(09)--JNI实例二 传递类对象

1 应用层代码

NdkParam.java是JNI函数的调用类,它的代码如下:

package com.skywang.ndk;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class NdkParam extends Activity {
    public static final String TAG="skywang--NdkParam";
    /** Called when the activity is first created. */
    private Person person=null;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        Log.d(TAG, "on create.");
        person = new Person();
        for (int i=0; i<3; i++) {
            getPersonInfoByIndex(person, i);
            Log.d(TAG, "person["+i+"] -- "+person);
        }
    }
    
    // jni中注册的方法
    private native int getPersonInfoByIndex(Person person, int index);

    static {
        // 加载本地libndk_load.so库文件
        System.loadLibrary("ndk_param");
    }
}

Person.java是用来在Java和JNI之间传递的数据类,它的代码如下:

package com.skywang.ndk;

public class Person {
    
    private String  mName;                     
    private int     mAge;
    private float   mHeight;
    
    public String toString(){
        return "mName:"+mName+", mAge:"+mAge+", mHeight:"+mHeight;
    }

}

2 JNI层代码

ndk_param.c是实现并注册JNI的文件,它的代码如下:

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <jni.h>
#include <assert.h>


// 获取数组的大小
# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
// 指定要注册的类,对应完整的java类名
#define JNIREG_CLASS "com/skywang/ndk/NdkParam"
#define JNIPAR_CLASS "com/skywang/ndk/Person"


// 引入log头文件
#include <android/log.h>  

// log标签
#define  TAG    "hello_param"
// 定义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__)

// jfieldID结构体,用于保存类“Person.java”的filedID
struct PersonOffsets
{
    jfieldID    name;
    jfieldID    age;
    jfieldID    height;
} gPersonOffsets;

// 与“Person.java”对应的结构体,用于保存数据,并将数据赋值给Person.java的成员
typedef struct tagPerson
{
    char    mName[10];
    int     mAge;
    float   mHeight;
}Person;

// 定义了3个Person
static Person gPersons[] = {
    {"skywang", 25, 175},
    {"eman"   , 30, 166},
    {"Dan"    , 51, 172},
};
#define GPERSON_NUM NELEM(gPersons)

/* 
 * 根据index获取Person信息。
 * 参数说明:
 *         env : JNI 接口指针。
 *        claszz : Java 类对象。
 *        person : 输入参数,java对象
 *        index : 输入参数,序列号。
 */
JNIEXPORT jint JNICALL 
getPersonInfoByIndex(JNIEnv *env, jobject clazz, jobject person, jint index)
{

    // 若index无效,则直接返回-1。
    if ((int)index<0 || (int)index>=GPERSON_NUM)
        return -1;

    // 将Person数组(gPersons)中的第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;
}


// 初始化函数,用于获取Java中各个成员对应的fieldID。
static void nativeClassInit (JNIEnv *env)
{   
    jclass personClass = (*env)->FindClass(env, JNIPAR_CLASS);       
    // 获取Person的mName成员对应的FieldID,并保存到gPersonOffsets中
    gPersonOffsets.name     = (*env)->GetFieldID(env, personClass, "mName"  , "Ljava/lang/String;");        
    // 获取Person的mAge成员对应的FieldID,并保存到gPersonOffsets中
    gPersonOffsets.age      = (*env)->GetFieldID(env, personClass, "mAge"   , "I");
    // 获取Person的mHeight成员对应的FieldID,并保存到gPersonOffsets中
    gPersonOffsets.height   = (*env)->GetFieldID(env, personClass, "mHeight", "F");
}

// Java和JNI函数的绑定表
static JNINativeMethod method_table[] = {
    { "getPersonInfoByIndex", "(Lcom/skywang/ndk/Person;I)I", (void*)getPersonInfoByIndex },//绑定
};

// 注册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_param(JNIEnv *env)
{
    nativeClassInit(env);
    // 调用注册方法
    return registerNativeMethods(env, JNIREG_CLASS,
            method_table, NELEM(method_table));
}

// JNI_OnLoad在jni注册时,会被回调执行。
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_param(env);

    // 返回jni的版本
    return JNI_VERSION_1_4;
}

Android.mk的代码如下:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := ndk_param
LOCAL_SRC_FILES := ndk_param.c
# 添加对log库的支持
LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib -llog
#  若生成static的.a,只需添加 LOCAL_LDLIBS:=-llog 

include $(BUILD_SHARED_LIBRARY)

LOCAL_PATH := $(call my-dir)

3 运行工程

logcat信息如下:

D/skywang--NdkParam: on create.
D/hello_param: getPersonInfoByIndex index-0  mName:skywang, mAge:25, mHeight:175.000000
D/skywang--NdkParam: person[0] -- mName:skywang, mAge:25, mHeight:175.0
D/hello_param: getPersonInfoByIndex index-1  mName:eman, mAge:30, mHeight:166.000000
D/skywang--NdkParam: person[1] -- mName:eman, mAge:30, mHeight:166.0
D/hello_param: getPersonInfoByIndex index-2  mName:Dan, mAge:51, mHeight:172.000000
D/skywang--NdkParam: person[2] -- mName:Dan, mAge:51, mHeight:172.0

点击下载:“源代码

免责声明:文章转载自《Android JNI和NDK学习(09)JNI实例二 传递类对象》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Docker实现运行tomcat并部署项目war包,并实现挂载目录WEB UI篇——还HTML标签以本来意义下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

android studio 中jni底层日志的打印

1 添加ndk对log支持若需要添加ndk对log的支持,只需要通过以下2步即可实现。 1.1 修改Android.mk如生成的库文件是“.so文件”,则在Android.mk中添加如下内容:LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib -llog如生成的库文件是“.a文件”,则在Android.mk中添加如下内容:LOCAL_LD...

Android用surface直接显示yuv数据(三)

本文用Java创建UI并联合JNI层操作surface来直接显示yuv数据(yv12),开发环境为Android 4.4,全志A23平台。 package com.example.myyuvviewer; import java.io.File; import java.io.FileInputStream; import and...

linux环境下java调用C/C++动态库(JNI技术:参数为指针与结构体)

一、JNI技术  JNI是Java Native Interface的缩写,通过使用 Java本地接口书写程序,可以确保代码在不同的平台上方便移植.  SUN公司发布的Java 本地接口(JNI)提供了将Java与C/C++、汇编等本地代码集成的方案,该规范使得在 Java 虚拟机内运行的 Java 代码能够与其它编程语言互相操作,包括创建本地方法、更新J...

Android下NDK开发环境搭建

Android下NDK开发环境搭建 1.AndroidNDK安装与配置 1.1 NDK简介 Android NDK是一套允许开发人员使用本地代码(如C/C++)进行Android APP部分功能开发的工具,通过这个工具,我们可以把用C/C++代码编译成可以直接运行在Android平台上的本地代码,这些本地代码以动态链接库( *.so )的形式存在,也...

Android深入浅出之 AudioTrack分析

Android深入浅出之Audio 第一部分 AudioTrack分析 一 目的 本文的目的是通过从Audio系统来分析Android的代码,包括Android自定义的那套机制和一些常见类的使用,比如Thread,MemoryBase等。 分析的流程是: l         先从API层对应的某个类开始,用户层先要有一个简单的使用流程。 l        ...

Android Studio添加原生库并自动构建

[时间:2017-09] [状态:Open] [关键词:Android,Android Studio,gradle,native,c,c++,cmake,原生开发,ndk-build] 0 引言 最近在工作中遇到了升级Android Studio 2.3.3稳定版之后,无法编译jar包的问题。之后寻找AS文档-探索 Android Studio发现。可以通...