android的JNI代码中可以调用C++的类,但是不能直接调用,要加上一个类似于接口的java类,这个类内部调用C++的类。实际上和接口类直接调用C++中的函数差不多,只是稍微复杂了一点。

1. 写一个简单的类(一直都是用VS自动生成的类,很少自己写一个类,因而此处也是用VS生成类,然后复制到Eclipse工程的jni目录下。)该类包含4个函数:

a带参数的构造函数,用于初始化类中的变量。

b析构函数,用于释放类中的指针(数组)

c求和函数calcSum

d求平均值函数calcMean

下面的代码是VS转到JNI后编译通过的代码(VS生成的可能需要稍微修改一点)

 1 // myMeanSum.h文件 2 #pragma once 3  4 #include <stdio.h> 5 #include <stdlib.h> 6  7 class myMeanSum 8 { 9 public:10     myMeanSum();11     ~myMeanSum();12     myMeanSum(int* data, int num);13     14     double calcMean();15     int calcSum();16 17 private:18     int m_number;19     int* databuf;20     double m_mean;21     int m_sum;22 };
 1 // myMeanSum.cpp文件 2  3 #include "myMeanSum.h" 4  5 myMeanSum::myMeanSum() 6 : m_mean(0) 7 , m_sum(0) 8 , m_number(0) 9 {10     databuf = new int[10];11 }12 13 myMeanSum::myMeanSum(int* data, int num)14 : m_mean(0)15 , m_sum(0)16 , m_number(0)17 {18     m_number = num;19     databuf = new int[m_number];20     memcpy(databuf, data, sizeof(int)*m_number);21 }22 23 24 myMeanSum::~myMeanSum()25 {26     if (databuf!=NULL)27     {28         delete[] databuf;29         databuf = NULL;30     }31 }32 33 34 double myMeanSum::calcMean()35 {36     m_sum = calcSum();37     return m_sum / 1.0 / m_number;  // / 1.0用来保证int类型自动转换成double类型。38 }39 40 41 int myMeanSum::calcSum()42 {43     m_sum = 0;44     for (int i = 0; i < m_number; i++)45     {46         m_sum += databuf[i];47     }48     return m_sum;49 }

2. 在Eclipse中创建新的android工程testClass。

3. 添加JNI文件AndroidClass.cpp。

4. 添加接口文件AndroidClass.java。

5. 在AndroidClass.java中添加long类型的指针,用于存储类的地址private long ptr_;

6. 在AndroidClass.java添加AndroidClass的构造函数:

1 public AndroidClass(int[] data, int num)2 {3     ptr_=AndroidClassGen(data, num);4 }

7. 在AndroidClass.java添加6中函数调用的函数接口:

private native long AndroidClassGen(int[] data, int num);

8. 在AndroidClass.cpp添加7中调用class的接口函数。

 1 JNIEXPORT jlong JNICALL Java_com_example_testclass_AndroidClass_AndroidClassGen 2   (JNIEnv *env, jobject obj, jintArray data, jint num) 3 { 4     jint *iAdata = env->GetIntArrayElements(data, 0); 5  6     jlong ptr= reinterpret_cast<jlong>(new myMeanSum(reinterpret_cast<int*>(iAdata), num)); 7  8     env->ReleaseIntArrayElements(data, iAdata, 0); 9 10     return ptr;11 }

9. 在AndroidClass.java添加释放内存的函数AndroidClassFree,感觉这两个函数名字不一定需要相同(相同没有错误,不相同没测试)。

1 public void AndroidClassFree()2 {3     AndroidClassFree(ptr_);4 }
private native void AndroidClassFree(long ptr);

10. 在AndroidClass.cpp添加9中调用class的接口函数。

1 JNIEXPORT void JNICALL Java_com_example_testclass_AndroidClass_AndroidClassFree2   (JNIEnv *, jobject, jlong ptr)3 {4     if(reinterpret_cast<myMeanSum*>(ptr))5     {6         delete reinterpret_cast<myMeanSum*>(ptr);7         ptr = 0;8     }9 }

11. 在android.mk中添加需要编译的C++类的源文件(默认是LOCAL_SRC_FILES := AndroidClass.cpp):

LOCAL_SRC_FILES := AndroidClass.cpp myMeanSum.cpp

12. 分别添加其他的代码,此处略去,详见工程:

https://github.com/darkknightzh/testClass

说明:AndroidClassGetPtr程序不使用,如果需要在外部的AndroidClass定义的对象A使用对象B,则使用这个函数传入 B的指针。

测试步骤:

1. 在VS中添加如下简单的测试代码:

1 int number = 10;2 int* data = new int[number];3 for (int i = 0; i < number; i++)4 {5     data[i] = i;6 }7 myMeanSum temp(data, number);8 printf("%d\n", temp.calcSum());9 printf("%f\n", temp.calcMean());

输出为

454.500000

2. 在Eclipse的MainActivity.java的onCreate中添加如下测试代码:

 1 int number = 10; 2 int[] data = new int[number]; 3 for (int i = 0; i < number; i++) 4 { 5       data[i] = i; 6 } 7  8 AndroidClass test=new AndroidClass(data,number); 9 System.out.println("test-----"+test.calcSum());10 System.out.println("test-----"+test.calcMean());        11 test.AndroidClassFree();

结果如下:

证明程序正确。

3. 为了证明class中的析构函数正确被调用,databuf申请的内存能正常释放,填写如下测试代码:

 1  int number = 1000*1000; 2 int[] data = new int[number]; 3 for (int i = 0; i < number; i++) 4 { 5         data[i] = i; 6 } 7  8 for(int i=0;i<1000;i++) 9 {10      AndroidClass test=new AndroidClass(data,number);11      System.out.println("test-----"+i+"   "+test.calcSum());12      System.out.println("test-----"+i+"   "+test.calcMean());        13       test.AndroidClassFree();14 }

程序执行完没有出错。证明析构函数能正确的执行,databuf申请的内存能正常释放。

4. 注释掉test.AndroidClassFree();后,程序跑到128次的时候崩溃,之后继续从0开始跑。证明AndroidClassFree函数正确的执行了析构函数。

5. 跑上面3的代码,但是myMeanSum类中的析构函数里面的代码全部注释掉,程序跑到128次后依旧崩溃,证明AndroidClassFree函数正确的执行了析构函数。

ps,上面程序只是一个简单的例子,可能有不完善的地方,同时代码写得也不是很好。

参考网址(貌似不能愉快的访问,感谢原作者,以及不能愉快的访问的搜索引擎):

http://stylishtoupee.blogspot.jp/2011/07/jni-example-with-class-instantiation-c.html

更多相关文章

  1. 用Carbide C++ UI Designer做UI的爽与不爽
  2. [转]编写高效的Android代码
  3. android代码混淆压缩、资源压缩全解析
  4. android高手之路--删除工程里面无用的代码和资源
  5. Android中去掉或更改标题栏TitleBar,theme的更改
  6. Android(安卓)源码通过makefile配置文件对系统APP进行代码混淆
  7. 在android中,编译的项目使用到第三方jar的导入方法 终极版!
  8. Android实现上传拍下的照片到服务器
  9. 指尖上的Android之实战篇--说明篇(二)

随机推荐

  1. Android(安卓)SpannableStringBuilder改
  2. Android(安卓)webkit log定义
  3. android 特效资源
  4. Android不让弹出键盘挡住View
  5. android图像处理系列之三--图片色调饱和度
  6. [原]android 中如何飞行模式的几个操作
  7. 进度条及拖动条背景颜色设置(progressDraw
  8. Android(安卓)windowSoftInputMode属性解
  9. android---------ndk中的各个版本的下载
  10. Android(安卓)中文 API (100) —— Scrol