转载请注明原文地址
笔者把Android重难点和读书笔记都整理在github上:https://github.com/miomin/AndroidDifficulty
如果你觉得对你有帮助的话,希望可以star/follow一下哟,我会持续保持更新。
(1)在Java代码中声明本地方法
(2)实现Java本地接口(JNI)粘合层
(3)创建Android makefile文件(Android Studio不需要,Gradle代替)
(4)使用C/C++实现native方法
(5)编译native库
(6)加载native库
private static native long fibonacciNative(int n);
写好之后clean然后rebuild,可以看到生成了classes文件夹。
cd app/build/intermediates/classes/debug
javah -jni com.scu.miomin.learnndk.JniUtils
这个时候查看debug文件夹,可以看到多了一个.h文件,剪切一下,在scr/main下创建jni文件夹,把这个.h文件粘贴进去。
下面上代码
com_scu_miomin_learnndk_JniUtils.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class com_scu_miomin_learnndk_JniUtils */
#ifndef _Included_com_scu_miomin_learnndk_JniUtils
#define _Included_com_scu_miomin_learnndk_JniUtils
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jlong JNICALL Java_com_scu_miomin_learnndk_JniUtils_fibonacciNative
(JNIEnv *, jclass, jint);
#ifdef __cplusplus
}
#endif
#endif
//
// Created by miomin on 2015/8/29.
//
#include "com_scu_miomin_learnndk_JniUtils.h"
#include "fibonacci.h"
JNIEXPORT jlong JNICALL Java_com_scu_miomin_learnndk_JniUtils_fibonacciNative
(JNIEnv *env, jobject obj, jint n) {
return fibonacci(n);
}
//
// Created by 莫绪旻 on 16/5/14.
//
#ifndef LEARNNDK_FIBONACCI_H
#define LEARNNDK_FIBONACCI_H
#include
extern long fibonacci(unsigned int n);
#endif //LEARNNDK_FIBONACCI_H
//
// Created by miomin on 2015/8/29.
//
#include "fibonacci.h"
long fibonacci(unsigned int n) {
if (n > 1) return fibonacci(n - 2) + fibonacci(n - 1);
return n;
}
在gradle.properties文件末尾添加android.useDeprecatedNdk=true
在app下的build.gradle中defaultConfig括号内添加如下代码
ndk {
moduleName "JniUtils" //生成的so名字
abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种abi体系结构下的so库,目前可有可无。
}
static {
try {
System.loadLibrary("JniUtils");//之前在build.gradle里面设置的so名字,必须一致}
success = true;
} catch (Throwable e) {
}
}
/**
* Created by miomin on 16/5/13.
*/
public class JniUtils {
private static final boolean useNative;
static {
boolean success;
try {
System.loadLibrary("JniUtils");//之前在build.gradle里面设置的so名字,必须一致}
success = true;
} catch (Throwable e) {
success = false;
}
useNative = success;
}
public static long fibonacci(int n) {
if (useNative)
return fibonacciNative(n);
return fibonacciJava(n);
}
private static long fibonacciJava(int n) {
if (n > 1)
return fibonacciJava(n - 2) + fibonacciJava(n - 1);
return n;
}
private static native long fibonacciNative(int n);
}
在JNI中使用字符串参数传递,经常会导致性能问题,Java使用Unicode编码字符串,而C/C++使用char*(ASC或UTF-8),Java的字符串必须转换成C/C++字符串才能使用。看下面的例子:
JniUtils.java
public static void withString(String s) {
if (useNative)
withStringNative(s);
else
withStringNative(s);
}
private static void withStringJava(String s) {
}
private static native void withStringNative(String s);
JNIEXPORT void Java_com_scu_miomin_learnndk_JniUtils_withStringNative
(JNIEnv *env, jobject obj, jstring s) {
const char *str = (*env)->GetStringUTFChars(env, s, NULL);
if (str != NULL) {
// 使用str
// 释放字符串,否则会内存泄漏
(*env)->ReleaseStringChars(env, s, str);
}
}
static {
boolean success;
try {
System.loadLibrary("JniUtils");//之前在build.gradle里面设置的so名字,必须一致}
success = true;
} catch (Throwable e) {
success = false;
}
useNative = success;
if (success)
getIds();
}
// 避免每次访问域时都去获取一次id,应该在类加载时获取,只执行一次
private static native void getIds();
public static int i = 0;
public static void sayHello() {
if (useNative)
sayHelloNative();
else
sayHelloJava();
}
private static native void sayHelloNative();
private static void sayHelloJava() {
}
public static void callFromJNI() {
Log.i("miomin", "callFromJni");
}
static jfieldID iId;
static jfieldID callFromJNIId;
JNIEXPORT void JNICALL Java_com_scu_miomin_learnndk_JniUtils_sayHelloNative
(JNIEnv *env, jclass clazz) {
// 增加i
jint i = (*env)->GetStaticIntField(env, clazz, iId);
(*env)->SetStaticIntField(env, clazz, callFromJNIId, i + 1);
// 调用callFromJNI
(*env)->CallStaticVoidMethod(env, clazz, callFromJNIId);
}
JNIEXPORT void JNICALL Java_com_scu_miomin_learnndk_JniUtils_getIds
(JNIEnv *env, jclass clazz) {
// 获取i的域和callFromJNI方法的id
iId = (*env)->GetStaticFieldID(env, clazz, "i", "I");
callFromJNIId = (*env)->GetStaticMethodID(env, clazz, "callFromJNI", " ()V");
}