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实例二 传递类对象的更多相关文章

  1. Android JNI和NDK学习(06)--JNI的数据类型(转)

    本文转自:http://www.cnblogs.com/skywang12345/archive/2013/05/23/3094037.html 本文介绍JNI的数据类型.NDK中关于JNI数据类型的 ...

  2. Android JNI和NDK学习(05)--JNI真机调试(转)

    本文转自: http://www.cnblogs.com/skywang12345/archive/2013/05/23/3094250.html 本文主要介绍如何将JNI导入到真机进行调试.下面以M ...

  3. Android JNI和NDK学习(04)--NDK调试方法(转)

    本文转自:http://www.cnblogs.com/skywang12345/archive/2013/05/23/3092812.html 本文主要介绍在ndk中添加log的方法.然后,我们就可 ...

  4. Android JNI和NDK学习(03)--动态方式实现JNI(转)

    本文转自:http://www.cnblogs.com/skywang12345/archive/2013/05/23/3092491.html 前面总结了静态实现JNI的方法,本文介绍如何动态实现J ...

  5. Android 通过 Intent 传递类对象或list对象

    (转:http://www.cnblogs.com/shaocm/archive/2013/01/08/2851248.html) Android中Intent传递类对象提供了两种方式一种是 通过实现 ...

  6. Android 通过 Intent 传递类对象

    Android中Intent传递类对象提供了两种方式一种是 通过实现Serializable接口传递对象,一种是通过实现Parcelable接口传递对象. 要求被传递的对象必须实现上述2种接口中的一种 ...

  7. Android 开发笔记——通过 Intent 传递类对象

    Android中Intent传递类对象提供了两种方式一种是 通过实现Serializable接口传递对象,一种是通过实现Parcelable接口传递对象. 要求被传递的对象必须实现上述2种接口中的一种 ...

  8. android通过 Intent 传递类对象

    Android中Intent传递类对象提供了两种方式一种是 通过实现Serializable接口传递对象,一种是通过实现Parcelable接口传递对象. 要求被传递的对象必须实现上述2种接口中的一种 ...

  9. Android中Intent传递类对象的方法一(Serializable)

    Activity之间通过Intent传递值,支持基本数据类型和String对象及它们的数组对象byte.byte[].char.char[].boolean.boolean[].short.short ...

随机推荐

  1. 洛谷 P1301 魔鬼之城

    P1301 魔鬼之城 题目描述 在一个被分割为N*M个正方形房间的矩形魔鬼之城中,一个探险者必须遵循下列规则才能跳跃行动.他必须从(1, 1)进入,从(N, M)走出:在每一房间的墙壁上都写了一个魔法 ...

  2. HDU 4328 Contest 3

    悬线法可解,稍有点烦琐. #include <iostream> #include <cstdio> #include <cstring> #include < ...

  3. UltraEdit正則表達式介绍及实例

    前几天,有个将Excel中的数据导入到数据库中的需求.原本想到用程序读取Excel中的数据并存储到数据库中,但经一哥们的提醒,说用 EditPlus或UltraEdit这种工具直接将数据拼凑成SQL插 ...

  4. Linux以下的两种文件锁

    文件锁是一种文件读写机制.在不论什么特定的时间仅仅同意一个进程訪问一个文件. 利用这样的机制可以使读写单个文件的过程变得更安全. 在这篇文章中.我们将探讨Linux中不同类型的文件锁,并通过演示样例程 ...

  5. Java面试中常问的数据库方面问题

    MySQL 为什么用自增列作为主键 如果我们定义了主键(PRIMARY KEY),那么InnoDB会选择主键作为聚集索引.如果没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的唯一索引作 ...

  6. Python一行代码获得IP地址

    比较靠谱的方法, 通过构造UDP包获得本机IP地址   python -c "import socket;print([(s.connect(('8.8.8.8', 53)), s.gets ...

  7. Ubuntu新建用户并加入SUDO组

    Ubuntu新建用户并加入SUDO组 新建用户: adduser xxxx 加入用户组: usermod -aG sudo username

  8. weboffice7

    document.all.WebOffice1.ShowToolBar = false;

  9. 关于webuploader跨域解决方法

    1.在iis处理程序映射 2.后台ashx处理添加如下代码

  10. JavaScript语法高亮库highlight.js使用

    highlight.js是一款基于JavaScript的语法高亮库,目前支持125种编程语言,有63种可供选择的样式,而且能够做到语言自动识别,和目前主流的JS框架都能兼容,可以混合使用. 这款高亮库 ...