jni 步骤

  这是我转的文章,是篇外文翻译,将介绍如何学习安装 Android NDK 并开始使用它。在这一教程结束后,将创建你自己的项目,从 Java 代码简单地调用原生C 语言代码。

教程细节

技术:Android SDK、NDK、C 语言

难度:进阶

预计完成时间:60-90 分钟(⊙﹏⊙b汗,还是挺长时间的)

先决经验:

      在开始之前,需要先花点时间了解一下这一教程的难度。它的标记是“进阶”。之所以标为“进阶”是因为作者想要确保你符合以下要求:

1、有Java和C语言经验。
2、能适应命令行操作。
3、知道如何了解你的 Cygwin、awk 和其他工具的版本。
4、能适应 Android Development。
5、有一个有效的 Android 开发环境(本文撰写时,笔者使用的是 Android 2.2)
5、使用 Eclipse 或者可以将 Eclipse 的指导步骤轻松应用于自己的 IDE 上。
6、就算并不满足这些条件,当然也欢迎你阅读这一教程,不过可能在某些步骤遇到困难。

      如果满足了以上条件这些困难就会轻易解除。也就是说,即使认为自己是个移动开发老手,使用 NDK 依然很容易碰到困难和麻烦。请注意可能要自行排查故障才能让一切正常运转于你的开发系统中。

      本教程提供完整的样例项目的开源代码。(我么有找到下载的东东)

何时使用 NDK 的说明

       好,正在阅读这篇教程的你,也许已经在考虑在你的 Android 项目中使用 NDK 了。不过,作者想要花点时间讨论一下 NDK 为什么那么重要、何时该使用它,以及——同等重要的,何时不该使用它。

        总的来说,只有当应用程序真的是个处理器杀手的时候,你才需要使用 NDK。也就是说,你设计的算法要利用 DalvikVM 中所有的处理器资源,而且原生运行较为有利。还有,别忘了在 Android 2.2 中,JIT 编译器会提高类似代码的效率。

       另一个使用 NDK 的原因是方便移植。如果在现有的应用程序中有大量的 C 语言代码,那么使用 NDK 不仅可以加速你项目的开发进程,也能在你的 Android 和非 Android 项目中保持修改的同步。这一点对于那些为其他平台而写的 OpenGL ES 应用程序来说尤为如此。

      别以为只要用了原生代码就能提高应用程序的效率。Java 与原生C 语言之间的转换会增加一些资源开销,因此只有你有一些集中消耗处理器资源的任务时才真正有必要这么做。

第 0 步:下载工具

       好了,现在就开始吧!你需要下载 NDK。先来开始下载,因为在下载的过程中你可以检查一下,确保所需要用到的其余工具的版本都正确。

       从 Android 网站下载适合你的操作系统的 NDK。
       现在,对照下列检查你的工具版本:
             1、如果在 Windows 下,Cygwin 1.7 或更高版本
             2、将 awk 升级到最新版本(我们使用的是 20070501)
             3、GNU Make 3.81 或更高版本(我们使用的是 3.81)

          如果其中任何一个的版本太旧,请在继续之前先升级。

第 1 步:安装 NDK

        既然 NDK 已经下载完成(没错吧?),你就需要解压缩它。解压后将它放入合适的目录中。要把它放在和 Android SDK 相同的目录下。记住你把它放在哪里了

        现在,你也许想要在路径设置中添加 NDK 工具。如果你在 Mac 或 Linux 下,你可以用你的原生路径设置来完成。如果你在 Windows 下的 Cygwin,你就需要设置 Cygwin 的路径设置。

第 2 步:创建项目

         创建一个常规的 Android 项目。为了避免日后的问题,你项目的路径必须不包含空格。作者的项目有个叫做“com.mamlambo.sample.ndk1”的包,带有一个叫做“AndroidNDK1SampleActivity”的默认 Activity——你之后还会看到它们。
      
         在这个项目的顶层创建一个叫做“jni”的目录——这是你放置原生代码的地方。如果你很熟悉 JNI,那你就会知道 Android NDK 很大程度上基于 JNI 的概念——它本质上是个只有有限的 C 语言编译头文件的 JNI。

第 3 步:添加一些 C 语言代码

       现在,在 jni 文件夹中,创建一个叫做 native.c 的文件。一开始将以下 C 语言代码写入该文件,我们以后再添加另一个函数:

  1. #include 
  2. #include 
  3. #include 
  4. #define DEBUG_TAG "NDK_AndroidNDK1SampleActivity" 
  5. void Java_com_mamlambo_sample_ndk1_AndroidNDK1SampleActivity_helloLog(JNIEnv * env, jobject this, jstring logThis) 
  6. jboolean isCopy; 
  7. const char * szLogThis = (*env)->GetStringUTFChars(env, logThis, &isCopy); 
  8. __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "NDK:LC: [%s]", szLogThis);
  9. (*env)->ReleaseStringUTFChars(env, logThis, szLogThis); 
  10. }
复制代码

      这个函数实际上非常浅显。它获取一个 Java 对象的字符串参数,将它转换为 C-string,然后将它写入到 LogCat 中。

        不过该函数的名字很重要。它遵循了以“Java”的特定字样开头,后面跟着包名称,然后类名称,然后方法名称,和 Java 中定义的一样。每一部分都由一根下划线隔开,而不是点。

        该函数的头两个参数也很重要。第一个参数是 JNI 环境,它与 helper 函数会被频繁调用。第二个参数是该函数所属的Java 对象。

第 4 步:从 Java 中调用原生代码

        既然你已经写好了原生代码,让我们回头看看 Java 这边。在默认的 Activity 中,按照你的喜好创建一个按钮,并添加一个按钮处理器。从按钮处理器中,对 helloLog 作调用:

  1. helloLog("This will log to LogCat via the native call.");
复制代码

       然后你必须在 Java 这边添加函数声明。在你的 Activity 类中添加如下声明:

  1. private native void helloLog(String logThis);
复制代码

      它告诉编译和链接系统该方法将在原生代码中实现。

      最后,你需要加载原生代码最终编译到的库。在 Activity 类中添加如下的静态初始化程序来根据名称加载库(库的名字随你决定,在下一步还会用到):

  1. static { 
  2. System.loadLibrary("ndk1"); 
  3. }
复制代码

第 5 步:添加原生代码的 Make 文件
        
       在 jni 文件夹中,现在你需要添加在编译中要用到的 makefile。该文件必须以“Android.mk”命名,如果你之前命名的文件为 native.c,库为 ndk1,那么 Android.mk 的内容就应该是这样:

  1. LOCAL_PATH := $(call my-dir) 
  2. include $(CLEAR_VARS) 
  3. LOCAL_LDLIBS := -llog 
  4. LOCAL_MODULE := ndk1 
  5. LOCAL_SRC_FILES := native.c 
  6. include $(BUILD_SHARED_LIBRARY)
复制代码

第 6 步:编译原生代码
    
        既然你的原生代码已完成,make 文件也已就绪,是时候编译原生代码了。在命令行下(Windows 用户在 Cygwin 下),你需要在你的项目的根目录下运行 ndk-build 命令。ndk-build 工具就在 NDK 工具目录中。将它添加到我们的路径中是最方便的办法。
1.png 
      在之后的编译中,如果你使用“ndk-build clean”命令,那么你可以确保所有的东西都被重新编译了。

第 7 步:运行代码

      现在你已准备妥当可以运行代码了。在你最喜欢的模拟器或者手持设备中载入该项目,查看 LogCat,然后点击按钮。
可能有两件事情会发生。首先,它可能正常工作了。这样的话,恭喜你!不过你可能还是想要继续阅读下去。

      你也可能在 LogCat 中得到类似“Could not execute method of activity”这样的错误。这很正常。这只是说明你漏掉了某个步骤罢了。用 Eclipse 很容易发生这种情况。通常,Eclipse 被设置为自动重编译。

        如果它不知道有东西被修改了,它就不会自动重编译和重链接。在本例中,Eclipse 不知道你编译了原生代码。所以,“清除(cleaning)”该项目(在 Eclipse 工具栏中点击项目(Project)->清除(Clean)),强制 Eclipse 重编译。

第 8 步:添加另一个原生函数

       接下来的函数将不仅演示返回值的能力,还会演示返回例如字符串这样的对象的能力。在 native.c 中添加如下函数:

  1. jstring Java_com_mamlambo_sample_ndk1_AndroidNDK1SampleActivity_getString(JNIEnv * env, jobject this, jint value1, jint value2) 
  2. char *szFormat = "The sum of the two numbers is: %i"; 
  3. char *szResult; 
  4. // add the two values 
  5. jlong sum = value1+value2; 
  6. // malloc room for the resulting string 
  7. szResult = malloc(sizeof(szFormat) + 20); 
  8. // standard sprintf 
  9. sprintf(szResult, szFormat, sum); 
  10. // get an object string 
  11. jstring result = (*env)->NewStringUTF(env, szResult); 
  12. // cleanup 
  13. free(szResult); 
  14. return result; 
  15. }
复制代码

       为了正常编译,你会需要添加一个 include stdio.h 的声明。而且,为了响应这个新的原生函数,请在你的 Activity Java 类中添加如下声明:

  1. private native String getString(int value1, int value2);
复制代码

       你现在可以随意设定其功能。我们使用如下两个调用和输出:

  1. String result = getString(5,2);
  2. Log.v(DEBUG_TAG, "Result: "+result); 
  3. result = getString(105, 1232); 
  4. Log.v(DEBUG_TAG, "Result2: "+result);
复制代码

       回到 C 语言函数中,你会注意到我们做了许多事情。首先,我们在使用 malloc() 函数中的 sprintf() 调用时需要创建一个缓冲器(buffer)。如果你不会忘记通过使用 free() 函数清理结果,那么这就很合理了。

        然后,为了传回结果,你可以使用一个叫作 NewStringUTF() 的 JNI helper 函数。该函数基本上就是获取一个 C 语言字符串,以之创建一个新的 Java 对象。这个新的字符串对象就可以在之后作为结果返回,你就可以在 Java 类中将它作为一个常规 Java 字符串对象使用了。
2.png 

指令集、兼容性
        Android NDK 需要 Android SDK 1.5 或更高版本。在新版本的 NDK 中,有些新的头文件可用于扩大对某些 API 的访问——特别是 OpenGL ES 库。

       不过,那些都不是我们要谈论的兼容性。这是原生代码,在使用时由处理器构架编译。因此,你要问自己的一个问题会是它支持何种处理器构架?在目前的 NDK 中(在本文撰写时)它只支持 ARMv5TE 和 ARMv7-A 指令集。默认设置下,目标架构被设置为 ARMv5TE,它可以在使用 ARM 芯片的 Android 设备上运行。

       它预计未来将支持其他指令集(其中提到了 x86)。这其中有很有意思的潜在状况:NDK 解决方案无法适用于所有的设备。例如,市面上有使用 x86 指令集的英特尔(Intel)Atom 处理器的 Android 平板设备。

       那么 NDK 在模拟器上如何呢?模拟器运行的是真正的虚拟机,包括完整的处理器虚拟。没错,这意味着在虚拟机中运行 Java 就等于是在虚拟机中运行了一个虚拟机。

总结
       成果如何?你装上了 Android NDK,最终完成了部分使用原生 C 语言代码的功能完善、正常运行的应用程序了吗?我们希望如此。在这一过程中有许多潜在的“出问题啦!”的可能,不过从某些方面来看,这些都是值得的。

转载于:https://www.cnblogs.com/songtzu/archive/2013/03/05/2944063.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/494287.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

德勤:2025年汽车行业价值链的四个合理情境

来源:亿欧摘要:近日,德勤发布《未来汽车行业价值链:2025年以后》,假设在大部分整车企业都有变革意愿的情境下,识别出四个2025年整车企业价值链可能具有的合理设定。随着自动驾驶、共享经济等新技术以及新商…

盘点英特尔、苹果、高通、AMD 处理器重大 Bug,硬件的坑软件能填?

来源:21ic电子网英特尔的CPU存在两大漏洞 ——Meltdown 和 Spectre,波及自 1995 年以来所有使用英特尔芯片的硬件设备。不止 Linux、Android、Windows、苹果 OS X 等操作系统,AWS、Azure、谷歌云等云计算提供商均受到影响,其威胁范…

java读写html文件时出现中文乱码问题的解决方法

最近在做HTML静态生成,需要从硬盘上把模版文件的内容读出来。然后,替换相关标签写到指定的文件中。无论是读写,都遇到了中文乱码问题。试过多种方法,发现下面一种可以避免中文乱码。(无论读取还是写入一定要进行编码转…

Android实现网络音乐播放器

本文是一个简单的音乐播放器 布局代码 <?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"android:layo…

【干货51页PPT】深度学习理论理解探索

来源&#xff1a;专知普林斯顿大学计算机科学系教授Sanjeev Arora做了深度学习理论理解探索的报告&#xff0c;包括三个部分&#xff1a;Why overparametrization and or overprovisioning?Optimization in deep learningTheory for Generative Models and Generative Adversa…

新星计划·第三季【博文流量密码公开课】

一、优质的内容 刚开始写博客的小伙伴&#xff0c;其不可漫无目的的写&#xff0c;到头来对自己的技术沉淀毫无帮助&#xff0c;升职加薪跳槽也不加分&#xff0c;更无法通过付费专栏等方式进行变现&#xff0c;到头来一无所获&#xff01; 强烈建议大家提前规划写什么方向的…

百度地图开发之定位

本文主要讲述利用百度地图API实现定位功能 第一步:下载SDK与申请KEY 参考链接&#xff1a;Android 百度地图 SDK v3.0.0 &#xff08;一&#xff09; - Hongyang - 博客频道 - CSDN.NET 注意 百度地图SDK与百度定位SDK已经分开了&#xff0c;如果在工程中同时导入这两个包…

Java与Http协议

Java与Http协议 引言 http&#xff08;超文本传输协议&#xff09;是一个基于请求与响应模式的、无状态的、应用层的协议&#xff0c;常基于TCP的连接方式。HTTP协议的主要特点是&#xff1a; 1.支持客户/服务器模式。 2.简…

《Python 黑科技》一键分析评论关键词,制作精美词云

本文重点&#xff1a; 学会抓取文章评论 学会文本分词、制作词云 目录 &#x1f351; 一、抓取全部评论 &#x1f35e; 1、找到评论接口 &#x1f34f; 2、Python 获取评论 &#x1f3c8; 二、文本分词、词云制作 &#x1f34b; 1、文本分析 &#x1f350; 2、生成词云…

PANS最新脑神经科学研究:激活一种新语言并不费力气

来源&#xff1a;中国生物技术网美国纽约大学的一项新研究发现&#xff0c;我们在不同语言之间切换时的大脑工作模式&#xff0c;这使我们对双语现象有了新的理解。纽约大学博士生Esti Blanco-Elorrieta是这项研究的第一作者&#xff0c;他解释说&#xff1a;“多语言能力者的一…

百度地图之添加覆盖物

本文主要讲解如何实现在百度地图上添加覆盖物 1.承载数据的实体 我们从服务器返回的数据部分&#xff0c;最终可能是个Json数组&#xff0c;我们需要转换为实体集合&#xff0c;即下面的Info.java 我直接在实体类中声明了一个静态列表集合&#xff0c;模拟从服务器返回的数据…

能力认证计划 -- 名企内推保 offer 直通车

CSDN 能力认证的目的&#xff1a;清晰定义工程师能力模型&#xff0c;面向开发者、技术爱好者、在校大学生等群体&#xff0c;通过机试&#xff08;真人露脸、全程录屏、限时提交&#xff09;测出应试者的真能力&#xff0c;筛选合格软件人才&#xff0c;建立应聘者与企业之间的…

fprintf 和 perror 的理解1

程序中的两种出错处理&#xff1a; 第一种: 用fprintf 2: #include <string.h> 3: #include <errno.h> 4: #include <stdlib.h> 5: 1: #include <stdio.h> 6: int main(void) 7: { 8: FILE *fp; 9: 10: if((fp fopen("1.c…

全文!《2018中国IoT报告》!

来源&#xff1a;5G9月15-18日&#xff0c;我国物联网领域规格最高、规模最大的国家级博览会——2018世界物联网博览会将在无锡举行。作为2018世界物联网博览会的重要活动之一&#xff0c;9月14日受大会组委会委托&#xff0c;中国经济信息社在无锡发布《2017-2018年中国物联网…

CSDN客户端实现

本文主要讲解实现了一个CSDN的安卓客户端&#xff0c;主要知识点如下 java爬虫获取网页数据 将java程序打包成jar包 FragmentviewpagerTabPageIndicator实现Tab效果 gestureImageView实现放大缩小图片imageLodar实现异步加载图上 XListView实现下拉刷新 java爬虫获取网页资源…

抓住金三银四的尾巴,解锁程序员面试《刷题神器》

点赞 ➕ 评论 ➕ 收藏 三连再看你最帅 刷题 不仅能掌握知识&#xff0c;快速学习进步。 更能轻松搞定面试&#xff0c;尤其是有的大厂 钟爱问算法题&#xff0c;你不刷就不会&#xff0c;就会被pass。同时&#xff0c;刷题能陶冶情操&#xff0c;避免老年痴呆 &#x1f60b; …

腾讯AI Lab开源世界首款自动化模型压缩框架PocketFlow:将深度学习装进口袋

来源&#xff1a;腾讯AI 实验室腾讯AI Lab机器学习中心今日宣布成功研发出世界上首款自动化深度学习模型压缩框架——PocketFlow&#xff0c;并即将在近期发布开源代码。这是一款面向移动端AI开发者的自动模型压缩框架&#xff0c;集成了当前主流&#xff08;包括腾讯AI Lab自研…

【拿走不谢】大数据高效查询神器--bitmap

背景 在hive中使用Roaring64Bitmap实现精确去重功能 主要目的&#xff1a; 提升 hive 中精确去重性能&#xff0c;代替hive 中的 count(distinct uuid)&#xff1b;节省 hive 存储 &#xff0c;使用 bitmap 对数据压缩 &#xff0c;减少了存储成本&#xff1b;提供在 hive 中…

Android之智能问答机器人

本文主要利用图灵机器人的接口&#xff0c;所做的一个简单的智能问答机器人 实现 由于发送与接收消息都是不同的listView&#xff0c;所以要用有两个listVeiw的布局文件 接收消息布局文件 <?xml version"1.0" encoding"utf-8"?> <LinearLa…

5张图告诉你:同样是职场人,差距怎么这么大?

点赞 ➕ 评论 ➕ 收藏 养成三连好习惯 在职场中&#xff0c;我们常常会听到各种各样的抱怨&#xff1a; &#x1f469;‍⚖️‍ 小A: 凭什么别人每次述职绩效都是优秀呀&#xff1f; 感觉TA也没干啥呀! &#x1f575; 小B: 凭啥这个事情&#xff0c;领导指派TA去对接呀&#…