初學JNI(二)調用C\C++中的方法

佈局文件:java

<?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代碼:android

 

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方法的類:ios

 */
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++代碼的實現: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);
    }
相關文章
相關標籤/搜索