Android学习——第一个NDK程序
在前面的学习中,我们已经讲解了关于NDK编程的环境搭建流程,简单的使用我们也通过官网本身自带的例子进行说明了。可是相信大家一定还存在这么的一个疑惑:“如果我要自己利用NDK编写一个Android应用,具体应该怎么做?有什么要求”。OK,别担心,下面就让我们一起来利用NDK来编写一个简单的Android应用。
1 创建一个新的Project
1) 通过以下命令创建一个新的Android Project (详细的使用方法,大家可以回去重新参考博文《Android学习第二天-android常用命令》)
android create project -n myfirstndk -t 1 -p ./myfirstndk -k cn.uc.myjni -a MainActivity
当Project创建成功后,我们可以通过查看文件夹发现它的大体架构如下图:
2 开始Coding
1) 进入该项目的MainActivity.java所在的目录下,新建一个定义本地方法的类 NumberSum.java ,输入以下代码:
1 package cn.uc.myjni;
2
3 public class NumberSum {
4
5 // 声明一个本地方法
6 public native int add (int a, int b);
7
8 // 加载名为 libnumber_sum.so的库
9 // 根据Unix的规则,系统为自动为number_sum
10 // 添加上lib前缀和.so后缀
11 static {
12 System.loadLibrary("number_sum");
13 }
14 }
2) 调用以下命令,编译NumberSum.java
javac -encoding UTF-8 NumberSum.java
编译成功后,控制台并没有特别的输出,同时,我们可以在目录下发现Number.class文件
这里需要注意的是,我的命令中之所以指定源文件使用的编码是因为我使用的是UTF-8编码,在windows中直接通过javac NumberSum.java 进行编译的话,会出现以下错误:
3) 返回项目源代码文件夹下,比如我的就是返回到src目录下,通过javah命令,生成头文件:
javah cn.uc.myjni.NumberSum
执行成功后,控制台没有输出什么特别的内容,同时,我们可以发现在src目录下多了一个头文件:
javah生成的头文件知识讲解:
① 从头文件的名字我们可以看出,它是由编译的调用本地方法的类名及其所在的包名通过下划线"_"分割组成。如我们的程序中是编译cn.uc.myjni.NumberSum生成的,所以就算cn_uc_myjni_NumberSum
② 头文件中的内容可能很多,但是我们只关注这个方法的声明:
JNIEXPORT jint JNICALL Java_cn_uc_myjni_NumberSum_add (JNIEnv *, jobject, jint, jint);
在这个声明中,我们可以清晰的看到方法名的最后面add就是在NumberSum类中声明的本地方法add,而前面的是 cn_uc_myjni_NumberSum就算完整的包名和类名,由此我们可以知道,一个完整的JNI函数名有3部分组成:Java、定义native方法的类的全名(包名+类名)、实际的函数名。这三部分用"_"进行连接。
4) 在Project的根目录下,新建一个文件夹jni (必须叫做jni),将我们之前生成的头文件移动到jni文件夹下,如图:
5) 新建一个c文件,名字为 number_sum.c,输入以下代码:
1 #include <jni.h>
2
3 // 此处的方法签名与头文件中声明的方法签名是相同的
4 // 建议直接从头文件中复制过来
5 JNIEXPORT jint JNICALL Java_cn_uc_myjni_NumberSum_add(JNIEnv *env,jobject obj,jint a,jint b)
6 {
7 return (a+b);
8 }
下面讲解下上面的一些相关内容:
① JNIEXPORT jint JNICALL JNIEnv 等都是在jni.h中定义的;
② 其中上面参数中的env表示JNI的调用环境,obj表示定义native方法的Java类的对象本身。
6) 新建一个Android.mk 文件,建议直接从官方文档给的例子 hello-jni 中复制出来进行修改LOCAL_MODUE 和 LOCAL_SRC_FILES,代码如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := number_sum
LOCAL_SRC_FILES := number_sum.c
include $(BUILD_SHARED_LIBRARY)
下面我们简单讲解一下上面几个参数的含义吧:
① LOCAL_PATH:Android.mk 的第一行必须是LOCAL。用于指定参与编译的C/C++源文件的位置。在上面例子中,宏函数mydir 是由系统提供的,用来返回当前目录的路径。也就是包含Android.mk文件的目录的路径。
② include ${CLEAR_VARS}:CLEAR_VARS变量是在系统中定义的,用来指定一个特殊的GNU Make文件。该文件用来清空很多以LOCAL_开头的变量,例如LOCAL_MODULE、LOCAL_SRC_FILES、LOCAL_STATIC_LIBRARIES 等。但这些变量不包括LOCAL_PATH。之所以要清空这些变量,是因为这些都是全局变啦ing。同时这些变量又要在不同的GNU Make文件中使用,为了多个GNU Make文件不相互影响,就需要在执行每一个GNU make文件(Android.mk文件)之前先清空这些变量。
③ LOCAL_MODULE := number_sum :在每一个模块中必须定义 LOCAL_MODULE变量,用来指定生成的模块名。该变量的值必须是唯一的,而且不能包含任何空白分隔符。实际上,LOCAL_MODULE 变量的值就是生产共享库的文件名(不包括lib和.so),在编译时,系统会自动在文件名的前后添加上lib 和.so 。如果该模块名前缀加了lib,在生产共享库的时候不会进行添加。
④ LOCAL_SRC_FILES := number_sum.c:用来指定一个C/C++源文件列表,这里不需要指定头文件,系统会自动计算当前C/C++源文件 include的头文件。系统就直接将LOCAL_SRC_FILES变量指定的源文件传给编译器。C++源文件的默认扩展名是.cpp,但可以通过LOCAL_DEFAULT_CPP_EXTENSION 变量改变 C++文件默认拓展名,例如将该变量的值设成".cxx",注意不要忘记了" . "
⑤ include ${BUILD_SHARED_LIBRARY} : BUILD_SHARED_LIBRARY是在系统中定义的,用来指定一个GNU Make脚本文件。该脚本文件会根据以LOCAL_开头的变量来生成共享库文件。如果想生成静态库文件,可以使用BUILD_STATIC_LIBRARY变量。
7) 为了能够把我们调用共享代码库执行的程序结果显示出来,我们对生成的代码界面进行一定的修改:
I. 打开 res/layout/main.xml 文件,给TextView添加上一个Id,方便我们在后台通过id获取组件进行显示内容的修改:
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:orientation="vertical"
4 android:layout_width="fill_parent"
5 android:layout_height="fill_parent"
6 >
7 <!-- 给TextView 添加了ID -->
8 <TextView
9 android:id="@+id/info_text"
10 android:layout_width="fill_parent"
11 android:layout_height="wrap_content"
12 android:text="Hello World, MainActivity"
13 />
14 </LinearLayout>
II. 给我们的主界面MainActivity.java的onCreate() 方法添加上将结果显示到界面上的逻辑代码:
1 package cn.uc.myjni;
2
3 import android.app.Activity;
4 import android.widget.TextView;
5 import android.os.Bundle;
6
7 public class MainActivity extends Activity
8 {
9 /** Called when the activity is first created. */
10 @Override
11 public void onCreate(Bundle savedInstanceState)
12 {
13 super.onCreate(savedInstanceState);
14 setContentView(R.layout.main);
15
16 // 通过Id获取TextView组件
17 TextView textView=(TextView) findViewById(R.id.info_text);
18 NumberSum sum = new NumberSum();
19 // 调用本地方法
20 int result=sum.add(10, 20);
21 textView.append("/n 10+20="+result);
22 }
23 }
>更多相关文章
首页推荐
佛山市东联科技有限公司一直秉承“一切以用户价值为依归
- 01-11全球最受赞誉公司揭晓:苹果连续九年第一
- 12-09罗伯特·莫里斯:让黑客真正变黑
- 12-09谁闯入了中国网络?揭秘美国绝密黑客小组TA
- 12-09警示:iOS6 惊现“闪退”BUG
- 05-06TCL科技:预计大尺寸面板价格上涨动能有望延
- 05-06新加坡电信Optus任命新首席执行官以重建品牌
- 05-06微软宣布为消费级用户账户提供安全密钥支持
- 05-06当好大数据产业“守门员”(筑梦现代化 共绘
- 04-29通用智能人“通通”亮相中关村论坛
相关文章
24小时热门资讯
24小时回复排行
热门推荐
最新资讯
操作系统
黑客防御