AndroidNDK开发(1-----JavaC互相调用实例详解

一、概述

对于大部分应用开发者来说可能都不怎么接触到NDK,但如果涉及到硬件操作的话就不得不使用NDK了。使用NDK还有另一个原因,就是C/C++的效率比较高,因此我们可以把一些耗时的操作放在NDK中实现。所以NDK主要做驱动的开发。

java中调用一个本地方法,然后由该本地方法直接返回一个参数给java(例如,在java中定义的本地方法为privateintcallJNI(inti))。但在大多数时候要求的并不是由开发者在java层主动去调JNI中的函数来返回想要的数据,而是由JNI主动去调java中的函数。举个最简单的例子,Android中的Camera,图像数据由内核一直往上传到java层,然而这些数据的传递并不需要开发者每一次主动去调用来JNI中的函数来获取,而是由JNI主动传给用java中方法,这类似于Linux驱动机制中的异步通知。

二、要求

NDK实现JavaC/C++互调,实现intstringbyte[]这三种类型的互相传递。

三、实现

下面的实现中,每次java调用JNI中的某个函数时,最后会在该函数里回调java中相应的方法而不是直接返回一个参数。可能你会觉得这不还是每次都是由开发者来主动调用吗,其实这只是为了讲解而已,在实际应用中,回调java中的方法应该由某个事件(非java层)来触发。

步骤:

1Java类里的声明

packagecom.ljt.work;

importandroid.annotation.SuppressLint;

importandroid.app.Activity;

importandroid.os.Bundle;

importandroid.os.Handler;

importandroid.os.Message;

importandroid.view.View;

importandroid.widget.Button;

importandroid.widget.TextView;

publicclassLjtndkActivityextendsActivity{

//本地方法,由java调用

privatenativevoidcallJNIInt(inti);

privatenativevoidcallJNIString(Strings);

privatenativevoidcallJNIByte(byte[]b);

static

{

//加载本地库

System.loadLibrary("myjni");

}

privateButtonintButton=null;

privateButtonstringButton=null;

privateButtonarrayButton=null;

privateTextViewintTextView=null;

privateTextViewstringTextView=null;

privateTextViewarrayTextView=null;

//定义一个处理线程的机制

privateHandlermHandler=null;

@SuppressLint("HandlerLeak")

@Override

protectedvoidonCreate(BundlesavedInstanceState){

//TODOAuto-generatedmethodstub

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

intButton=(Button)this.findViewById(R.id.intbutton);

//注册按钮监听

intButton.setOnClickListener(newClickListener());

stringButton=(Button)this.findViewById(R.id.stringbutton);

//注册按钮监听

stringButton.setOnClickListener(newClickListener());

arrayButton=(Button)this.findViewById(R.id.arraybutton);

//注册按钮监听

arrayButton.setOnClickListener(newClickListener());

intTextView=(TextView)this.findViewById(R.id.inttextview);

stringTextView=(TextView)this.findViewById(R.id.stringtextview);

arrayTextView=(TextView)this.findViewById(R.id.arraytextview);

//消息处理

mHandler=newHandler()

{

@Override

publicvoidhandleMessage(Messagemsg)

{

switch(msg.what)

{

//整型

case0:

{

intTextView.setText(msg.obj.toString());

break;

}

//字符串

case1:

{

stringTextView.setText(msg.obj.toString());

break;

}

//数组

case2:

{byte[]b=(byte[])msg.obj;

arrayTextView.setText(Byte.toString(b[0])+Byte.toString(b[1])+Byte.toString(b[2])+Byte.toString(b[3])+Byte.toString(b[4]));

break;

}

}

}

};

}

/*下面定义被JNI调用的方法*/

//被JNI调用,参数由JNI传入

privatevoidcallbackInt(inti)

{

Messagemsg=newMessage();

//消息类型

msg.what=0;

//消息内容

msg.obj=i;

//发送消息

mHandler.sendMessage(msg);

}

//被JNI调用,参数由JNI传入

privatevoidcallbackString(Strings)

{

Messagemsg=newMessage();

//消息类型

msg.what=1;

//消息内容

msg.obj=s;

//发送消息

mHandler.sendMessage(msg);

}

//被JNI调用,参数由JNI传入

privatevoidcallbackByte(byte[]b)

{

Messagemsg=newMessage();

//消息类型

msg.what=2;

//消息内容

msg.obj=b;

//发送消息

mHandler.sendMessage(msg);

}

//按钮监听事件

publicclassClickListenerimplementsView.OnClickListener{

@Override

publicvoidonClick(Viewv){

//TODOAuto-generatedmethodstub

switch(v.getId())

{

caseR.id.intbutton:

{

//调用JNI中的函数

callJNIInt(1);

break;

}

caseR.id.stringbutton:

{

//调用JNI中的函数

callJNIString("你好!我是从JNI函数中返回一个字符串");

break;

}

caseR.id.arraybutton:

{

//调用JNI中的函数

callJNIByte(newbyte[]{1,2,3,4,5});

break;

}

}

}

}

}

2在工程的根目录下新建jni文件夹,在里面添加一个Android.mk文件和一个callback.c文件,Android.mk文件如下:

LOCAL_PATH:=$(callmy-dir)

include$(CLEAR_VARS)

LOCAL_MODULE:=myjni

LOCAL_SRC_FILES:=callback.c

LOCAL_LDLIBS:=-llog

include$(BUILD_SHARED_LIBRARY)

callback.c文件如下:

#include<string.h>

#include<stdio.h>

#include<stdlib.h>

#include<unistd.h>

#include<sys/ioctl.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<fcntl.h>

#include<com_ljt_work_LjtndkActivity_ClickListener.h>

#include<com_ljt_work_LjtndkActivity.h>

#include<jni.h>

#include<android/log.h>

#defineLOGI(...)((void)__android_log_print(ANDROID_LOG_INFO,"native-activity",__VA_ARGS__))

#defineLOGW(...)((void)__android_log_print(ANDROID_LOG_WARN,"native-activity",__VA_ARGS__))

/**********传输整数*************

两个方向都没有乱码问题

*/

JNIEXPORTvoidJNICALLJava_com_ljt_work_LjtndkActivity_callJNIInt

(JNIEnv*env,jobjectobj,jinti){

//找到java中的类

jclasscls=(*env)->FindClass(env,"com/ljt/work/LjtndkActivity");

//再找类中的方法,调用callbackInt方法传输整数

jmethodIDmid=(*env)->GetMethodID(env,cls,"callbackInt","(I)V");

if(mid==NULL)

{

LOGI("interror");

return;

}

//打印接收到的数据

LOGI("fromjavaint:%d",i);

//回调java中的方法

(*env)->CallVoidMethod(env,obj,mid,i);

}

/********传输字符串*************

两个方向都没有乱码问题

*/

JNIEXPORTvoidJNICALLJava_com_ljt_work_LjtndkActivity_callJNIString

(JNIEnv*env,jobjectobj,jstrings){

//找到java中的类

jclasscls=(*env)->FindClass(env,"com/ljt/work/LjtndkActivity");

//再找类中的方法callbackString

jmethodIDmid=(*env)->GetMethodID(env,cls,"callbackString","(Ljava/lang/String;)V");

if(mid==NULL)

{

LOGI("stringerror");

return;

}

constchar*ch;

//获取由java传过来的字符串

ch=(*env)->GetStringUTFChars(env,s,NULL);

//打印

LOGI("fromjavastring:%s",ch);

(*env)->ReleaseStringUTFChars(env,s,ch);

//回调java中的方法

(*env)->CallVoidMethod(env,obj,mid,(*env)->NewStringUTF(env,"你好!我是一个字符串haha"));

}

/********传输数组(byte[])*************

*/

JNIEXPORTvoidJNICALLJava_com_ljt_work_LjtndkActivity_callJNIByte

(JNIEnv*env,jobjectobj,jbyteArrayb){

//找到java中的类

jclasscls=(*env)->FindClass(env,"com/ljt/work/LjtndkActivity");

//再找类中的方法callbackByte

jmethodIDmid=(*env)->GetMethodID(env,cls,"callbackByte","([B)V");

if(mid==NULL)

{

LOGI("byte[]error");

return;

}

//获取数组长度

jsizelength=(*env)->GetArrayLength(env,b);

LOGI("length:%d",length);

//获取接收到的数据

inti;

jbyte*p=(*env)->GetByteArrayElements(env,b,NULL);

//打印

for(i=0;i<length;i++)

{

LOGI("%d",p[i]);

}

charc[5];

c[0]=1;c[1]=2;c[2]=3;c[3]=4;c[4]=5;

//构造数组

jbyteArraycarr=(*env)->NewByteArray(env,length);

(*env)->SetByteArrayRegion(env,carr,0,length,c);

//回调java中的方法

(*env)->CallVoidMethod(env,obj,mid,carr);

}

/********相加*************

*/

JNIEXPORTjlongJNICALLJava_com_ljt_work_LjtndkActivity_AddJNInum

(JNIEnv*env,jobjectobj,jlongx,jlongy){

returnx+y;

}

进入H:\android-ndk-r9d\samples\LJTNDKwork\bin\classes目录

用javah-jni

ljt@ljt-PC/cygdrive/H/android-ndk-r9d/samples/LJTNDKwork/bin/classes

$javah-jnicom.ljt.work.LjtndkActivity

.\com\ljt\work\LjtndkActivity.class:警告:无法找到类型为“android.annotation.Su

ppressLint”的注释方法“value():未找到android.annotation.SuppressLint的类文

1警告

然后将到的.h库文件声明到.c文件中

#include<com_ljt_work_LjtndkActivity_ClickListener.h>

#include<com_ljt_work_LjtndkActivity.h>

然后进入H:\android-ndk-r9d\samples\LJTNDKwork

$NDK/ndk-build

ljt@ljt-PC/cygdrive/H/android-ndk-r9d/samples/LJTNDKwork

$$NDK/ndk-build

[armeabi]Cygwin:Generatingdependencyfileconverterscript

[armeabi]Compilethumb:myjni<=callback.c

[armeabi]SharedLibrary:libmyjni.so

[armeabi]Install:libmyjni.so=>libs/armeabi/libmyjni.so

调试:

04-0921:07:13.728:I/native-activity(555):fromjavastring:你好!我是一个字符串haha

04-0921:07:13.728:W/dalvikvm(555):JNIWARNING:inputisnotvalidModifiedUTF-8:illegalcontinuationbyte0xe3

04-0921:07:13.728:W/dalvikvm(555):string:'���!����һ���ַhaha'

04-0921:07:13.728:W/dalvikvm(555):inLcom/ljt/work/LjtndkActivity;.callJNIString:(Ljava/lang/String;)V(NewStringUTF)

更多相关文章

  1. Android基础知识巩固系列 Android之四大组件——Service(服务)
  2. [置顶] 解决android某些应用开发某些类无法解析/找到的问题--使
  3. Android面试真题,了解一下?
  4. 实现两次按返回键退出的五种方法
  5. ListView的两次测量(源码分析)
  6. android解析xml和json区别
  7. 向android 的状态栏中加入快捷按钮(home,back,menu等等)的方法(续)
  8. iOS中Objective-C与JavaScript之间相互调用的实现(实现了与Androi
  9. 【重磅】通付盾独家获得应用加固发明专利授权

随机推荐

  1. Android获取屏幕高度、标题高度、状态栏
  2. Android的五大布局
  3. android.widget.TextView 属性详解
  4. Android(安卓)计步传感器的实现
  5. android 资源文件命名规则 drawable mipm
  6. Android学习笔记Android线程模型解析
  7. Android开发人员必备的10个开发工具
  8. Android属性动画
  9. Android点击EditText文本框之外任何地方
  10. Android界面布局——视图/容器易混淆点总