【Android性能优化】使用NDK进行Java和C++混编
2016-05-15 09:53
681 查看
转载请注明原文地址
笔者把Android重难点和读书笔记都整理在github上:https://github.com/miomin/AndroidDifficulty
如果你觉得对你有帮助的话,希望可以star/follow一下哟,我会持续保持更新。
(2)实现Java本地接口(JNI)粘合层
(3)创建Android makefile文件(Android Studio不需要,Gradle代替)
(4)使用C/C++实现native方法
(5)编译native库
(6)加载native库
写好之后clean然后rebuild,可以看到生成了classes文件夹。
继续输入命令,生成头文件。
这个时候查看debug文件夹,可以看到多了一个.h文件,剪切一下,在scr/main下创建jni文件夹,把这个.h文件粘贴进去。
下面上代码
com_scu_miomin_learnndk_JniUtils.h
jni.c
fibonacci.h
fibonacci.c
在app下的build.gradle中defaultConfig括号内添加如下代码
JniUtils.java
jni.c
JniUtils.c
笔者把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.javaprivate 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 <jni.h> /* 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
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 <stdio.h> 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.javastatic { 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"); }
相关文章推荐
- Android:Intent Filter 过滤器与隐式Intent
- Android LayoutInflater详解
- Android ListView,GridView,ScrollView,ProgressBar,SeekBar,RelativeLayout,EditText常用属性
- Android studio 导入项目
- Android四大组件说明
- 在android studio中使用NDK(1)
- Androidstudio中自定义字体
- android开发笔记之权限大全
- android开发笔记之多媒体—VideoView播放视频
- [Android]Binder池的使用
- android 闪屏分析及解决方案
- Android成长之路(6)——数据持久化处理
- Android消息机制
- Miko Android自学之路 WifiDirect中文最强详解,如何传输数据,如何设置GroupOwener,如何设置客户端以及服务器端
- 浅谈android中的图片处理之基本绘图(一)
- Android 判断字符串是数字、中文还是字母的方法
- Android杂谈--ListView之BaseAdapter的使用
- 【安卓小笔记】Android的日志工具Log
- android 使用volley下载文件和加载gif图片
- android开发笔记之多媒体—SoundPool(音效池)