初学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);
    }

posted on 2013-08-18 18:26  foolchen  阅读(805)  评论(0编辑  收藏  举报

导航