zoukankan      html  css  js  c++  java
  • (原)android的JNI中使用C++的类

    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_AndroidClassFree
    2   (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
    ", temp.calcSum());
    9 printf("%f
    ", temp.calcMean());

    输出为

    45
    4.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

  • 相关阅读:
    tomcat feign rocketmq 最大线程数
    rocketmq
    使用docker在linux上安装oracle数据库
    dnf 腾讯 解人脸
    记一次mysql慢查询优化
    python运行内存分析
    【转】【WPF】WPF强制刷新界面
    【转】【WPF】Grid显示边框线
    流媒体服务新手入门教程03--音视频基础
    流媒体服务新手入门教程02--m7s环境搭建
  • 原文地址:https://www.cnblogs.com/darkknightzh/p/4366179.html
Copyright © 2011-2022 走看看