转载请注明原文地址

笔者把Android重难点和读书笔记都整理在github上:https://github.com/miomin/AndroidDifficulty

如果你觉得对你有帮助的话,希望可以star/follow一下哟,我会持续保持更新。


一、Java和C/C++混编的步骤

(1)在Java代码中声明本地方法
(2)实现Java本地接口(JNI)粘合层
(3)创建Android makefile文件(Android Studio不需要,Gradle代替)
(4)使用C/C++实现native方法
(5)编译native库
(6)加载native库

1、声明本地方法

  • JniUtils.java
private static native long fibonacciNative(int n);

  写好之后clean然后rebuild,可以看到生成了classes文件夹。

2、实现JNI粘合层

  • 打开Terminal,输入命令,进入到debug文件夹。
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 __cplusplusextern "C" {#endifJNIEXPORT jlong JNICALL Java_com_scu_miomin_learnndk_JniUtils_fibonacciNative        (JNIEnv *, jclass, jint);#ifdef __cplusplus}#endif#endif
  • jni.c
//// 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);}
  • fibonacci.h
//// 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
  • fibonacci.c
//// 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;}

3、配置gradle

  • 在gradle.properties文件末尾添加android.useDeprecatedNdk=true

  • 在app下的build.gradle中defaultConfig括号内添加如下代码

ndk {    moduleName "JniUtils"  //生成的so名字    abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种abi体系结构下的so库,目前可有可无。}

4、加载native库

  • 在JniUtils.java中添加如下static代码块
static {        try {            System.loadLibrary("JniUtils");//之前在build.gradle里面设置的so名字,必须一致}            success = true;        } catch (Throwable e) {        }}

5、为Native提供备用的Java方案

  • 有些设备不能支持NDK所支持的所有ABI的任意一种,这时候就调用不了native方法,为了方式应用奔溃,我们提供如下解决方案。
/** * 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的信息

1、JNI字符串

  • 在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);
  • jni.c
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);    }}

2、在JNI中访问Java对象或方法

  • JniUtils.java
    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");    }
  • JniUtils.c
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");}

更多相关文章

  1. Android实现类似excel表格的方法整理
  2. 一文彻底搞懂Android(安卓)View的绘制流程
  3. 剖析 Android(安卓)架构组件之 ViewModel
  4. AIDL跨进程通信和Service调用
  5. Android(安卓)ContentProvider 使用
  6. Android(安卓)TV框架TIF
  7. android中setNegativeButton和setNeutralButton的区别是什么?
  8. Android(安卓)Material Design之Snackbar
  9. Android(安卓)ANR介绍与避免

随机推荐

  1. 关键字弹出动画
  2. 服务android
  3. Android(安卓)版本号等等获取
  4. android 高德地图定位(地理位置) 笔记
  5. android接收mjpg-streamer软件视频流
  6. Chapter 2 Navigating Android(安卓)Stud
  7. SignApk.java 源码
  8. Android(安卓)ViewPager实现相册
  9. android 设置圆角图片实现代码
  10. 五分钟学会之AsyncTask