本文主要介绍JNI开发中java与c进行如下所示的交互,代码中注释很详细,很好理解
JniDemo.c
#include "com_example_barry_jnidemo_JniDemo.h"
#include <stdlib.h>
//c文件中打印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__)
//
// Created by Barry on 2016/8/7.
//
JNIEXPORT jint JNICALL Java_com_example_barry_jnidemo_JniDemo_Add
(JNIEnv * env, jobject obj, jint a, jint b)
{
LOGD("%d+%d=%d", a, b, a+b);
return a+b;
}
// 把jstr 转换成char*
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_example_barry_jnidemo_JniDemo_SayHelloC
(JNIEnv *env, jobject obj, jstring str)
{
//jstring转换成char*
char* cstr = Jstring2CStr(env, str);
//拼接字符串
strcat(cstr, "hello");
//char*转为jstring
jstring newstr = (*env)->NewStringUTF(env, cstr);
return newstr;
}
JNIEXPORT jintArray JNICALL Java_com_example_barry_jnidemo_JniDemo_AddTen
(JNIEnv *env, jobject obj, jintArray intArray)
{
// 需要获取的数组的长度
int len=(*env)->GetArrayLength(env,intArray);
// 遍历数组 void* -> jinit*
// jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);
int* array=(*env)->GetIntArrayElements(env,intArray,JNI_FALSE);
int i=0;
for(;i<len;i++){
// 遍历的过程中让数组每个元素+10
*(array+i)+=10;
}
return intArray;
}
//回调java方法原理是反射机制
JNIEXPORT void JNICALL Java_com_example_barry_jnidemo_JniDemo_CallMethod1
(JNIEnv *env, jobject obj)
{
// Class<?> loadClass = MainActivity.class.getClassLoader().loadClass("com.itheima.ndkcallback.DataProvider");
// 1 反射类的字节码 jclass (*FindClass)(JNIEnv*, const char*);
jclass clazz=(*env)->FindClass(env,"com/example/barry/jnidemo/JniDemo");
// Method method = loadClass.getMethod("helloFromJava", (Class[]) null);
// 2 加载方法 jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
// 参数 env 参数2 类的字节码 参数3 方法名 参数4 方法的签名
jmethodID methodID= (*env)->GetMethodID(env,clazz,"Method1","()V");
// method.invoke(loadClass.newInstance(), (Object[]) null );
// 3 调用方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
(*env)->CallVoidMethod(env,obj,methodID);
}
//与方法一差不多,只是函数签名,传参不一样了
JNIEXPORT void JNICALL Java_com_example_barry_jnidemo_JniDemo_CallMethod2
(JNIEnv *env, jobject obj)
{
// 步骤1 获取类的字节码
jclass clazz=(*env)->FindClass(env,"com/example/barry/jnidemo/JniDemo");
// 步骤2 获取方法的id
jmethodID methodID= (*env)->GetMethodID(env,clazz,"Method2","(II)I");
// 步骤3
jint result=(*env)->CallIntMethod(env,obj,methodID,3,5);
}
//与方法一差不多,函数签名,传参不一样了,注意非基本类型传参Ljava/lang/String;
JNIEXPORT void JNICALL Java_com_example_barry_jnidemo_JniDemo_CallMethod3
(JNIEnv *env, jobject obj)
{
jclass clazz=(*env)->FindClass(env,"com/example/barry/jnidemo/JniDemo");
jmethodID methodID= (*env)->GetMethodID(env,clazz,"Method3","(Ljava/lang/String;)V");
(*env)->CallVoidMethod(env,obj,methodID,(*env)->NewStringUTF(env,"jni"));
}
//调用静态方法有专门(GetStaticMethodID)的方法
JNIEXPORT void JNICALL Java_com_example_barry_jnidemo_JniDemo_CallMethod4
(JNIEnv *env, jobject obj)
{
jclass clazz=(*env)->FindClass(env,"com/example/barry/jnidemo/JniDemo");
jmethodID methodID= (*env)->GetStaticMethodID(env,clazz,"Method4","()V");
(*env)->CallStaticVoidMethod(env,clazz,methodID);
}
//调用其他类的函数需要新创建那个类,googel不建议这么做,
//尽量让native方法和要回调的方法在同一个类中
JNIEXPORT void JNICALL Java_com_example_barry_jnidemo_JniDemo_CallMethod5
(JNIEnv *env, jobject obj)
{
jclass clazz=(*env)->FindClass(env,"com/example/barry/jnidemo/MainActivity");
jmethodID methodID= (*env)->GetMethodID(env,clazz,"Method5","()V");
// 由于obj 是代表的dataProvider 我们期望Mainactivity
// jobject (*AllocObject)(JNIEnv*, jclass); 尽量让native方法和要回调的方法在同一个类中
jobject mainObj=(*env)->AllocObject(env,clazz); //new Mainctivity()
(*env)->CallVoidMethod(env,mainObj,methodID);
}
MainActivity
package com.example.barry.jnidemo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
JniDemo jd = null;
TextView tv = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
jd = new JniDemo();
tv = (TextView)findViewById(R.id.tv);
}
public void add(View v)
{
int n = jd.Add(1,1);
tv.setText("add:"+n);
}
public void str(View v)
{
String str = jd.SayHelloC("jni");
tv.setText(str);
}
public void intarray(View v)
{
int[] ia = new int[]{1,2,3};
jd.AddTen(ia);
for (int i=0;i<ia.length;i++)
{
System.out.println(ia[i]+"");
}
}
public void callmethod1(View v)
{
jd.CallMethod1();
}
public void callmethod2(View v)
{
jd.CallMethod2();
}
public void callmethod3(View v)
{
jd.CallMethod3();
}
public void callmethod4(View v)
{
jd.CallMethod4();
}
public void Method5()
{
System.out.println("Mainactivity method");
}
public void callmethod5(View v)
{
jd.CallMethod5();
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.barry.jnidemo.MainActivity">
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello World!" />
<Button
android:id="@+id/btn_add"
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="传递int:add"
android:onClick="add"/>
<Button
android:id="@+id/btn_str"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="拼接str"
android:onClick="str"/>
<Button
android:id="@+id/btn_intarray"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="int数组"
android:onClick="intarray"/>
<Button
android:id="@+id/btn_callmethod1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="调用空参数方法"
android:onClick="callmethod1"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="调用int参数方法"
android:onClick="callmethod2"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="调用string参数方法"
android:onClick="callmethod3"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="调用静态方法"
android:onClick="callmethod4"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="调用其他类中的方法"
android:onClick="callmethod5"/>
</LinearLayout>
JniDemo
package com.example.barry.jnidemo;
/**
* Created by Barry on 2016/8/7.
*/
public class JniDemo {
static {
System.loadLibrary("JniDemo");
}
public void Method1()
{
System.out.println("null param method");
}
public int Method2(int a,int b)
{
System.out.println("two int param method:"+ (a+b));
return a+b;
}
public void Method3(String str)
{
str += "hello";
System.out.println("string param method:"+str);
}
public static void Method4()
{
System.out.println("static method");
}
public native int Add(int a, int b);
public native String SayHelloC(String str);
public native int[] AddTen(int[] iNum);
public native void CallMethod1();
public native void CallMethod2();
public native void CallMethod3();
public native void CallMethod4();
public native void CallMethod5();
}
com_example_barry_jnidemo_JniDemo.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_barry_jnidemo_JniDemo */
#ifndef _Included_com_example_barry_jnidemo_JniDemo
#define _Included_com_example_barry_jnidemo_JniDemo
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_barry_jnidemo_JniDemo
* Method: Add
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_example_barry_jnidemo_JniDemo_Add
(JNIEnv *, jobject, jint, jint);
/*
* Class: com_example_barry_jnidemo_JniDemo
* Method: SayHelloC
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_barry_jnidemo_JniDemo_SayHelloC
(JNIEnv *, jobject, jstring);
/*
* Class: com_example_barry_jnidemo_JniDemo
* Method: AddTen
* Signature: ([I)[I
*/
JNIEXPORT jintArray JNICALL Java_com_example_barry_jnidemo_JniDemo_AddTen
(JNIEnv *, jobject, jintArray);
/*
* Class: com_example_barry_jnidemo_JniDemo
* Method: CallMethod1
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_example_barry_jnidemo_JniDemo_CallMethod1
(JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_example_barry_jnidemo_JniDemo_CallMethod2
(JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_example_barry_jnidemo_JniDemo_CallMethod3
(JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_example_barry_jnidemo_JniDemo_CallMethod4
(JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_example_barry_jnidemo_JniDemo_CallMethod5
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif