一天掌握Android JNI本地编程 快速入门
一、JNI(Java Native Interface)
private native String getStringFromC();
3、在jni中创建一个C文件,定义一个函数实现本地方法,函数名必须用使用 本地方法的全类名,点改为下划线。
#include <stdio.h>
#include <stdlib.h>
#include <jni.h>
//方法名必须为本地方法的全类名点改为下划线,穿入的两个参数必须这样写,
//第一个参数为Java虚拟机的内存地址的二级指针,用于本地方法与java虚拟机在内存中交互
//第二个参数为一个java对象,即是哪个对象调用了这个 c方法
jstring Java_com_mwp_jnihelloworld_MainActivity_getStringFromC(JNIEnv* env,
jobject obj){
//定义一个C语言字符串
char* cstr = "hello form c";
//返回值是java字符串,所以要将C语言的字符串转换成java的字符串
//在jni.h 中定义了字符串转换函数的函数指针
//jstring (*NewStringUTF)(JNIEnv*, const char*);
//第一种方法:很少用
jstring jstr1 = (*(*env)).NewStringUTF(env, cstr);
//第二种方法,推荐
jstring jstr2 = (*env) -> NewStringUTF(env, cstr);
return jstr2;
}
4、在jni中创建 Android.mk文件,用于配置 本地方法
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#编译生成的文件的类库叫什么名字
LOCAL_MODULE := hello
#要编译的c文件
LOCAL_SRC_FILES := Hello.c
include $(BUILD_SHARED_LIBRARY)5、在jni目录下执行 ndk-build.cmd指令,编译c文件
static{
//加载打包完毕的 so类库
System.loadLibrary("hello");
}
7、jni打包的C语言类库默认仅支持 arm架构,需要在jni目录下创建 Android.mk 文件添加如下代码可以支持x86架构
APP_ABI := armeabi armeabi-v7a x86
四、JNI常见错误
#include <jni.h>
#include <string.h>
//将java字符串转换为c语言字符串(工具方法)
char* Jstring2CStr(JNIEnv* env, jstring jstr)
{
char* rtn = NULL;
jclass clsstring = (*env)->FindClass(env,"java/lang/String");
jstring strencode = (*env)->NewStringUTF(env,"GB2312");
jmethodID mid = (*env)->GetMethodID(env,clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr= (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); // String .getByte("GB2312");
jsize alen = (*env)->GetArrayLength(env,barr);
jbyte* ba = (*env)->GetByteArrayElements(env,barr,JNI_FALSE);
if(alen > 0)
{
rtn = (char*)malloc(alen+1); //"\0"
memcpy(rtn,ba,alen);
rtn[alen]=0;
}
(*env)->ReleaseByteArrayElements(env,barr,ba,0); //
return rtn;
}
JNIEXPORT jstring JNICALL Java_com_mwp_encodeanddecode_MainActivity_encode
(JNIEnv * env, jobject obj, jstring text, jint length){
char* cstr = Jstring2CStr(env, text);
int i;
for(i = 0;i<length;i++){
*(cstr+i) += 1; //加密算法,将字符串每个字符加1
}
return (*env)->NewStringUTF(env,cstr);
}
JNIEXPORT jstring JNICALL Java_com_mwp_encodeanddecode_MainActivity_decode
(JNIEnv * env, jobject obj, jstring text, jint length){
char* cstr = Jstring2CStr(env, text);
int i;
for(i = 0;i<length;i++){
*(cstr+i) -= 1;
}
return (*env)->NewStringUTF(env, cstr);
}
public class MainActivity extends Activity { static{
System.loadLibrary("encode");
}
int[] array = {1,2,3,4,5};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} public void click(View v){
encodeArray(array);
//不需要返回值,实际操作的是同一块内存,内容已经发生了改变
for (int i : array) {
System.out.println(i);
}
} //传递数组其实是传递一个堆内存的数组首地址的引用过去,所以实际操作的是同一块内存,
//当调用完方法,不需要返回值,实际上参数内容已经改变,
//Android中很多操作硬件的方法都是这种C语言的传引用的思路,要非常熟练
private native void encodeArray(int[] arr);
}
#include <jni.h>
/*
* Class: com_mwp_jniarray_MainActivity
* Method: encodeArray
* Signature: ([I)V
*/
JNIEXPORT void JNICALL Java_com_mwp_jniarray_MainActivity_encodeArray
(JNIEnv * env, jobject obj, jintArray arr){
//拿到整型数组的长度以及第0个元素的地址
//jsize (*GetArrayLength)(JNIEnv*, jarray);
int length = (*env)->GetArrayLength(env, arr);
// jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);
int* arrp = (*env)->GetIntArrayElements(env, arr, );
int i;
for(i = ;i<length;i++){
*(arrp + i) += ; //将数组中的每个元素加10
}
}
public class MainActivity extends Activity { static{
//加载美图秀秀的类库
System.loadLibrary("mtimage-jni");
}
private ImageView iv;
private Bitmap bitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); iv = (ImageView) findViewById(R.id.iv); bitmap = BitmapFactory.decodeFile("sdcard/aneiyi.jpg");
iv.setImageBitmap(bitmap);
} public void click(View v){ int width = bitmap.getWidth();
int height = bitmap.getHeight(); //用于保存所有像素信息的数组
int[] pixels = new int[width*height];
//获取图片的像素颜色信息,保存至pixels
bitmap.getPixels(pixels, 0, width, 0, 0, width, height); JNI jni = new JNI();
//调用美图秀秀本地库中的美图方法,靠猜
//arg0:保存了所有像素颜色信息的数组
//arg1:图片的宽
//arg2:图片的高
//此方法是通过改变pixels的像素颜色值来实现美化效果,传递一个数组参数是不需要返回值的
jni.StyleLomoB(pixels, width, height); Bitmap bmNew = Bitmap.createBitmap(pixels, width, height, bitmap.getConfig());
iv.setImageBitmap(bmNew);
}
}
public class MainActivity extends Activity {
static{
System.loadLibrary("hello");
} @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} public void click(View v){
cLog();
} public native void cLog(); public void show(String message){
Builder builder = new Builder(this);
builder.setTitle("标题");
builder.setMessage(message);
builder.show();
} }
#include <jni.h>
#include <android/log.h>
#define LOG_TAG "System.out"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
JNIEXPORT void JNICALL Java_com_mwp_ccalljava2_MainActivity_cLog
(JNIEnv * env, jobject obj){
//打印log输出
LOGD("我是C语言打印的debug日志");
LOGI("我是C语言打印的info日志");
//通过反射来调用java的方法,需要知道方法签名,使用javap得到方法签名
//在bin/classes目录下执行 javap -s 全类名
//1、得到类的字节码对象
//jclass (*FindClass)(JNIEnv*, const char*);
jclass clazz = (*env)->FindClass(env, "com/mwp/ccalljava2/MainActivity");
//jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
jmethodID methodID = (*env)->GetMethodID(env, clazz, "show", "(Ljava/lang/String;)V");
//void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
(*env)->CallVoidMethod(env,obj,methodID, (*env)->NewStringUTF(env, "这是弹窗的内容"));
}
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS += -llog
LOCAL_MODULE := hello
LOCAL_SRC_FILES := log.c
include $(BUILD_SHARED_LIBRARY)
十、模拟监测压力传感器
public class MainActivity extends Activity {
static{
System.loadLibrary("monitor");
}
private MyProgressBar mpb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); mpb = (MyProgressBar) findViewById(R.id.mpb);
mpb.setMax(100);
} public void start(View v){
new Thread(){
public void run() {
startMonitor();
};
}.start();
} public void stop(View v){
stopMonitor();
} public native void startMonitor();
public native void stopMonitor(); //供本地方法调用刷新UI
public void show(int pressure){
mpb.setPressure(pressure);
}
}
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
//模拟压力传感其传递数据
int getPressure(){
return rand()%;
}
//用于控制循环的开关
int monitor;
JNIEXPORT void JNICALL Java_com_mwp_monitor_MainActivity_startMonitor
(JNIEnv * env, jobject obj){
monitor = ;
int pressure;
jclass clazz;
jmethodID methodid;
while(monitor){
//本地方法获取传感器数据
pressure= getPressure();
//使用反射调用java方法刷新界面显示
//jclass (*FindClass)(JNIEnv*, const char*);
clazz= (*env)->FindClass(env, "com/mwp/monitor/MainActivity");
//jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
methodid= (*env)->GetMethodID(env, clazz, "show","(I)V");
// void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
(*env)->CallVoidMethod(env, obj, methodid, pressure);
sleep();
}
}
JNIEXPORT void JNICALL Java_com_mwp_monitor_MainActivity_stopMonitor
(JNIEnv * env, jobject obj){
//结束循环
monitor = ;
}
#include <jni.h>
#include "com_mwp_cplusplus_MainActivity.h"
JNIEXPORT jstring JNICALL Java_com_mwp_cplusplus_MainActivity_helloC
(JNIEnv * env, jobject obj){
char* cstr = "hello from c";
//return (*env)->NewStringUTF(env, cstr);
return env->NewStringUTF(cstr);
}
一天掌握Android JNI本地编程 快速入门的更多相关文章
- .Net Core WebAPI 基于Task的同步&异步编程快速入门
.Net Core WebAPI 基于Task的同步&异步编程快速入门 Task.Result async & await 总结 并行任务(Task)以及基于Task的异步编程(asy ...
- COM编程快速入门
COM编程快速入门 COM编程快速入门 http://www.vckbase.com/index.php/wv/1642 COM是一种跨应用和语言共享二进制代码的方法.与C++不同,它提倡源代码重 ...
- Haskell 函数式编程快速入门【草】
什么是函数式编程 用常规编程语言中的函数指针.委托和Lambda表达式等概念来帮助理解(其实函数式编程就是Lambda演算延伸而来的编程范式). 函数式编程中函数可以被非常容易的定义和传递. Hask ...
- Android JNI&NDK编程小结及建议
前言 由于网上关于JNI/NDK相关的知识点介绍的比较零散而且不具备参照性,所以写了这篇JNI/NDK笔记,便于作为随时查阅的工具类型的文章,本文主要的介绍了在平时项目中常用的命令.JNI数据类型.签 ...
- Android jni/ndk编程二:jni数据类型转换(primitive,String,array)
一.数据类型映射概述 从我们开始jni编程起,就不可能避开函数的参数与返回值的问题.java语言的数据类型和c/c++有很多不同的地方,所以我们必须考虑当在java层调用c/c++函数时,怎么正确的把 ...
- Android JNI 本地开发接口
前言 我们为什么要用JNI --> 高效.扩展 高效:Native code效率高,数学运算,实时渲染的游戏上,音视频处理 (极品飞车,opengl,ffmpeg,文件压缩,图片处理-) 扩展: ...
- Android jni/ndk编程五:jni异常处理
在Java的编程中,我们经常会遇到各种的异常,也会处理各种的异常.处理异常在java中非常简单,我们通常会使用try-catch-finally来处理,也可以使用throw简单抛出一个异常.那么在jn ...
- Android jni/ndk编程四:jni引用类型
一.JNI引用类型 JNI支持三种类型的 opaque reference:local references, global references,和weak global references,下面 ...
- Android jni/ndk编程三:native访问java
一.访问静态字段 Java层的field和method,不管它是public,还是package.private和protected,从 JNI都可以访问到,Java面向语言的封装性不见了. 静态字段 ...
随机推荐
- 数往知来 HTML<十一>
HTML_CSS <!--一.表单 <form></form> 表单就是用来进行数据提交的标签 表单就是一对<form></form>标 ...
- 【转】GUID学习
概念 GUID: 即Globally Unique Identifier(全球唯一标识符) 也称作 UUID(Universally Unique IDentifier) . GUID是一个通过特定算 ...
- Camel In Action 阅读笔记 第一部分概述 + 第一章概述 认识Camel
第一部分: 最开始的一小步 Apache Camel 是一个开源集成框架,其目的是让系统集成变得更加简便,在本书的第一章中,我们会为您介绍它并向您展示它是如何在大型企业应用中做好集成工作.您也会了解到 ...
- Oracle 表空间修改字段大小
1.修改字段大小 当表中已经存在数据,就不能直接修改某字段大小,需要新建一个字段来过渡 ALTER TABLE TABLE RENAME COLUMN GRP TO FUND_GRP_1; ); ...
- 省时的浏览器同步测试工具 browsersync NodeJS
http://www.browsersync.cn/ 省时的浏览器同步测试工具 Browsersync能让浏览器实时.快速响应您的文件更改(html.js.css.sass.less等)并自动刷新页面 ...
- js运动 多物体运动含Json 但是里面数值不一样
<!doctype html> <html> <head> <meta charset = "utf-8"> <title&g ...
- Microsoft Office Excel 不能访问文件“XXXXXXXXXXXXX.xls”。 可能的原因有:
解决办法:1. 1).通过webconfig中增加模拟,加入管理员权限, <identity impersonate="true" userName="系统管理员& ...
- Debugging Information in Separate Files
[Debugging Information in Separate Files] gdb allows you to put a program's debugging information in ...
- Java模板引擎 FreeMarker
@(编程) [TOC] 1. 简介 FreeMarker是一个模板引擎,一个基于模板生成文本输出的通用工具,使用纯Java编写.它是为Java程序员提供的一个开发包.它不是面向最终用户的,而是为程序员 ...
- nginx打开目录游览功能
#开启索引功能 location / { autoindex on; autoindex_exact_size off; autoindex_localtime on; } #别名目录location ...