zoukankan      html  css  js  c++  java
  • [置顶] JNI之java传递数据给c语言

    1.首先创建 DataProvider类:

    package com.pl.ndkpassdata;
    
    public class DataProvider {
    	static{
    		System.loadLibrary("passdata");//加载库
    	}
    	
    	/**
    	 * 把两个java中的int传递给c语言, c语言处理完毕后,把相加的结果返回给java
    	 */
    	public native int add(int x,int y);
    	/**
    	 * 静态方法 c语言处理减法运算 返回结果给java
    	 */
    	public static native int sub(int x,int y);
    	/**
    	 * 把java中的string传递给c语言, c语言获取到java中的string之后 ,在string后面添加 一个hello 字符串
    	 */
    	public native String getHelloString(String s);
    	/**
    	 * 把java中的一个int数组 传递给c语言,c语言处理完毕这个java数组 
    	 * 把int数组中的每一个元素+10,然后把结果返回给java
    	 */
    	public native int[] getIntArr(int[] iNum);
    	
    }
    


    2.创建完毕后找到它.class位置,生成JNI样式的头文件:

    com_pl_ndkpassdata_DataProvider.h:

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class com_pl_ndkpassdata_DataProvider */
    
    #ifndef _Included_com_pl_ndkpassdata_DataProvider
    #define _Included_com_pl_ndkpassdata_DataProvider
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     com_pl_ndkpassdata_DataProvider
     * Method:    add
     * Signature: (II)I
     */
    JNIEXPORT jint JNICALL Java_com_pl_ndkpassdata_DataProvider_add
      (JNIEnv *, jobject, jint, jint);
    
    /*
     * Class:     com_pl_ndkpassdata_DataProvider
     * Method:    sub
     * Signature: (II)I
     */
    JNIEXPORT jint JNICALL Java_com_pl_ndkpassdata_DataProvider_sub
      (JNIEnv *, jclass, jint, jint);
    
    /*
     * Class:     com_pl_ndkpassdata_DataProvider
     * Method:    getHelloString
     * Signature: (Ljava/lang/String;)Ljava/lang/String;
     */
    JNIEXPORT jstring JNICALL Java_com_pl_ndkpassdata_DataProvider_getHelloString
      (JNIEnv *, jobject, jstring);
    
    /*
     * Class:     com_pl_ndkpassdata_DataProvider
     * Method:    getIntArr
     * Signature: ([I)[I
     */
    JNIEXPORT jintArray JNICALL Java_com_pl_ndkpassdata_DataProvider_getIntArr
      (JNIEnv *, jobject, jintArray);
    
    #ifdef __cplusplus
    }
    #endif
    #endif

    上面是用javah -jni命令生成的。

    3.  在项目的根目录创建jni目录(和src,bin等目录平级);

    1.拷贝com_pl_ndkpassdata_DataProvider.h到jni目录下;

            2.在jni目录下创建Android.mk文件和passdata.c文件;(关于c语言的.c和.h文件的区别是 :函数定义要放在.c中,而.h只做声明.

    下面是Android.mk的内容:

     LOCAL_PATH := $(call my-dir)
    
       include $(CLEAR_VARS)
    
       LOCAL_MODULE    := passdata
       LOCAL_SRC_FILES := passdata.c
       #liblog.c
       LOCAL_LDLIBS += -llog
       include $(BUILD_SHARED_LIBRARY)


    下面是passdata.c

    #include <stdio.h>
    #include <jni.h>
    #include <stdlib.h>
    #include "com_pl_ndkpassdata_DataProvider.h"
    #include <android/log.h>
    #define LOG_TAG "System.out.c"
    #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
    #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
    
    /**
     * 用于把java中的String转换成c可用的指向字符的指针类型
     */
    /**
     * <jni.h>中的指针函数:
     * jclass      (*FindClass)(JNIEnv*, const char*); //拿到一个类
     * jstring     (*NewStringUTF)(JNIEnv*, const char*);//拿到一个String对象
     * jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);//拿到类的方法
     * jobject     (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...);//调用类的方法
     * jsize       (*GetArrayLength)(JNIEnv*, jarray);//拿到数组的长度
     *  jbyte*     (*GetByteArrayElements)(JNIEnv*, jbyteArray, jboolean*); //转换成c可用的byte指针类型
     */
    char* Jstring2CStr(JNIEnv * env,jstring s){ //JNIEnv*:java虚拟机的结构体c语言实现的指针,包含的有很多jni方法
    	char*   rtn   =   NULL;
    	jclass classstring = (*env)->FindClass(env,"java/lang/String"); //调用java中的String类
    	jstring   strencode = (*env)->NewStringUTF(env,"GB2312"); //拿到编码格式
    	//拿到方法 。参数2:指定类,参数3:方法名,参数4:(Ljava/lang/String;)是getBytes的参数;[B代表是返回值是一个byte数组
    	jmethodID  mid = (*env)->GetMethodID(env,classstring,"getBytes","(Ljava/lang/String;)[B");
    	jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env,s,mid,strencode);//相当于调用java的getBytes
    	//拿到byte数组的长度
    	jsize size = (*env)->GetArrayLength(env,barr);
    	 jbyte* ba = (*env)->GetByteArrayElements(env,barr,JNI_FALSE);
    	 if(size   >   0){
    		  rtn   =   (char*)malloc(size+1); //申请一块内存         //+""
    		  memcpy(rtn,ba,size); //拷贝字符串
    		  rtn[size]=0; //''
    		 }
    	 (*env)->ReleaseByteArrayElements(env,barr,ba,0);//释放内存空间
    	 return rtn;
    }
    JNIEXPORT jint JNICALL Java_com_pl_ndkpassdata_DataProvider_add
      (JNIEnv * env, jobject obj, jint x, jint y){
    	LOGD("add()x:%d,y:%d",x,y);
    	return x+y;
    }
    
    JNIEXPORT jint JNICALL Java_com_pl_ndkpassdata_DataProvider_sub
    (JNIEnv * env, jclass clazz, jint x, jint y){
    	LOGD("sub()x:%d,y:%d",x,y);
    	return x-y;
    }
    
    JNIEXPORT jstring JNICALL Java_com_pl_ndkpassdata_DataProvider_getHelloString
      (JNIEnv * env, jobject obj, jstring s){
    	char* cs = Jstring2CStr(env,s);
    	LOGD("cs=%s",cs);
    	char carr[7] = {' ','h','e','l','l','o',''};
    	strcat(cs,carr); //拼接
    	LOGD("new cs=%s",cs);
    	LOGD("end getHelloString()");
    	return (*env)->NewStringUTF(env,cs);
    }
    
    //jsize       (*GetArrayLength)(JNIEnv*, jarray); //拿到数组长度
    // jint*       (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*) //转换成c可用的int指针类型
    JNIEXPORT jintArray JNICALL Java_com_pl_ndkpassdata_DataProvider_getIntArr
      (JNIEnv * env, jobject obj, jintArray jarr){
    	jsize  len = (*env)->GetArrayLength(env,jarr);
    	LOGD("len=%d",len);
    	jint* carr = (*env)->GetIntArrayElements(env,jarr,JNI_FALSE);
    	int i;
    	for(i=0;i<len;i++){
    		*(carr+i)+=10;
    	}
    	LOGD("end getIntArr()");
    	return jarr;
    }
    


    完成映射实现,使用Cygwin生成.so库文件.基本完成了,别忘了clean下项目。

    基本到这做完了。下面是测试代码:

    MainActivity.java

    package com.pl.ndkpassdata;
    
    import android.os.Bundle;
    import android.app.Activity;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.Toast;
    
    public class MainActivity extends Activity implements OnClickListener{
    	private Button bt1,bt2,bt3,bt4;
    	private DataProvider provider;
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.main);
    		  	bt1 = (Button) this.findViewById(R.id.bt1);
    	        bt2 = (Button) this.findViewById(R.id.bt2);
    	        bt3 = (Button) this.findViewById(R.id.bt3);
    	        bt4 = (Button) this.findViewById(R.id.bt4);
    	        
    	        bt1.setOnClickListener(this);
    	        bt2.setOnClickListener(this);
    	        bt3.setOnClickListener(this);
    	        bt4.setOnClickListener(this);
    	        provider = new DataProvider();
    	}
    	public void onClick(View v) {
    		switch (v.getId()) {
    		case R.id.bt1:
    			int result = provider.add(10, 10);
    			Toast.makeText(this, "相加的结果:"+result, 1).show();
    			break;
    
    		case R.id.bt2:
    			String str = provider.getHelloString("pengliang");
    			Toast.makeText(this, str, 1).show();
    			break;
    		case R.id.bt3:
    			int[] arr = {7,8,9,10,6};
    			provider.getIntArr(arr);
    			String arrtostr ="[";
    			for(int i=0;i<arr.length;i++){
    				arrtostr+=arr[i]+",";
    			}
    			arrtostr +="]";
    			Toast.makeText(this, arrtostr, 1).show();
    			break;
    		case R.id.bt4:
    			int subresult = DataProvider.sub(100, 24);
    			Toast.makeText(this, "相减的结果:"+subresult, 1).show();
    			break;
    		}
    	}
    }
    


    main.xml:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >
    
        <Button
            android:id="@+id/bt1"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="传递两个int给c代码" />
    
        <Button
            android:id="@+id/bt2"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="传递string给c代码" />
    
        <Button
            android:id="@+id/bt3"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="传递int数组给c代码" />
    
        <Button
            android:id="@+id/bt4"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="调用静态native方法" />
    
    </LinearLayout>


  • 相关阅读:
    JS——switch case
    JS——“==”与“===”
    C#——枚举格式转换与比较
    XML——读与写
    SQl基本操作——try catch
    JS——indexOf replace search
    C#——数据库的访问
    SQL基本操作——存储过程
    C#——设置开机启动
    C#——计时器的操作
  • 原文地址:https://www.cnblogs.com/riasky/p/3433168.html
Copyright © 2011-2022 走看看