Android Ndk(Beginner ‘s guide)(2.4)

来源:互联网 发布:日本留学英语 知乎 编辑:程序博客网 时间:2024/06/05 22:36

Java 调用C/C++

 保持你的Eclipse打开知道我们完成。事实上我们已经有了一个工作项目,但是等会我们将使用本地代码来释放android的力量。因为刚刚那个仅仅是一个Java项目。在这部分,我们将创建C/C++资源文件,编译他们使他们成为名为mylib的本地库文件,然后使用Java来调用他们

 行动时间——从java调用c代码

 我们将创建的本地库文件mylib将会包含一个简单的方法getMyData(),他将返回一个简单的字符串。首先,我们将改写java代码来声明以及运行这个方法:

1.打开MyActivity.java。在主方法里面使用本地关键字声明本地方法但是不写方法的实现:

public class MyActivity extends Activity {
public native String getMyData();
...
2.然后,使用一段静态初始化语句来载入包含这个方法的本地库文件。这段语句将会在Activity线程初始化之前被调用:
...
static {
System.loadLibrary("mylib");
}
...

3.最后,当Activity被创建的时候,它调用本法方法并用其返回值来更新屏幕中的内容。你可以查看本书提供的最终代码:

...
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setTitle(getMyData());
}
}
现在让我们准备生成本地代码所需要的项目文件
4.在eclipse里面,在项目的根目录生成一个名为jni的文件夹
File|New|Folder
5.进入jni目录,创建一个名为Android.mk的新文件(File|New|File).如果CDT已经正确安装,这个文件在Package Explorer视图里面将会有一个特别的图标
6.然后在文件里面添加下面的内容。主要描述了怎么编译成名为mylib的本地库文件以及包含了一个名为com_myproject_MyActivity.c的资源文件

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := mylib
LOCAL_SRC_FILES := com_myproject_MyActivity.c


include $(BUILD_SHARED_LIBRARY)
完成了本地应用所需的编译文件,我们就可以开始写期待已久的本地代码。虽然C代码文件需要手写,但是相关的头文件可以用JDK提供的帮助工具生成:javah
7.在eclipse里面打开Run| External Tools| External Tools Configurations….
8.使用以下参数创建一个新的program配置:
    Name:MyProject javah
   位置参考javah的绝对路径,不同的操作系统不同:在Windows下你可以输入${env_var:JAVA_HOME}\bin\javah.exe。在Mac OS和linux下通常是/usr/bin/javah.
Working directory: ${workspace_loc:/MyProject/bin}.
Arguments: –d ${workspace_loc:/MyProject/jni} com.myproject.
MyActivity}.
9.在Refresh栏,勾上Refresh resoureces upon completion并且选择Specific resources,点击Specific Resource按钮,选择jni文件夹
10.最后点击Run按钮来保存很运行javah。在jni文件夹里面生成了名为com_myproject_MyActicity.h的新文件。它包含了Java方面希望用到的getMyData()的函数的声明:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
...
JNIEXPORT jstring JNICALL Java_com_myproject_MyActivity_getMyData
(JNIEnv *, jobject);
...

11.我们现在可以在jni目录下面创建com_myproject_MyActivity.c来返回一个字符串。函数名来自生成的头文件里面:
#include "com_myproject_MyActivity.h"
JNIEXPORT jstring Java_com_myproject_MyActivity_getMyData(JNIEnv* pEnv, jobject pThis)
{
return (*pEnv)->NewStringUTF(pEnv,
"My native project talks C++");
}

Eclipse还没有设置如何编译本地代码(jni里面的)只能编译java代码。我们将在本章末设置如果编译,我们现在可以手动编译本地代码

12.打开一个终端进入MyProject目录,使用ndk-build对本地代码进行编译
$ cd <your project directory>/MyProject
$ ndk-build

在libs/armeabi目录下面将会生成编译好的名为libmylib.so的库文件。编译过程中生成的零食文件在obj/local目录下

13.在eclipse下面,重新启动MyProject,你将获得下面的结果:


刚刚我们完成了什么?

在前面一节(2.3里面的),我们创建了一个android的Java项目,在这个部分我们使java代码与Android NDK编译C文件生成的本地库文件链接了起来。这种从java到C的绑定允许通过JNI从本地代码向Java传递一个返回值。样例程序展示了Java和C/C++怎么一起工作:
1.用Java创建UI部分,并且定义本地调用的函数
2.使用javah来生成即将使用的C/C++方法的头文件
3.写好本地代码来完成预期的操作
本地方法在java方面是用native关键字声明。这些方法没有函数体(想抽象方法一样)因为他们将会在native方实现方法。仅仅只是他们的原型需要被声明。本地方法可以有参数,返回值,其他属性(private prtected,package protected或者public)也可以是静态的(static),向典型的Java方法一样。当然他们需要在他被调用之前载入。载入的方法就是在静态初始化模块中使用System.loadLibrary()因为这样可以在控制类被载入的时候就初始化。有可能在第一次载入的时候产生错误,其错误异常在java.lang.UnsatisfiedLinkError中。
尽管它并不是必须的,JDK提供的javah工具对于生产本地代码的头文件非常有用。事实上,JNI协议是非常乏味的并且容易产生错误。通过生成的头文件,你就能立刻发现Java方所需要的本地方法是不是缺少或者不正确的声明。我建议你在你的项目里面有组织的使用javah,更具体的说,每次本地方法的声明改变的时候。JNI代码生成源于.class文件,那就意味着你的Java代码必须在使用javah之前编译。具体的实现应该是在独立的C/C++代码里面。
怎样在本地写JNI代码将会在下一章做更多细节的讨论。但是记住那个特殊的名字转换本地方法是必须遵守的,下面是模式的总结:
<returnType> Java_<com_mypackage>_<class>_<methodName> (JNIEnv* pEnv, <parameters>...)
本地方法是以Java_以及包名/类名(以_隔开)为前缀。第一个疑问总是JNIEnv类型(下章将会有更多解释)和传给Java方法的实际参数


原创粉丝点击