编写android程序调用jni本地方法的实现(详细例子)

来源:互联网 发布:轿车送货软件 编辑:程序博客网 时间:2024/04/29 04:49

在写android程序的时候会用到jni,接下来的代码讲诉C实现,环境配置请看我其他的博客,不多说,直接上代码,代码上几乎每一句都会解释,绝对易懂

MainActivity中的代码:

package com.ndk.test;import java.io.UnsupportedEncodingException;import com.example.testndk.R;import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;public class MainActivity extends Activity implements OnClickListener {private static final String TAG = "MainActivity";private TextView show;private Button getInt, getString, getIntArray, getBool, getBackIntArray,getBackStrArray, getObject;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);init();}private void init() {show = (TextView) this.findViewById(R.id.show);getInt = (Button) this.findViewById(R.id.getint);getInt.setOnClickListener(this);getIntArray = (Button) this.findViewById(R.id.getintarray);getIntArray.setOnClickListener(this);getString = (Button) this.findViewById(R.id.getstring);getString.setOnClickListener(this);getBool = (Button) this.findViewById(R.id.getbool);getBool.setOnClickListener(this);getBackIntArray = (Button) this.findViewById(R.id.getBackIntArray);getBackIntArray.setOnClickListener(this);getBackStrArray = (Button) this.findViewById(R.id.getBackStrArray);getBackStrArray.setOnClickListener(this);getObject = (Button) this.findViewById(R.id.getObject);getObject.setOnClickListener(this);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.getint:int intBack = JniClient.getInstance().AddInt(10, 10);showInfo(intBack);break;case R.id.getstring:String strBack = JniClient.getInstance().AddStr("program1","program2");showInfo(strBack);break;case R.id.getintarray:int intArr = JniClient.getInstance().intArrayMethord(new int[] { 2, 5, 8 });showInfo(intArr);break;case R.id.getbool:boolean bool = JniClient.getInstance().booleanMethord(true);showInfo(bool);break;case R.id.getBackIntArray:int[] intBackArr = JniClient.getInstance().intMethord();showInfo(intBackArr);break;case R.id.getBackStrArray:String[] texts = JniClient.getInstance().stringMethord("java编程思想");for (int i = 0; i < texts.length; i++) {try {texts[i] = new String(texts[i].getBytes("ISO8859-1"), "GBK");} catch (UnsupportedEncodingException e) {e.printStackTrace();}showInfo(texts[i]);}System.out.println();break;case R.id.getObject:boolean object = JniClient.getInstance().objectMethod("this is object data");showInfo(object);break;default:break;}}private void showInfo(Object object) {show.setText("" + object);Log.i(TAG, "返回的信息-->" + object);}}

jniclient 代码:

package com.ndk.test;public class JniClient {static {System.loadLibrary("TestNdk");}private JniClient() {}private static JniClient jniClient = new JniClient();public static JniClient getInstance() {return jniClient;}// 1public native String AddStr(String strA, String strB);// 2public native int AddInt(int a, int b);// 3public native int intArrayMethord(int[] intArray);// 4public native boolean booleanMethord(boolean b);// 5public native int[] intMethord();// 6public native String[] stringMethord(String text);// 7public native boolean objectMethod(String data);}

mailinfo代码:

package com.ndk.test;public class MailInfo {public String topic;public String getTopic() {return this.topic;}public void setTopic(String topic) {this.topic = topic;}}

com_ndk_test_JniClient.c代码:

#include "com_ndk_test_JniClient.h"#include <stdlib.h>//#include<jni.h>#include <stdio.h>#define ARRAY_LENGTH 5//宏定义#ifdef __cplusplusextern "C"{#endif/* * 例子1 传递字符串,返回字符串 * Class:     com_ndk_test_JniClient * Method:    AddStr * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_ndk_test_JniClient_AddStr(JNIEnv *env,jclass arg, jstring a, jstring b) {//JNIEnv也是在jni.h中定义的,代表JNI调用的上下文,//GetStringUTFChars()、ReleaseStringUTFChars()和NewStringUTF()均是JNIEnv的函数。//jstring str = (*env)->NewStringUTF(env, "HelloWorld from JNI !");//从JNI调用上下文中获取UTF编码的输入字符,将其放在指针str所指向 的一段内存中const char* str = (*env)->GetStringUTFChars(env, a, 0); //这是c的写法,接下来没有注释的都是有c编写//const char* s1 = env->GetStringUTFChars(a, 0);//这是c++的写法,以下的方法都是这种形式char cap[128]; //定义char数组strcpy(cap, str); //复制字符串到cap(*env)->ReleaseStringUTFChars(env, a, str); //释放这段内存,个人认为这个像c++虚函数int i = 0;for (i = 0; i < strlen(cap); i++)*(cap + i) = (char) toupper(*(cap + i)); //将经过大写转换的字符串予以返回return (*env)->NewStringUTF(env, cap); //C语言的字符串指针 转换为JNI的jstring类型//return (*env)->NewStringUTF(env, strupr(cap));//return str;}/* * 例子2 传递两个int类型参数,返回int类型数据 * Class:     com_ndk_test_JniClient * Method:    AddInt * Signature: (II)I */JNIEXPORT jint JNICALL Java_com_ndk_test_JniClient_AddInt(JNIEnv *env,jclass arg, jint a, jint b) {return a + b;};//TODO/** * 例子3 * 传递一个int[]类型参数。返回int类型 * * **/JNIEXPORT jint JNICALL Java_com_ndk_test_JniClient_intArrayMethord(JNIEnv * env,jclass clazz, jintArray array) {//return 200;int i, sum = 0;jsize len = (*env)->GetArrayLength(env, array);jint *body = (*env)->GetIntArrayElements(env, array, 0);for (i = 0; i < len; i++) {sum += body[i];}(*env)->ReleaseIntArrayElements(env, array, body, 0);return sum;}/** * 例子4 * 传递一个boolean类型参数。返回boolean类型 * * **/JNIEXPORT jboolean JNICALL Java_com_ndk_test_JniClient_booleanMethord(JNIEnv *env, jclass clazz, jboolean b) {return !b;}/** *例子5 * 无参数,返回一个int[]类型数组 * */JNIEXPORT jintArray JNICALL Java_com_ndk_test_JniClient_intMethord(JNIEnv *env,jclass clazz) {int i = 1; //jint是在JNI框 架内特有的整数类型jintArray array; //定义数组对象array = (*env)->NewIntArray(env, 10); //开辟出一个长度为10 的jint数组for (; i <= 10; i++) //依次向该数组中放入元素1-10(*env)->SetIntArrayRegion(env, array, i - 1, 1, &i);//演示GetArrayLength() 和GetIntArrayElements()这两个函数的使用方法/* 获取数组对象的元素个数 */int len = (*env)->GetArrayLength(env, array);/* 获取数组中的所有元素 */jint* elems = (*env)->GetIntArrayElements(env, array, 0);for (i = 0; i < len; i++)printf("ELEMENT %d IS %d/n", i, elems[i]);return array;}/** * 例子6 * 所有的本地方法的第一个参数都是指向JNIEnv结构的。 * 这个结构是用来调用JNI函数的。第二个参数jclass的意义, * 要看方法是不是静态的(static)或者实例(Instance)的。 * 前者,jclass代表一个类对象的引用,而后者是被调用的方法所属对象的引用。 * 深化:虽然仍然是传递数组,但是数组的基类换成了字符串这样一种对象数据类型。 * Java程序将向C程序传入一个包含中文字符的字符串, * C程序并没有处理这个字符串,而是开辟出一个新的字符串数组返回给Java程序,其中还包含两个汉字字符串。 * java写法----->: public native String[] stringMethod(String text); public static void main(String[] args) throws java.io.UnsupportedEncodingException { System.loadLibrary("TestNdk"); String[] texts = JniClient.getInstance().stringMethod("java编程思想"); for(int i=0;i<texts.length;i++) { texts[i]=new String(texts[i].getBytes("ISO8859-1"),"GBK"); System.out.print( texts[i] ); } System.out.println(); } * */JNIEXPORT jobjectArray JNICALL Java_com_ndk_test_JniClient_stringMethord(JNIEnv *env, jclass obj, jstring string) {//通过FindClass()函数在JNI上下文中获取到java.lang.String的类型 (Class),并将其赋予jclass变量jclass objClass = (*env)->FindClass(env, "java/lang/String");//JNI框架并 没有定义专门的字符串数组,//而是使用jobjectArray——对象数组,//对象数组的基类是jclass,jclass是JNI框架内特有的类型,//相当 于Java语言中的Class类型//定义了一个长度为5的对象数组textsjobjectArray texts = (*env)->NewObjectArray(env, (jsize) ARRAY_LENGTH,objClass, 0);jstring jstr;char* sa[] = { "Hello,", "world!", "JNI", "I love U", "happy" };int i = 0;//循环放入预先定义好的sa数组中的字符串,//当然前置条件是使用NewStringUTF()函数将C语言的字符串转换为jstring类型for (; i < ARRAY_LENGTH; i++) {jstr = (*env)->NewStringUTF(env, sa[i]);(*env)->SetObjectArrayElement(env, texts, i, jstr); //必须放入jstring}//中文字符则是用支持GBK的输入法输入的,而Java程序采用 ISO8859_1字符集存放JNI调用的返回字符return texts;}/** * 例子7 对象的调用 * 演示的是C程序向Java程序传递对象数组, * 而且对象数组中存放的不再是字符串, * 而是一个在Java中自定义的、含有一个topic属性的MailInfo对象类型 *MailInfo对象定义如下:-> public class MailInfo { public String topic; public String getTopic() { return this.topic; } public void setTopic(String topic) { this.topic=topic; } } Java程序的源代码如下:-> public class Sample { public native MailInfo[] objectMethod(String text); public static void main(String[] args) { System.loadLibrary("TestNdk"); MailInfo[] mails = JniClient.getInstance()..objectMethod("Thinking In Java"); for(int i=0;i<mails.length;i++) System.out.println(mails[i].topic); } } * */JNIEXPORT jobjectArray JNICALL Java_com_ndk_test_JniClient_objectMethod(JNIEnv *env,jobject obj, jstring string) {//这次通过FindClass()函数在JNI上下文中获取的是java.lang.Object的类型(Class),//并将 其作为基类开辟出一个长度为5的对象数组( #define ARRAY_LENGTH 5),准备用来存放MailInfo对象。jclass objClass = (*env)->FindClass(env, "java/lang/Object");jobjectArray mails = (*env)->NewObjectArray(env, (jsize) ARRAY_LENGTH,objClass, 0);jclass objectClass = (*env)->FindClass(env, "MailInfo");//创建一个jfieldID类型的变量,在JNI中,操作对 象属性都是通过jfieldID进行的.//首先查找得到MailInfo的类型(Class),//然后基于这个jclass进一步获取其名为 topic的属性,并将其赋予jfieldID变量。jfieldID topicFieldId = (*env)->GetFieldID(env, objectClass, "topic","Ljava/lang/String;");int i = 0;//循环向对象数组中放入jobject对象。 SetObjectField()函数属于首次使用,//该函数的作用是向jobject的属性赋值,而值的内容正是Java程序传入的jstring变量 值。//请注意在向对象属性赋值和向对象数组中放入对象的过程中,//我们使用了在函数头部分定义的jobject类型的环境参数obj作为中介。//至此,JNI框 架固有的两个环境入参env和obj,我们都有涉及。for (; i < ARRAY_LENGTH; i++) {(*env)->SetObjectField(env, obj, topicFieldId, string);(*env)->SetObjectArrayElement(env, mails, i, obj);}return mails;}#ifdef __cplusplus}#endif

com_ndk_test_JniClient.h代码:

/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_ndk_test_JniClient */#ifndef _Included_com_ndk_test_JniClient#define _Included_com_ndk_test_JniClient#ifdef __cplusplusextern "C" {#endifJNIEXPORT jstring JNICALL Java_com_ndk_test_JniClient_AddStr(JNIEnv *, jclass,jstring, jstring);JNIEXPORT jint JNICALL Java_com_ndk_test_JniClient_AddInt(JNIEnv *, jclass,jint, jint);JNIEXPORT jint JNICALL Java_com_ndk_test_JniClient_intArrayMethord(JNIEnv *,jclass,jintArray);JNIEXPORT jboolean JNICALL Java_com_ndk_test_JniClient_booleanMethord(JNIEnv *,jclass, jboolean);JNIEXPORT jintArray JNICALL Java_com_ndk_test_JniClient_intMethord(JNIEnv *env,jclass clazz);JNIEXPORT jobjectArray JNICALL Java_com_ndk_test_JniClient_stringMethord(JNIEnv *env, jclass obj, jstring string);JNIEXPORT jobjectArray JNICALL Java_com_ndk_test_JniClient_objectMethod(JNIEnv *env,jobject obj, jstring string);#ifdef __cplusplus}#endif#endif

android.mk文件:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := TestNdk
LOCAL_SRC_FILES := com_ndk_test_JniClient.c
include $(BUILD_SHARED_LIBRARY)
#LOCAL_PATH := $(call my-dir)
#include $(CLEAR_VARS)
#LOCAL_MODULE    := libusbhid
#LOCAL_SRC_FILES := com_ndk_test_JniClient.c
#LOCAL_C_INCLUDES :=  $(JNI_H_INCLUDE)    
#LOCAL_LDLIBS :=  -llog 
#include $(BUILD_SHARED_LIBRARY)

Application.mk文件:

APP_ABI := all


mainfest.xml文件:


<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.example.testndk"    android:versionCode="1"    android:versionName="1.0" >    <uses-sdk        android:minSdkVersion="8"        android:targetSdkVersion="18" />    <application        android:allowBackup="true"        android:icon="@drawable/ic_launcher"        android:label="@string/app_name"        android:theme="@style/AppTheme" >        <activity            android:name="com.ndk.test.MainActivity"            android:label="@string/app_name" >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application></manifest>


layout中的文件:

<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    android:background="#2fb"    tools:context=".MainActivity" >    <TextView        android:id="@+id/show"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:textSize="20dp"        android:hint="获得信息显示" />    <Button        android:id="@+id/getintarray"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignBaseline="@+id/getint"        android:layout_alignBottom="@+id/getint"        android:layout_centerHorizontal="true"        android:text="getintarray" />    <Button        android:id="@+id/getint"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentLeft="true"        android:layout_below="@+id/show"        android:layout_marginTop="75dp"        android:text="getint" />    <Button        android:id="@+id/getstring"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignBottom="@+id/getintarray"        android:layout_alignParentRight="true"        android:text="getstring" />    <ProgressBar        android:id="@+id/progressBar1"        style="?android:attr/progressBarStyleLarge"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentBottom="true"        android:layout_centerHorizontal="true"        android:layout_marginBottom="23dp" />    <Button        android:id="@+id/getbool"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignLeft="@+id/getint"        android:layout_below="@+id/getint"        android:layout_marginTop="26dp"        android:text="getbool" />    <Button        android:id="@+id/getBackIntArray"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignBottom="@+id/getbool"        android:layout_alignLeft="@+id/getintarray"        android:text="getBackIntArray" />    <Button        android:id="@+id/getObject"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignLeft="@+id/getbool"        android:layout_below="@+id/getbool"        android:layout_marginTop="16dp"        android:text="getObject" />    <Button        android:id="@+id/getBackStrArray"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_below="@+id/getBackIntArray"        android:layout_toRightOf="@+id/getintarray"        android:text="getBackStrArray" /></RelativeLayout>


上面是布局文件。


上面是所有文件目录。


上面三个是路径配置。

完毕!!!

8 0
原创粉丝点击