Android中关于JNI 的学习(零)简单的例子,简单地入门

Android中JNI的作用,就是让Java能够去调用由C/C++实现的代码,为了实现这个功能,需要用到Anrdoid提供的NDK工具包,在这里不讲如何配置了,好麻烦,配置了好久。。。

本质上,Java去调用C/C++的代码其实就是去调用C/C++提供的方法,所以,第一步,我们要创建一个类,并且定义一个Native方法,如下:

JniTest类:

public class JniTest {

	public native String getTestString();
}

可以看到,在这个方法的前面,用到了native关键字。

接着,我们要在命令行中编译这个java文件,得到一个class文件,如下:

然后我们可以利用javah命令文件,生成一个C的头文件,其实javah这一步不是必需的,因为创建这个头文件,只是为了方便我们复制这个Jni中对应的方法名称,因为这些名称实在太复杂了。

在这里有一点要注意,javah命令要在包的根目录下调用,对应的类文件,必须是完整的类名,如上图所示,会先回到src目录,再调用javah命令。

这样我们就会在src文件夹下在产生一个头文件,如下图所示:

我们可以看到其名称是com_lms_jni_JniTest.h,其实就是包名+类名,我们可以看看里面的内容:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_lms_jni_JniTest */

#ifndef _Included_com_lms_jni_JniTest
#define _Included_com_lms_jni_JniTest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_lms_jni_JniTest
 * Method:    getTestString
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_lms_jni_JniTest_getTestString
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

我们可以看到,在这里面有一个方法,名称是Java_com_lms_jni_JniTest_getTestString,够复杂吧,其实如果我们知道这个名称规则,并且知道如何去实现这样一个方法的话,我们是完全可以不生成这个头文件的,我们可以直接写出对应的C文件。

接下来,在jni文件中创建一个对应的C文件,名称是值得并无所谓,但为了统一,我们就把它叫JniTest.c吧,如下:

在这里,我们也把com_lms_jni_JniTest.h也放到这里了,这个其实是没关系的,只是为了内容的协调和统一而已,一般情况下,我们会把所以由C/C++实现的文件都放在项目目录下一个叫 jni 的文件夹下面。

下面是在JniTest.c中实现native方法,getTestString,如下:

#include <stdio.h>
#include <stdlib.h>
#include <jni.h>

JNIEXPORT jstring JNICALL Java_com_lms_jni_JniTest_getTestString
  (JNIEnv *e, jobject obj){
	return (**e).NewStringUTF(e,"Hello from JniTest Function");
}

在这个c文件中,我们看到,并没有引用头文件com_lms_jni_JniTest.h,而只是引用了一般的C/C++库文件,比如stido.h和stdlib.h文件等,在这里注意到一点,我们还会引用jni.h文件,jni.h文件是JNI编程中很重要的一个头文件,关于Java中的数据类型跟jni中的数据类型的对应全部是在这个文件中定义的,后续会来看一下这个jni.h文件。

在上面JniTest.c文件中实现了方法之后,关于C/C++这边的实现其实也就实现了,那么接下来就是要将这个C文件编译成so文件由Android来调用。

为什么是so文件呢,这是因为Android本质上就是一个linux系统,所以其调用的JNI库文件,都是so形式。

Android提供的NDK库提供了ndk-build的命令来实现这个编译过程,但在此之前,我们要先创建一个Android.mk文件,这是一个简单的小小的Make文件,其内容如下:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := com_lms_jni_HwDemo
LOCAL_SRC_FILES := HwDemo.c JniTest.c
include $(BUILD_SHARED_LIBRARY)

在这里,我们会定义几个变量:

LOCAL_PATH:其值是call my-dir,而my-dir是个宏函数,会返回Android.mk所在的路径,在这里,就是jni文件夹。

include $(CLEAR_VARS),这个命令会清除掉所有LOCAL开头的变量,比如LOCAL_MODULE之类的,但有一个例外,就是其上面的LOCAL_PATH 。

LOCAL_MODULE:要生成的so包名,也是Android中Java代码加载时的名称。

LOCAL_SRC_FILES:要进行编译的源文件,如在这里,有HwDemo.c和JniTest.c等。

include $(BUILD_SHARED_LIBRARY):表明生成一个动态链接库。

定义后这样一个Android.mk文件之后,在命令行中调用ndk-build命令,如下:

命令实行之后,我们可以在项目目录下看到libs中多了一个so库,如下:

到这里,关于Jni实现的就结束了,接下来就是如何在Android中使用这个本地方法了。

我们创建了一个Activity,在它里面只放置一个TextView控件,它的布局如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/tvJni"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="test" />

</LinearLayout>

然后在Activity中,我们要加载这个so库,如下:

public class HwDemo extends Activity {

	static {
		System.loadLibrary("com_lms_jni_HwDemo");//加载so库
	}

	public native String printHello();	

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		TextView tv = (TextView)findViewById(R.id.tvJni);
		JniTest jniTest = new JniTest();//调用JniTest文件的方法
		tv.setText(jniTest.getTestString());
	}

}

1)利用static静态代码块,加载so库文件,可以看到在这里,这个名称就是Anrdoid.mk中定义的LOCAL_MODULE值。

2)创建JniTest对象,调用其getTestString()方法,最终显示结果如下:

到这里,通过一个简单的例子,我们明白了如何在Android中利用JNI来调用C/C++的方法了。

最后,我们总结一下这几个步骤:

1)创建Java类文件,并定义Native方法,如JniTest类。

2)利用javac生成class文件,然后回到src目录,利用javah生成C/C++头文件,在这里要注意,javah命令要在包的根目录下调用,对应的类文件,必须是完整的类名,如下:

在Src目录:javah com.lms.jni.JniTest,在上面的截图,也可以看到javac之后,是回到src目录,再调用javah。

3)编写对应的C文件,如JniTest.c,在里面实现C/C++的方法,记得要放在jni文件夹下面。

4)编写Android.mk文件,利用ndk-build命令生成so文件。

5)在Android中利用static静态代码块,调用system.loadLibrary方法来加载so库文件。

6)在Java逻辑中调用之前定义的JniTest类的方法。

结束。源代码下载

Android中关于JNI 的学习(零)简单的例子,简单地入门,布布扣,bubuko.com

时间: 2024-12-20 01:18:44

Android中关于JNI 的学习(零)简单的例子,简单地入门的相关文章

Android中关于JNI 的学习(四)简单的例子,温故而知新

在第零篇文章简单地介绍了JNI编程的模式之后,后面两三篇文章,我们又针对JNI中的一些概念做了一些简单的介绍,也不知道我到底说的清楚没有,但相信很多童鞋跟我一样,在刚开始学习一个东西的时候,入门最好的方式就是一个现成的例子来参考,慢慢研究,再学习概念,再回过来研究代码,加深印象,从而开始慢慢掌握. 今天我们就再来做一个小Demo,这个例子会比前面稍微复杂一点,但是如果阅读过前面几篇文章的话,理解起来也还是很简单的.很多东西就是这样,未知的时候很可怕,理解了就很简单了. 1)我们首先定义一个Jav

Android中关于JNI 的学习(五)在C文件中使用LogCat

事实上,本文是在Peter Jerde的How much information can be stored by ordering 52 playing cards文章基础上翻译.改编和扩展而来的.当然这是经过Jerde本人首肯的. 注意本文方法并非最优,也没有完全利用所有的信息空间,只是简单的尝试. 有数字的地方就有信息.所以扑克牌中保存信息不是什么新鲜事. PDF文档点这里:下载 原文(英文)点这里:访问 这里有两个DEMO. 编码DEMO,解码DEMO 首先是"DEEP IN SHALL

Android中关于JNI 的学习(三)在JNI层访问Java端对象

前面两篇文章简单介绍了JNI层跟Java层的一些对应关系,包括方法名,数据类型和方法名称等,相信在理论层面,能够很好地帮助我们去了解JNI在Native本地开发中的作用,对JNI的一些概念也有了一个初步的认识,由于表达能力或者理解还是有限,有些地方讲得不是很清楚,如果各位朋友有觉得云里雾里,欢迎大家留言一起学习. 概念上的理解有助于我们更好地认识JNI,而一些实际点的例子则能够更好地帮我们从代码上去掌握并应用JNI. 在第一篇文章,我们是从一个小例子来入门学习的,在其中,我们通过JNI层函数返回

Android中关于JNI 的学习(二)对于JNI方法名,数据类型和方法签名的一些认识

处理特征数据 及 代码 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26240241 输入文件:  1. 归一化后的特征文件, 第1列是标签, 其余列是特征; 2. 特征最大值向量文件: 前3列是标准格式, 其余列是最大值; 输出文件: 1. 符合SVM训练数据的特征格式; 2. Mat存储的标准XML文件; 代码: /* 处理特征数据程序 By C.L.Wang 数据格式: 特征数据: 第1列是标签, 其余列是特征; 最大

Android中关于JNI 的学习(零)简单的样例,简单地入门

Android中JNI的作用,就是让Java可以去调用由C/C++实现的代码,为了实现这个功能.须要用到Anrdoid提供的NDK工具包,在这里不讲怎样配置了,好麻烦,配置了好久. . . 本质上,Java去调用C/C++的代码事实上就是去调用C/C++提供的方法.所以,第一步,我们要创建一个类,而且定义一个Native方法.例如以下: JniTest类: public class JniTest { public native String getTestString(); } 能够看到,在这

Android中关于JNI 的学习(四)简单的样例,温故而知新

在第零篇文章简单地介绍了JNI编程的模式之后.后面两三篇文章,我们又针对JNI中的一些概念做了一些简单的介绍,也不知道我究竟说的清楚没有.但相信非常多童鞋跟我一样.在刚開始学习一个东西的时候,入门最好的方式就是一个现成的样例来參考,慢慢研究,再学习概念.再回过来研究代码,加深印象,从而開始慢慢掌握. 今天我们就再来做一个小Demo.这个样例会比前面略微复杂一点.可是假设阅读过前面几篇文章的话,理解起来也还是非常easy的. 非常多东西就是这样.未知的时候非常可怕.理解了就非常easy了. 1)我

Android中关于JNI 的学习(三)在JNI层訪问Java端对象

前面两篇文章简介了JNI层跟Java层的一些相应关系,包含方法名,数据类型和方法名称等,相信在理论层面.可以非常好地帮助我们去了解JNI在Native本地开发中的作用,对JNI的一些概念也有了一个初步的认识,因为表达能力或者理解还是有限,有些地方讲得不是非常清楚.假设各位朋友有认为云里雾里,欢迎大家留言一起学习. 概念上的理解有助于我们更好地认识JNI.而一些实际点的样例则可以更好地帮我们从代码上去掌握并应用JNI. 在第一篇文章,我们是从一个小样例来入门学习的,在当中,我们通过JNI层函数返回

Android中关于JNI 的学习(六)JNI中注冊方法的实现

在前面的样例中,我们会发现,当在Java类中定义一个方法的时候,例如以下: public class ParamTransferTest { public static int testval = 1; public native void changeTestVal(); 则在相应的JNI层中,由javah生成的头文件和其相应的C文件,其方法名称必须例如以下: JNIEXPORT void JNICALL Java_com_lms_jni_ParamTransferTest_changeTes

Android中关于JNI 的学习(一)对于JNIEnv的一些认识

一个简单的样例让我们初步地了解JNI的作用,可是关于JNI中的一些概念还是须要了解清楚,才可以更好的去利用它来实现我们想要做的事情. 那么C++和Java之间的是怎样通过JNI来进行互相调用的呢? 我们知道.在Android中,当Java文件被编译成dex文件之后,会由类载入器载入到Dalvik VM(DVM)中,由DVM来进行解释,翻译成机器语言之后,才干由机器来执行. 而对于C/C++来说,其源码经由Android提供的NDK工具包,能够编译成可运行动态库(即.so文件).之后.Java和C