本博客主要是在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_jni
LOCAL_SRC_FILES := object_jni.c LOCAL_LDLIBS := -llog include $(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[];
int mAge;
float mHeight;
} Person; static Person gPersons[] = {
{"clarck", , },
{"lilei", , },
{"hanmeimei", , },
}; #define GPERSON_NUM NELEM(gPersons) JNIEXPORT jint JNICALL native_object(JNIEnv *env, jobject clazz, jobject person, jint index) {
if ((int) index < || (int) index >= GPERSON_NUM)
return -; //将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 ;
} 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) < ) {
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 = -; 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): onCreate
04-15 15:37:30.916: D/jni_logger(31477): native_object index-0 mName:clarck, mAge:25, mHeight:175.000000
04-15 15:37:30.916: D/Test(31477): mPersion[0] -- mName: clarck, mAge: 25, mHeight: 175.0
04-15 15:37:30.916: D/jni_logger(31477): native_object index-1 mName:lilei, mAge:30, mHeight:166.000000
04-15 15:37:30.916: D/Test(31477): mPersion[1] -- mName: lilei, mAge: 30, mHeight: 166.0
04-15 15:37:30.916: D/jni_logger(31477): native_object index-2 mName:hanmeimei, mAge:51, mHeight:172.000000
04-15 15:37:30.916: D/Test(31477): mPersion[2] -- mName: hanmeimei, mAge: 51, mHeight: 172.0

Android NDK 学习之传递类对象的更多相关文章

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

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

  2. Android 通过 Intent 传递类对象

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

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

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

  4. android通过 Intent 传递类对象

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

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

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

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

    1 应用层代码 NdkParam.java是JNI函数的调用类,它的代码如下:   package com.skywang.ndk; import android.app.Activity; impo ...

  7. Android NDK 学习之在C中调用Java的变量和静态变量

    本博客主要是在Ubuntu 下开发,且默认你已经安装了Eclipse,Android SDK, Android NDK, CDT插件. 在Eclipse中添加配置NDK,路径如下Eclipse-> ...

  8. Android中数据的传递以及对象序列化

    Android中当两个Activity需要有信息交互的时候,可以使用Intent.具体来说: 发送单一类型数据: 发送方: String data = "Hello SecondActivi ...

  9. Android NDK 学习之调用Java函数

    本博客主要是在Ubuntu 下开发,且默认你已经安装了Eclipse,Android SDK, Android NDK, CDT插件. 在Eclipse中添加配置NDK,路径如下Eclipse-> ...

随机推荐

  1. SQL——用户定义函数

    根据用户定义函数返回值的类型,可将用户定义函数分为如下三个类别: (1) 返回值为可更新表的函数 若用户定义函数包含单个 SELECT 语句且该语句可更新,则该函数返回的表也可更新,这样的函数称为内嵌 ...

  2. iOS YSDropdownMagnify 下拉放大,向上导航显示

    要实现的效果如上.在实际开发中,我们会使用到三种方式来实现. 通过隐藏导航栏,自定义导航View 改变原生导航栏背景透明 原生导航栏通过添加背景图片改变 个人是比较喜欢第二种. github下载地址: ...

  3. 转 CSS hack:针对IE6,IE7,firefox显示不同效果

    CSS hack:针对IE6,IE7,firefox显示不同效果 做网站时经常会用到,衡量一个DIV+CSS架构师的水平时,这个也很重要. 区别不同浏览器的CSS hack写法: 区别IE6与FF:  ...

  4. atitit.spring3 mvc url配置最佳实践

    atitit.spring3 mvc url配置最佳实践 1. Url-pattern  bp 1 2. 通用星号url pattern的问题 1 3. Other code 1 4. 参考 2 1. ...

  5. WindowsPhone App如何扩展能够使用的内存

    目前手机系统中对App的内存使用都是有限制的,尤其是对于Android和WindowsPhone这样的平台,因为机型很多,配置高低不同因此对于同一个App在不同的手机上运行的效果也不同. WP上通常对 ...

  6. MongoDB学习笔记——索引管理

    索引 索引能够提升查询的效率.没有索引,MongoDB必须扫描集合中的所有文档,才能找到匹配查询语句的文档. 索引是一种特殊的数据结构,将一小块数据集保存为容易遍历的形式.索引能够存储某种特殊字段或字 ...

  7. javaweb回顾第七篇jsp

    1:为什么会有JSP jsp全名(java server pages)中文叫做java服务器页面.在Servlet那一篇我们发现用Servlet可以生成动态页面,但是我们却在Servlet中却写了大量 ...

  8. 关于iphone6安装了727个应用后,更新app 导致一些app无法更新,无法删除,重启后消失,但是却还是占用空间的解决办法

    我的iphone6 苹果手机,64GB的,存储空间最近一直很吃紧,很捉急,昨天,终于下定决心 解决下这个问题. 由于 空间大,我又随便安装许多APP,现在有727个app,常用的其实就是那个几十个而已 ...

  9. 田渊栋:AlphaGo系统即使在单机上也有职业水平

    Facebook人工智能组研究员田渊栋博士在知乎专栏上更新了一篇文章,详细分析了AlphaGo在<自然>杂志上发表的论文,他认为AlphaGo整个系统即使在单机上也已具有了职业水平,与李世 ...

  10. Porter/Duff,图片加遮罩setColorFilter

    同步发表于http://avenwu.net/2015/02/03/porterduff Fork on github https://github.com/avenwu/support 经常会遇到给 ...