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

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

JniTest类:

public class JniTest {

	public native String getTestString();
}

能够看到,在这种方法的前面,用到了nativekeyword。

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

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlubWlhbnNoZW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

然后我们能够利用javah命令文件。生成一个C的头文件。事实上javah这一步没必要的,由于创建这个头文件,仅仅是为了方便我们复制这个Jni中相应的方法名称,由于这些名称实在太复杂了。

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

这样我们就会在src目录下在产生一个头文件。例如以下图所看到的:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlubWlhbnNoZW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

我们能够看到其名称是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命令,例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlubWlhbnNoZW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

命令实行之后,我们能够在项目文件夹下看到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 的学习(零)简单的样例,简单地入门的更多相关文章

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

    一个简单的样例让我们初步地了解JNI的作用.可是关于JNI中的一些概念还是需要了解清楚,才干够更好的去利用它来实现我们想要做的事情. 那么C++和Java之间的是怎样通过JNI来进行互相调用的呢? 我 ...

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

    在第零篇文章简单地介绍了JNI编程的模式之后.后面两三篇文章,我们又针对JNI中的一些概念做了一些简单的介绍,也不知道我究竟说的清楚没有.但相信非常多童鞋跟我一样.在刚開始学习一个东西的时候,入门最好 ...

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

    前面两篇文章简介了JNI层跟Java层的一些相应关系,包含方法名,数据类型和方法名称等,相信在理论层面.可以非常好地帮助我们去了解JNI在Native本地开发中的作用,对JNI的一些概念也有了一个初步 ...

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

    在前面的样例中,我们会发现,当在Java类中定义一个方法的时候,例如以下: public class ParamTransferTest { public static int testval = 1 ...

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

    Log是开发过程中.对于我们调试程序非常重要的一个工具,有非常多时候,我们正是通过Log才干够看清楚程序是不是真的依照我们想像中的模式在跑,从而定位到问题所在的地方.而在Android开发中,毫无疑问 ...

  6. Android中的SQLite使用学习

    Android中的SQLite使用学习 SQLite是非常流行的嵌入式关系型数据库,轻载, 速度快,而且是开源.在Android中,runtime提供SQLite,所以我们可以使用SQLite,而且是 ...

  7. android中使用jni对字符串加解密实现分析

    android中使用jni对字符串加解密实现分析 近期项目有个需求.就是要对用户的敏感信息进行加密处理,比方用户的账户password,手机号等私密信息.在java中,就对字符串的加解密我们能够使用A ...

  8. 深入理解Android(5)——从MediaScanner分析Android中的JNI

    前面几篇介绍了Android中的JNI和基本用法,这一篇我们通过分析Android源代码中的JNI实例,来对JNI部分做一个总结. 一.通向两个不同世界的桥梁 在前面我们说过,JNI就像一个桥梁,将J ...

  9. 深入理解Android(2)——理解Android中的JNI(中)

    阳光小强参加了CSDN博客之星评选,如果你觉得阳光小强的博客对你有所帮助,为小强投上一票吧:http://vote.blog.csdn.net/blogstar2014/details?usernam ...

随机推荐

  1. Unity C# 关于设计模式的思考

    一.当你的项目发现有如下问题之一时,就需要考虑重构代码,可能会有某种模式适合. 1.代码无法进行单元测试. 2.需求的变动总是导致代码的变动. 3.有重复代码的存在. 4.继承层次过多. 5.隐藏的依 ...

  2. Linux下的ioctl()函数详解

    我这里说的ioctl函数是指驱动程序里的,因为我不知道还有没有别的场合用到了它,所以就规定了我们讨论的范围.写这篇文章是因为我前一阵子被ioctl给搞混了,这几天才弄明白它,于是在这里清理一下头脑. ...

  3. MyBatis学习总结(10)——批量操作

    一.mybatis中的批量操作    批量操作核心就是一次传入多个数据然后进行相关操作,增删改查中掌握其中一个其他的也不成问题 1.最新在做的短信平台,要批量插入群发的短信记录: 当然批量操作还有:批 ...

  4. C++调用Lua的性能測试

    游戏服务器经典的架构就是C++和Lua的结合,C++开发主体框架.Lua实现一些复杂的逻辑.我们都知道Lua是一种很快的语言.可是究竟有多块.我们測试下看看. C++调用Lua的性能測试.发现不正确的 ...

  5. iOS framework配置脚本

    # Sets the target folders and the final framework product. FMK_NAME=HovnVoipEngine FMK_VERSION=1.0 # ...

  6. Unity UGUI——UI基础,Canvas

    主题:画布--Canvas 内容:创建Canvas UI控件的绘制顺序 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTXJfQUhhbw==/font/5 ...

  7. git commit template

    https://www.zhihu.com/question/27462267/answer/204658544 https://gist.github.com/adeekshith/cd4c95a0 ...

  8. how to backup and restore database of SQL Server

    Back up 1,右键选中需要备份的数据库,Tasks-->Backup 2.General中,Destination,先remove掉之前的,然后再Add 需要注意的是,add的文件,必须要 ...

  9. Hadoop的多节点集群详细启动步骤(3或5节点)

    版本1 利用自己写的脚本来启动,见如下博客 hadoop-2.6.0-cdh5.4.5.tar.gz(CDH)的3节点集群搭建 hadoop-2.6.0.tar.gz的集群搭建(3节点) hadoop ...

  10. codeforces1114D. Flood Fill(区间Dp)

    传送门: 解题思路: 区间Dp,发现某一个区间修改后区间颜色一定为左边或右边的颜色. 那么只需要设方程$f_(l,r,0/1)$表示区间$[l,r]$染成左/右颜色的最小代价 转移就是枚举左右颜色就好 ...