Android JNI的使用
来源:互联网 发布:阿里巴巴一键上传淘宝 编辑:程序博客网 时间:2024/05/21 09:23
下面是一个简单的JNI编程实例
1 新建Android ApplicationProject。项目名称设为JniTest,其它采用默认配置。
2 新建Test类。写出对固有方法以及它的自变量进行声明的Java代码
package com.example.jnitest;public class Test {public static native void ShowMessage(String msg);static {System.loadLibrary("jnitest");}}
这里只声明了一个方法ShowMessage。
static 代码块中的内容是加载动态库libjnitest.so
3 生成C头文件
编译头Test.java文件,并对编译出来的.class文件运行javah。
步骤如下:
假设工程目录为:F:\workspace\JniTest
执行如下命令
cd /d F:\workspace\JniTest\bin\classes
javah com.example.jnitest.Test
然后会在目录F:\workspace\JniTest\bin\classes
生成一个com_example_jnitest_Test.h文件。javah 会读入类文件,并为每个固有方法声明在C 或C++头文件里生成一个函数原型。
4 完成C或C++代码
新建msg.c文件,其内容如下#include "com_example_jnitest_Test.h"#include <stdio.h>#include <android/log.h> //for __android_log_print/*ShowMessage的实现*/JNIEXPORT void JNICALL Java_com_example_jnitest_Test_ShowMessage(JNIEnv *jEnv, jobject this, jstring jMsg){ const char * msg;msg = (*jEnv)->GetStringUTFChars(jEnv, jMsg,0);printf("From jni: %s\n", msg); //这个打印在eclipse 的logcat看不到, //下面的打印是为了在logcat中可以看到。__android_log_print(ANDROID_LOG_INFO, "JniTest","%s", msg); (*jEnv)->ReleaseStringUTFChars(jEnv, jMsg,msg);}
5 编译生成动态库
在你配置好NDK环境的系统中新建一个jnitest文件夹,并在其下新建一个jni文件夹。把msg.c和javah生成的头文件拷贝到jnitest/jni目录下。
然后新建Android.mk文件,内容如下:
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_CFLAGS := -D__STDC_CONSTANT_MACROS -fvisibility=hiddenLOCAL_ARM_MODE := armLOCAL_LDLIBS :=-L$(SYSROOT)/usr/lib -llogLOCAL_SRC_FILES := msg.cLOCAL_MODULE := msgimplinclude $(BUILD_SHARED_LIBRARY)
cd 到jnitest/jni目录下,执行ndk-build进行编译
6 回到eclipse
如图在libs文件夹下创建一个文件夹并命名为armeabi,然后把生成的libjnitest.so拖到该文件夹下面。
7 java代码中调用ShowMessage()
我们在MainActivity.java中的onCreate函数中调用ShowMessage()5次。
Test.ShowMessage("Msg 1 from java");
Test.ShowMessage("Msg 2 from java");
Test.ShowMessage("Msg 3 from java");
Test.ShowMessage("Msg 4 from java");
Test.ShowMessage("Msg 5 from java");
打印5条不同的消息。
8 运行JniTest
一切正常的话,你会在logcat看到5条这样的消息
证明已经成功调用到C中的实现
下图显示的是JNI的实现流程:
JNI理论知识
JNI是Java Native Interface的缩写,中文为Java本地调用。JNI是Java代码与其它语言写的代码进行交互的一个接口。Java代码和本地代码相互协作,共同实现程序的功能。
JNI的存在是有其必要性的:
·标准的java类库可能不支持你的程序所需的特性。
·或许你已经有了一个用其他语言写成的库或程序,而你希望在java程序中使用它。
·你可能需要用底层语言实现一个小型的时间敏感代码,比如汇编,然后在你的java程序中调用这些功能。
相互调用问题
调用问题主要是数据类型之间的转换
基本数据类型之间的对应关系如下
例如我在.java文件中声明如下函数
public static native void typeTest(boolean b, int i, char c, long l, byte bt, float f, double db);经javah转换后生成的函数声明为
JNIEXPORT void JNICALL Java_com_example_jnitest_Test_typeTest (JNIEnv *, jclass, jboolean, jint, jchar, jlong, jbyte, jfloat, jdouble);这些类型可以直接进行转换或赋值。需要注意的一点是,java的char是16位的,long是64位的。
java传递的String转换为C的char *
java传入的String参数,在c文件中被jni转换为jstring的数据类型,在c文件中声明char* msg然后msg= (char*)(*jEnv)->GetStringUTFChars(jEnv, jMsg, 0)注意:msg使用完后,通知虚拟机平台相关代码无需再访问:(*jEnv)->ReleaseStringUTFChars(jEnv, jMsg, msg);
对应的C++风格:msg= jEnv->GetStringUTFChars(jMsg, 0); jEnv->ReleaseStringUTFChars(jMsg, msg)
更严谨的使用是把msg声明为const char *msg。这相当于传递了一个字串,这个字串是只读的。
java传递的bytearray转换为char *并使用
这相当于传递了一个块buffer。可以改变buffer的内容并返回。
char *buffer = (char*) (*env)->GetByteArrayElements(env, bytearray, 0);
...
(*env)->ReleaseByteArrayElements(env, bytearray, buffer, 0);
此外还可以传递和使用Java对象
下面是书上的一个简单示例
Java代码
class MyJavaClass {public void divByTwo() { aValue /= 2; }public int aValue;}public class UseObjects {public static void main(String [] args) {UseObjects app = new UseObjects();MyJavaClass anObj = new MyJavaClass();anObj.aValue = 2;app.changeObject(anObj);System.out.println("Java: " + anObj.aValue);}private native voidchangeObject(MyJavaClass obj);static {System.loadLibrary("UseObjImpl");}}C代码
JNIEXPORT void JNICALL Java_UseObjects_changeObject(JNIEnv * env, jobject jThis, jobject obj) {jclass cls;jfieldID fid;jmethodID mid;int value;cls = env->GetObjectClass(obj);fid = env->GetFieldID(cls,"aValue", "I");mid = env->GetMethodID(cls,"divByTwo", "()V");value = env->GetIntField(obj, fid);printf("Native: %d\n", value);env->SetIntField(obj, fid, 6);env->CallVoidMethod(obj, mid);value = env->GetIntField(obj, fid);printf("Native: %d\n", value);}
JNI函数
JNI定义了一系列函数,提供本地代码访问java代码的接口。每个Jni函数都会接收一个特殊的自变量作为自己的第一个参数:JNIEnv自变量。这些函数可以划分为下述类别:
■ 获取版本信息
■ 进行类和对象操作
■ 控制对Java对象的全局或局部引用
■ 访问实例字段和静态字段
■ 调用实例方法和静态方法
■ 执行字串和数组操作
■ 产生和控制Java异常
JNI函数的数量相当多,具体可以搜索“JNI 函数”, 也可以参阅所用编译器的JNI文档。
- Android JNI的使用
- android jni的使用
- Android的JNI使用
- Android中JNI的使用
- Android中jNI的使用
- android JNI javah的使用
- android之JNI的使用
- android中JNI的使用
- Android中JNI的使用
- Android中JNI的使用
- Android中JNI的使用
- Android-JNI的简单使用
- Android之JNI的使用
- Android中JNI的使用
- Android中JNI的使用
- ANDROID JNI的使用简介
- Android中JNI的使用
- Android studio JNI的使用
- android xml 布局错误
- dump数据块
- RHCSA/RHCE Red Hat Linux认证学习指南(第6版):EX200 & EX300
- DedeCms Runphp 标签中调用其他变量的方法
- wap开发语言
- Android JNI的使用
- Android下Affinities和Task
- 让Eclipse的自动提示功能更强大
- mysql数据库备份
- vb上传下载控件Inet-FTP使用大全
- Hadoop之道--MapReduce简单应用倒排索引(InversedIndex)
- 短信的收发及在android模拟器之间实践(二)
- Daily-C-Study(13):c语言变量及命名
- 同济大学软件学院万金友院长谈嵌入式(学习与规划)