先啰嗦一段,从学习Android以来一直会看到这个JNI,偶尔也看到要写c/c++的代码,其实从心里就是有些排斥的,毕竟我学的是Java,我学习一个JNI我还得学会c++,c其实是学了一遍了,但是长期不用基本也就忘了,虽然基本的都是看得懂的,但是编码并不是看得懂就行的,要自己能写,所以其实打心底是排斥JNI的.但是学习Android的时间越长,我发现JNI是支撑Android运行的一大模块,比如我们常见的那些播放音频的功能其实底层就是使用了JNI,这样子就让Java代码可以调用底层的c代码,从而可以操纵硬件的目的,所以其实JNI我们可以理解为Java和(c/c++)之间的桥梁,举例一段源码:

MediaPlayer m = new MediaPlayer();m.start();
/*** Starts or resumes playback. If playback had previously been paused,* playback will continue from where it was paused. If playback had* been stopped, or never started before, playback will start at the* beginning.** @throws IllegalStateException if it is called in an invalid state*/public  void start() throws IllegalStateException {    stayAwake(true);    _start();}private native void _start() throws IllegalStateException;

这是播放音频控件的开始播放方法的有关源码,我们可以看到,在start()方法中,调用了一个_start()的方法,这个方法是用native关键字标识的,这就是我们以前经常听到的本地方法,意思就是说这个方法的具体实现是通过c/c++代码实现的,这就是JNI的简单案例

ndk环境的搭建,这里亲们就去谷歌官网去下载就行了,下载完毕解压,然后在eclipse里面关联一下即可

Android JNI入门_第1张图片

下面让我带大家入门

我带大家做一个简单的加法来学习JNI,首先我们得声明一个方法

private native int add(int i,int j);

方法类似于上面的_start()方法是没有方法体的,类似于接口中的方法声明对不对,没有方法体,然后我们在activity的oncreate()方法中调用这个方法来实现

@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);int result = add(3,5);System.out.println("result == " + result);}

调用的时候就和普通方法一样调用就可以了,这样子就可以了?

很明显这样子不够,因为方法的实现我们还没做呢!我们说实现是需要c/c++来实现的,这里设计到书写c/c++代码了.

步骤:

1.在项目根目录建立一个文件夹jni,里面用来书写c/c++代码

Android JNI入门_第2张图片

2.在jni文件夹下新建一个c/c++源码文件


3.里面自然需要实现我们之前定义个那个方法add了

int add(int i, int j){return i + j;}
c中写一个add方法就是上面这样子书写的,但是使用JNI的时候需要加上JNI的一些规范
首先就是方法名字,规范如下:

Java_包名_类名_方法名

所以代码就需要改成这样子

int Java_com_example_day01_MainActivity_add(int i, int j){return i + j;}
都是用下划线隔开的,请注意,然后就是参数列表,这里有两个参数是固定的,必须要写,如下:

int Java_com_example_day01_MainActivity_add(JNIEnv* e, jobject thiz, int i,int j) {return i + j;}

可以看到这里多了两个参数,一个是JNIEnv*和jobject

JNIEnv*:这里做一下解释,我们的java代码是运行在虚拟机里面的,所以利用JNI在实现功能的同时,需要用到虚拟机环境的指针,也就是需要环境的支持,并且这是一个指针,指向运行环境

jobject是调用方法的时候的对象,这里也就是我们的MainActivity对象

做完了这一切我们就实现了add方法,当然了别忘了添加一些必要的头文件,完整的c代码是

#include <stdio.h>#include <stdlib.h>#include <jni.h>jint Java_com_example_day01_MainActivity_add(JNIEnv* e, jobject thiz, int i,int j) {return i + j;}
这里有一个jni.h头文件是使用jni功能所必需的,还有这里的返回值jint,其实就是谷歌为了让代码更有可读性预定义的一些名字,这里我点进去

Android JNI入门_第3张图片

可以看到就是一个int,这里也做一个解释,为啥要这样子,直接适应int不是挺好的.

其实这里你用int和jint都是没有什么区别的,但是我们想一下,在c中是没有对象的概念的,加入你java里面传入的是一个数组,或者传入一个对象,在c中都是一个指针而已,指向了你传入的对象,在c中都是void*表示,这时候你写的代码过几天去看,你还知道当初的void*这里的参数,到底是数组呢还是对象,还是字符串呢?你不知道了,你只能去调用的地方去瞧瞧,很明显这里降低了代码的可阅读性,所以谷歌工程师为我们预定义了很多的关键字来表示不同的对象

typedef void*           jobject;typedef jobject         jclass;typedef jobject         jstring;typedef jobject         jarray;typedef jarray          jobjectArray;typedef jarray          jbooleanArray;typedef jarray          jbyteArray;typedef jarray          jcharArray;typedef jarray          jshortArray;typedef jarray          jintArray;typedef jarray          jlongArray;typedef jarray          jfloatArray;typedef jarray          jdoubleArray;typedef jobject         jthrowable;typedef jobject         jweak;

可以看到这些的本质的是void*,但是我们可以用jobject和jarray这些来说明参数的含义,这样子就可阅读性很强

最后我们写的c/c++代码最后都会被打包成.so文件,所以我们使用的时候需要在Avtivity里面先加载类库

public class MainActivity extends Activity {static {System.loadLibrary("hello");}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);int result = add(3,5);System.out.println("result == " + result);}private native int add(int i,int j);}

我们的.so文件要打包成功还需要有一个android.mk,直接从ndk自带的例子里面复制过来就行了

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE    := helloLOCAL_SRC_FILES := hello.cinclude $(BUILD_SHARED_LIBRARY)
里面就是这几句话,只要修改hello所在的地方就可以了,你可以把上面的两个hello改成其他的任意名字

利用ndk里面的ndk-build.cmd进行打包我们的c代码

当然了用eclipse关联了ndk之后,直接运行项目就可以了,打包的工作交给eclipse

Android JNI入门_第4张图片

更多相关文章

  1. Android通过原生方式获取经纬度与城市信息的方法
  2. Android搜索控件的基本使用方法
  3. Android官方离线文档(API文档)打开速度慢的解决方法
  4. Android IPC机制(三)在Android Studio中使用AIDL实现跨进程方法调
  5. Android中微信主界面菜单栏的布局实现代码
  6. android实现观察者模式的几种方法
  7. Android Studio怎样提示函数使用方法

随机推荐

  1. android图片拖动
  2. android获取3G或wifi流量信息
  3. 2013.12.03(6) ——— android ActionbarSh
  4. 攔截Android的SMS並且停止轉發
  5. Android处理线程暂停与恢复
  6. Android如何监听输入框的出现和隐藏
  7. android中异步加载图片信息
  8. android 自带 xml解析
  9. Android(安卓)Menu(Context Menu,Options
  10. Android读取设备内存大小