2019独角兽企业重金招聘Python工程师标准>>>
(注:由于新浪博客不支持 C 注释,所以请将 /^ ^/ 想像替换为 /星 星/)
一、实现目标:
给出两个坐标点,求它们之间的距离。
一、实现目标:
给出两个坐标点,求它们之间的距离。
二、代码实现: 1.Java 代码:
1) CPoint.java 文件内容如下:
1) CPoint.java 文件内容如下:
package wzh.nsc;
/^ 定义一个 CPoint 类 ^/
public class CPoint {
float x; // x轴坐标点
float y; // y轴坐标点
}
/^ 定义一个 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 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 文件内容如下:
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;
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;
CPoint cpointB = new CPoint();
cpointB.x = 5;
cpointB.y = 5;
// 调用 C 语言函数,求出两点坐标之间的距离
float fDistanceValue = nc.MeasureDistance( cpointA, cpointB );
float fDistanceValue = nc.MeasureDistance( cpointA, cpointB );
textviewObj.setText( "MeasureDistance( cpointA, cpointB ) = " +
fDistanceValue );
setContentView( textviewObj );
fDistanceValue );
setContentView( textviewObj );
setTitle( "a + b = " +
String.valueOf( nc.add( 81,
84 ) ) );
}
}
String.valueOf( nc.add( 81,
84 ) ) );
}
}
2.C 代码:
1) wzh_nsc_nativecode.h 文件内容如下:
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 );
/^ 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
}
#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
记住还要在 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 ) );
}
/^
* 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
LOCAL_SRC_FILES := wzh_nsc_nativecode.c
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog
#编译动态库
include $(BUILD_SHARED_LIBRARY)
#编译可执行程序
#include $(BUILD_EXECUTABLE)
include $(BUILD_SHARED_LIBRARY)
#编译可执行程序
#include $(BUILD_EXECUTABLE)
4. Application.mk 文件内容如下:
APP_PROJECT_PATH := $(call my-dir)/jni
APP_MODULES := nativecode
APP_MODULES := nativecode
5. 整个工程目录描述:
~/
|---android_code
|---nativecode
|---testjnipro
~/
|---android_code
|---nativecode
|---testjnipro
1) C 语言本地动态库工程目录:
nativecode
|---jni
|---Application.mk
|---Android.mk
|---wzh_nsc_nativecode.c
|---wzh_nsc_nativecode.h
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
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
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 -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
通过 ~/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 运行演示效果。