初学JNI(二)调用C\C++中的方法
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center">
<TextView
android:id="@+id/tv_call"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Hello World, MyActivity"
android:padding="10dp"
android:gravity="center" />
<Button
android:id="@+id/btn_call"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Call" />
<Button
android:id="@+id/btn_send_int"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="传递int参数" />
<Button
android:id="@+id/btn_send_str"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="传递String参数" />
<Button
android:id="@+id/btn_ints"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="传递int数组" />
</LinearLayout>
Java代码:
public class MyActivity extends Activity implements View.OnClickListener {
DataProvider mPro;
/**
* 使用静态代码块加载库文件
*/
static {
System.loadLibrary("Hello");
}
public native String helloFromJNI ();
/**
* Called when the activity is first created.
*/
@Override
public void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mPro = new DataProvider();
initView();
}
TextView mTvCall;
private void initView () {
mTvCall = (TextView) findViewById(R.id.tv_call);
Button btnCall = (Button) findViewById(R.id.btn_call);
Button btnInts = (Button) findViewById(R.id.btn_ints);
Button btnInt = (Button) findViewById(R.id.btn_send_int);
Button btnStr = (Button) findViewById(R.id.btn_send_str);
btnCall.setOnClickListener(this);
btnInt.setOnClickListener(this);
btnInts.setOnClickListener(this);
btnStr.setOnClickListener(this);
}
@Override
public void onClick (View v) {
int id = v.getId();
switch (id) {
case R.id.btn_call:
//调用C\C++中的方法输出"你好 from C++."
mTvCall.setText(helloFromJNI());
Toast.makeText(MyActivity.this, helloFromJNI(), Toast.LENGTH_LONG).show();
break;
case R.id.btn_send_int:
//向C++代码中传递两个int型参数
mTvCall.setText(String.valueOf(mPro.add(10, 20)));
break;
case R.id.btn_send_str:
//向C++代码中传递一个String型参数
mTvCall.setText(mPro.sayHello(" JNI"));
break;
case R.id.btn_ints:
//向C++代码中传递int数组
int[] arr = mPro.intMethod(new int[]{30, 40});
StringBuilder sb = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1)
sb.append(arr[i]);
else
sb.append(arr[i]).append(",");
}
mTvCall.setText(sb.toString());
break;
}
}
}
在定义native方法时,并不推荐直接定义在Activity中,而是专门建立一个定义native方法的类:
*/
public class DataProvider {
static{
System.loadLibrary("Hello");
}
public native int add(int x,int y);
public native String sayHello(String str);
public native int[] intMethod(int[] numbers);
}
C++代码的实现:
#include <iostream>
#include <string>
#include <malloc.h>
#include <jni.h>
#include "com_chen_jni_demo_MyActivity.h"
#include "com_chen_jni_demo_DataProvider.h"
using namespace std;
//导入Log
#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__)
//jni.h没有导入的话,编译时会出现符号错误的问题
//使用C++实现输出
JNIEXPORT jstring JNICALL Java_com_chen_jni_demo_MyActivity_helloFromJNI
(JNIEnv * env, jobject obj){
char* cstr = "你好 from C++.";
LOGI("DEBUG %s",cstr);
return (*env).NewStringUTF(cstr);
}
//向C++代码中传递一个String型参数
JNIEXPORT jstring JNICALL Java_com_chen_jni_demo_DataProvider_sayHello
(JNIEnv * env, jobject obj, jstring jstr){
//声明要调用的函数
char* jstringTostring(JNIEnv* env, jstring jstr);
//将java字符串转换为c++中的字符数组
char* str1=jstringTostring(env,jstr);
char* str2="你好";
//拼接字符数组
strcat(str1,str2);
return (*env).NewStringUTF(str1);
}
//向C++代码中传递两个int型参数
JNIEXPORT jint JNICALL Java_com_chen_jni_demo_DataProvider_add
(JNIEnv * env, jobject obj, jint x, jint y){
return x+y;
}
//向C++代码中传递一个int数组
JNIEXPORT jintArray JNICALL Java_com_chen_jni_demo_DataProvider_intMethod
(JNIEnv * env,jobject obj, jintArray jintArr){
//获得整型数组的长度
jsize size = (*env).GetArrayLength(jintArr);
//jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);
//jboolean* 表示获得数据的方式 true-1-复制 false-0-引用 c语言中
jint* arr = (*env).GetIntArrayElements(jintArr,false);
for(int i=0;i<size;i++){
//第一种
//*(arr+i) = *(arr+i)+10;
//*(arr+i) +=10;
/*
第二种
void (*SetIntArrayRegion)(JNIEnv*, jintArray,jsize, jsize, const jint*);
设置IntArray中指定范围内元素的值
参数3:范围的起始位置
参数4:范围的擦海南过度(指定修改的元素的个数)
参数5:const jint* 指定元素的值(地址)
*/
int temp = *(arr+i)+10;
(*env).SetIntArrayRegion(jintArr,i,1,&temp);
}
//使用的是引用方式,直接返回即可,数据已经改变
return jintArr;
}
/**
*将Java的String转换为char*
*/
jstring stoJstring (JNIEnv*env, const char*pat) {
jclass strClass = env -> FindClass("Ljava/lang/String;");
jmethodID ctorID = env -> GetMethodID(strClass, "", "([BLjava/lang/String;)V");
jbyteArray bytes = env -> NewByteArray(strlen(pat));
env -> SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte *)pat); jstring encoding = env -> NewStringUTF("utf-8");
return (jstring) env -> NewObject(strClass, ctorID, bytes, encoding);
}
//invoke function
JNIEXPORT jstring JNICALL Java_test_cs_web_SWIFTAlianceCASmfTest_strcal (JNIEnv*env, jclass obj, jstring jstr1, jstring jstr2) {
jbyteArray bytes = 0;
jthrowable exc;
char*pszResult = NULL;
char*pszSTR1 = NULL;
char*pszSTR2 = NULL;
pszSTR1 = jstringTostring(env, jstr1);
pszSTR2 = jstringTostring(env, jstr2);
int nlen = sizeof(char)*(strlen(pszSTR1) + strlen(pszSTR2));
pszResult = (char*)malloc(nlen);
strcpy(pszResult, pszSTR1);
strcat(pszResult, pszSTR2);
jstring jstrRe = stoJstring(env, pszResult);
free(pszSTR1);
free(pszSTR2);
free(pszResult);
return (jstrRe);
}
浙公网安备 33010602011771号