热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

AndroidNDK实现C代码中操作Java代码的类对象

2019独角兽企业重金招聘Python工程师标准(注:由于新浪博客不支持C注释,所以请将^^想像替换为星星)一、实现目标:给出两个坐

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

(注:由于新浪博客不支持 C 注释,所以请将 /^ ^/ 想像替换为 /星 星/)
一、实现目标:
给出两个坐标点,求它们之间的距离。

二、代码实现: 1.Java 代码:
1) CPoint.java 文件内容如下:
package wzh.nsc;
/^ 定义一个 CPoint 类 ^/
public class CPoint {
   float x; // x轴坐标点
   float y; // y轴坐标点
}

2) nativecode.java 文件内容如下:
package wzh.nsc;
public class nativecode {
   /^ 把 lib动态库名.so 放到你的 工程文件夹名/libs/armeabi/ 下,
      然后在程序随便什么地方中加入如下代码 ^/

   static {
       // Java 代码要求 Virtual Machine 去载入所指定的 C 语言动态库
       // Virtual Machine 去 Android 的 /system/lib/ 下载入 lib动态库名.so
       // 下面的动态库名为 libMeasureDistanceDemo.so 去掉了 lib 与 .so 的名字
       System.loadLibrary( "MeasureDistanceDemo" );
   }
   public native float MeasureDistance( CPoint a, CPoint b );
   public native int add(int a, int b);
}

3) testjni.java 文件内容如下:
package wzh.nsc;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class testjni extends Activity {
   @Override
   public void onCreate( Bundle savedInstanceState ) {
       super.onCreate( savedInstanceState );

       nativecode nc = new nativecode();
       TextView textviewObj = new TextView( getApplicationContext() );

       
// 新建一个 Point 类对象 cpointA
       CPoint cpointA = new CPoint();
       cpointA.x = 3;
       cpointA.y = 3;
       // 新建一个 Point 类对象 cpointB
       CPoint cpointB = new CPoint();
       cpointB.x = 5;
       cpointB.y = 5;
       // 调用 C 语言函数,求出两点坐标之间的距离
       float fDistanceValue = nc.MeasureDistance( cpointA, cpointB );
       textviewObj.setText( "MeasureDistance( cpointA, cpointB ) = " +
                            fDistanceValue );
       setContentView( textviewObj );
       setTitle( "a + b = " +
                 String.valueOf( nc.add( 81,
                                         84 ) ) );
   }
}

2.C 代码:
1) wzh_nsc_nativecode.h 文件内容如下:
/^ DO NOT EDIT THIS FILE - it is machine generated ^/
/^ jni.h 里面提供了很多对 Java 类及对象的操作 ^/
#include
/^ Header for class wzh_nsc_nativecode ^/
#ifndef _Included_wzh_nsc_nativecode
   #define _Included_wzh_nsc_nativecode
   #ifdef __cplusplus
       extern "C"
       {
   #endif
/^
 * Class:    wzh_nsc_nativecode
 * Method:   add
 * Signature: (II)I
 ^/

JNIEXPORT jint JNICALL
Java_wzh_nsc_nativecode_add( JNIEnv *,
                            jobject,
                            jint,
                            jint );
/^
 * Class:    wzh_nsc_nativecode
 * Method:   MeasureDistance
 * Signature: (Lwzh/nsc/CPoint;Lwzh/nsc/CPoint;)F
 ^/

JNIEXPORT jfloat JNICALL
Java_wzh_nsc_nativecode_MeasureDistance( JNIEnv *,
                                        jobject,
                                        jobject,
                                        jobject );
   #ifdef __cplusplus
       }
   #endif
#endif

2) wzh_nsc_nativecode.c 文件内容如下:
/^ 提供了 log 的 API,
  记住还要在 Android.mk 里面加上 LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog ^/

/^ Android 2.1提供了 openGL ES 2.0 的 API,使用方法同 log 一样 ^/
/^ Android 2.2提供了 graphics 的处理接口,使用方法同 log 一样 ^/

#include
#include
#include "wzh_nsc_nativecode.h"

/^
 * Class:    wzh_nsc_nativecode
 * Method:   add
 * Signature: (II)I
 ^/

JNIEXPORT jint JNICALL
Java_wzh_nsc_nativecode_add( JNIEnv *env,
                            jobject this,
                            jint a,
                            jint b )
{
    return ( a + b );
}


/^ 返回值是float,在 jni 中定义的是 jfloat ^/
/^
 * Class:    wzh_nsc_nativecode
 * Method:   MeasureDistance
 * Signature: (Lwzh/nsc/CPoint;Lwzh/nsc/CPoint;)F
 ^/

JNIEXPORT jfloat JNICALL
/^ 函数名规则:
  第一部分以关键字 Java 开头,
  第二部分则是由每一层的包名组成,每层包名之间都用(_)下划线隔开,
  第三部分即是类名,Java 代码中声明此函数的所在类名,
  第四部分才是给 Java 代码声明且或调用的 C 语言函数名,
  以上四部分中间都用(_)下划线隔开 ^/
/^ 第一、二个参数:jni标准必须的参数 ^/

/^ 第三、四个参数:Java传递进来的参数 ^/
Java_wzh_nsc_nativecode_MeasureDistance( JNIEnv* env,
                                        jobject this,
                                        jobject cpointA,
                                        jobject cpointB )
{
   /^ 找到指定包中的Java类 */
   /^ 在 C 语言中使用 env 都要写成(*env)-> 且后面的函数中第一个参数也为 env */
   /^ 在 C++ 语言中使用 env 则可写成 env-> 且后面的函数中第一个参数无需为 env */
   /^ 具体请看一下 jni.h 的代码定义: */

   /^ #if defined(__cplusplus)
          typedef _JNIEnv JNIEnv;
          typedef _JavaVM JavaVM;
      #else
          typedef const struct JNINativeInterface* JNIEnv;
          typedef const struct JNIInvokeInterface* JavaVM;
      #endif */
   /^ JNINativeInterface 结构中 */
   /^ FindClass 原型为 jclass (*FindClass)(JNIEnv*, const char*); */

   jclass jclassPoint = (*env)->FindClass( env,
                                           "wzh/nsc/CPoint" );
   /^ 如果 找到指定包中的 Java 类失败 的话,则 */
   if ( NULL == jclassPoint )
   {
        /^ 输出的 log 一般是到 /dev/log/ 下的三个设备中,可以用 logcat 工具查看 */
        __android_log_write( ANDROID_LOG_INFO,           /^ 日志信息 */
                             "
nativecode",    /^ 日志标签 */
                             "Don't found class Point" ); /^ 日志内容 */
        return 0;
   }
   else /^ 找到指定包中的 Java 类成功 */
   {
       __android_log_write( ANDROID_LOG_INFO, /^ 日志信息 */
                            "nativecode", /^ 日志标签 */
                            "Sure found class Point" ); /^ 日志内容 */
   }

/^ 得到类函数 GetMethodID(Jni环境变量,
                        函数所属Java类的类名,
                        函数名,
                        函数的参数及返回值类型描述字符串 )
                        例如:
(II)V" => void (int, int) */
/^ jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); */
   /^ 调用类函数 CallObjectMethod(
Jni环境变量,
                                 传进来的类对象,
                                 
GetMethodID的返回值,
                                 Java类的函数所需的参数
) */
   /^ jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...); */
   /^ 得到 CPoint::x 的ID */

   jfieldID fieldID_x = (*env)->GetFieldID( env,        /^ */
                                            jclassPoint, /^ */
                                            "x",        /^ CPoint::x */
                                            "F" );      /^ float类型 */
   /^ 得到 CPoint::y 的ID */
   jfieldID fieldID_y = (*env)->GetFieldID( env,        /^ */
                                            jclassPoint, /^ */
                                            "y",        /^ CPoint::y */
                                            "F" );      /^ float类型 */

   /^ 得到 cpointA::x 的值 */

   jfloat jfloatAX = (*env)->GetFloatField( env,
                                            cpointA,
                                            fieldID_x );
   
   jfloat jfloatAY = (*env)->GetFloatField( env,
                                            cpointA,
                                            fieldID_y );
   /^ 得到 cpointB::x 的值 */
   jfloat jfloatBX = (*env)->GetFloatField( env,
                                            cpointB,
                                            fieldID_x );
   /^ 得到 cpointB::y 的值 */
   jfloat jfloatBY = (*env)->GetFloatField( env,
                                            cpointB,
                                            fieldID_y );
   /^ powf - 指数运算,第二个参数是第一个参数的指数 */
   /^ sqrtf - 开平方运算 */
   return sqrtf( powf( jfloatBX - jfloatAX, 2 ) +
                 powf( jfloatBY - jfloatAY, 2 ) );
}

3. Android.mk 文件内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := nativecode
LOCAL_SRC_FILES := wzh_nsc_nativecode.c
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog
#编译动态库
include $(BUILD_SHARED_LIBRARY)
#编译可执行程序
#include $(BUILD_EXECUTABLE)

4. Application.mk 文件内容如下:
APP_PROJECT_PATH := $(call my-dir)/jni
APP_MODULES     := nativecode

5. 整个工程目录描述:
~/
 |---android_code
     |---nativecode
     |---testjnipro

1) C 语言本地动态库工程目录:
nativecode
 |---jni
     |---Application.mk
     |---Android.mk
     |---wzh_nsc_nativecode.c
     |---wzh_nsc_nativecode.h

2) Java 语言应用程序工程目录:
testjnipro
 |---bin
     |---wzh
          |---nsc
               |---CPoint.class
               |---nativecode.class
               |---testjni.class
               |---...
 |---src
     |---wzh
          |---nsc
               |---CPoint.java
               |---nativecode.java
               |---testjni.java

5. 由 nativecode.java 生成 wzh_nsc_nativecode.h 的方法:
  1) 进入到 ~/android_code/nativecode/jni 目录下:
  $ cd ~/android_code/nativecode/jni
  2) 在 ~/android_code/nativecode/jni 目录下
     通过 ~/android_code/testjnipro/bin/nativecode.class 文件生成 wzh_nsc_nativecode.h
  $ javah -classpath ../../testjnipro/bin wzh.nsc.nativecode

  或者 用 javah -jni 或 直接用 javah 在 ~/android_code/testjnipro/bin 目录下
      生成 wzh_nsc_nativecode.h

   1) 进入到 ~/android_code/testjnipro/bin 目录下:
  $ cd ~/android_code/testjnipro/bin
  2) 在 ~/android_code/testjnipro/bin 目录下
     通过 ~/android_code/testjnipro/bin/nativecode.class 文件
     生成 wzh_nsc_nativecode.h
  $ javah -jni wzh.nsc.nativecode
  或
  $ javah wzh.nsc.nativecode
  注:-jni 生成 JNI样式的头文件(为 javah 默认选项)

  3) 在 ~/android_code/nativecode 目录下 或
     在 ~/android_code/nativecode/jni 目录下
     执行 $NDK/ndk-build 编译 C 语言本地动态库工程
  $ $NDK/ndk-build
  注:Application.mk 文件 和 Android.mk 文件必需在 ~/android_code/nativecode/jni 目录下;

  4) 把执行 $NDK/ndk-build 编译在 ~/android_code/nativecode 目录下产生的 libs 文件夹,
     复制到 ~/android_code/testjnipro 目录下,即可用 Eclipse 运行演示效果。

转:https://my.oschina.net/zhuzihasablog/blog/115653



推荐阅读
author-avatar
ll66068ll你
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有