Android - JNI指南

时间:2009-10-09 05:03:06

标签: android java-native-interface

我想在我的Android项目中加入小型,精简和基于C语言的解析器。我过去做过JNI编程,但在Android上没有任何类型的原生(C)开发。我的计划是将C lib编译成SO并在其周围创建JNI包装器,我将在我的应用程序中使用它。这是怎么做/应该做的?第二个也是最重要的问题 - 如何在我的APK中添加.so?它会去哪里?

4 个答案:

答案 0 :(得分:5)

取决于您传递的数据量以及我经常怀疑Java / JNI / C执行速度比本机java实现更快的频率。

将“Java Int”以外的任何内容传递给“C long”会调用JNI数据转换例程,这些例程不是精简和平均值。

因此,除非你的JNI例程适合这种模式:

  • 传递少量数据。
  • 在C中做很多很多工作。
  • 传回小结果集。

您将比本机java实现慢得多。如果你坚持使用基本的“C”,比如java操作(+, - ,*,==,>),使用“本机”数据类型(int,char,String),并避免花哨的库,Java的执行速度几乎一样快作为C.

Java性能的剩余bug是启动JVM并使所有事情发生的时间,但是当你从Java程序开始时,这是一个非问题。

“慢”java性能的另一个原因是人们坚持使用不必要的工厂,容器,xml bean等等,其中简单明了的方法可以更好地完成工作。

答案 1 :(得分:3)

在Android根应用程序文件夹中创建一个JNI文件夹(其中有src,res)。放置代码(1),将其命名为someshared-lib.c。

(1)

Java_YourPackageName_YourClassNameWhereYoudeclareYourNativeFunction_NativeFuntionName(JNIEnv* env,jobject thiz)
{


//your c code , the JNI will act as a wrapper for it

return (*env)->NewStringUTF(env, "<string to pass or you can mention jchar * type string >");

}

(2)IN java file

package YourPackageName;

public class YourClassNameWhereYoudeclareYourNativeFunction extends Activity
{

    public native String  NativeFuntionName();
    String returnValue = NativeFuntionName();


}

(3)在Android.mk中执行此操作:

LOCAL_PATH:= $(致电my-dir)

包括$(CLEAR_VARS)

LOCAL_MODULE:= someshared-lib //注意libname与c文件名相同

LOCAL_SRC_FILES:= someshared-lib.c //这是您放置代码的文件(1)

包括$(BUILD_SHARED_LIBRARY)

导出你的ndk-build (导出PATH =:$ PATH

转到上面创建的JNI文件夹: 执行ndk-build命令

您将在Application根文件夹中形成的lib文件夹中创建一个库 someshared-lib 。在构建和运行应用程序时,这将与apk并将安装在设备中。要验证这一点,您可以转到

/ data / data / your_package_name / lib文件夹。

应用程序在/ data / data / your_package_name / lib(也是/ system / lib)文件夹中搜索了此lib,并将其用于从Android应用程序进行的动态调用(JNI)。

现在,如果你想要返回除字符串以外的任何内容,你必须在c文件中更改上述方法declration,如下所示:

Java_YourPackageName_YourClassNameWhereYoudeclareYourNativeFunction_NativeFuntionName(JNIEnv* env,jclass obj,jobject thiz)
{
jfieldID fid;
jboolean enable_flag;

//Pass the class object having all the variable from the android app to  the JNI in the jclass obj and access its members using the field ID and using Get and Set firld ID.

clazz = (*env)->GetObjectClass(env, info);
fid = (*env)->GetFieldID(env,clazz,"some_variable","X"); //"X" - type of variable for boolean it //is Z , for INtezer it is I, for double it is D,

请参阅此document以获取详细说明

//for getting teh value fomr the JNI
 enable_flag = (*env)->GetBooleanField(env, **thiz**, fid);


//for setting the value 

fid = (*env)->GetFieldID(env,clazz,"other_float_variable","D");
(*env)->SetDoubleField(env,**thiz**,fid,other_float_variable);



}

同样在Android应用程序中,您必须传递结构的Class对象。 例如

(2)现在将成为:

打包YourPackageName;

public class YourClassNameWhereYoudeclareYourNativeFunction extends Activity
{

    public native String  NativeFuntionName();
    String returnValue = NativeFuntionName( exampleStruct exst);

其中exampleStruct:

public class exampleStruct {

protected boolean  some_variable = 0;//no log saving by default 
protected float  other_float_variable   = 0;

}

}

希望这有帮助。

答案 2 :(得分:2)

使用 Android NDK
下载n个文档Android NDK 1.6

这将使您免于为lib编写JNI层,并且还会将应用程序安装在应用程序数据文件夹的lib文件夹中。

答案 3 :(得分:2)