一、JNA和JNI的对比

  1.JNI的调用流程
  Android应用开发中要实现Java和C,C++层交互时,想必首先想到的是JNI,但是JNI的使用过程十分繁琐,需要自己再封装一层JNI接口进行转换(使用SUN规定的数据结构去替代C语言的数据结构),包名、函数名等都要匹配,难以阅读和更新。
  如下图是通过JNI实现Java调用C层的方法流程:
  

  2.什么是JNA?与JNI有什么差异?

  JNA(Java Native Access):建立在JNI之上的Java开源框架,SUN主导开发,用来调用C、C++代码,尤其是底层库文件(windows中叫dll文件,linux下是so【shared object】文件)。JNA简化了Java调用原生函数的过程,原理是提供了一个动态的C语言编写的转发器(实际上也是一个动态链接库,在Linux-i386中文件名是:libjnidispatch.so)可以自动实现Java与C之间的数据类型映射。
  相比JNI,JNA只需要导入一个.jar和一个.so,然后就可以在Java中直接声明so中公开的函数并调用,十分方便。而JNA有两个小缺点:(1)性能上会比通过JNI调用动态链接库要稍低,但总体影响不大,因为JNA也避免了JNI的一些平台配置的开销。(2)因为JNA调用是直接在Java层实现,所以反过来C层无法直接通过JNA调用Java方法,但是Java层可以把方法模拟函数指针传到c层进行回调。
 
  

 二、JNA实践
 
  1. jna.jar包和libjnidispatch.so库文件下载
  
     JNA项目的Git Hub地址:https://github.com/java-native-access/jnalibjnidispatch.so 包含在android-armv7.jar中,以及jna.jar 都在 dist 目录下。
  
  2.导入jar包和so到Android studio工程
  (1)目录结构
    

  (2)build.gradle 配置

apply plugin: 'com.android.library'

android {
......
sourceSets{
main{
jniLibs.srcDirs = ['src/main/jniLibs']
}
}
......
} dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
......
}
   3.代码实现
     (1)新建一个Java接口直接加载第三方动态库 libnanovoice.so

    其中libnanovoice.so对于应的头文件(.h)内容如下:

#ifndef __JB_NANOSIC__H__
#define __JB_NANOSIC__H__ #ifdef __cplusplus
extern "C" {
#endif typedef void (*AppCallback) (char* data,int datalen); int nano_open(AppCallback cb);
int nano_close(void); #ifdef __cplusplus
}
#endif #endif

    根据动态库提供的头文件里函数声明,编写JnaNanovoice.java 内容如下:

package com.lxl.nanosic.voice;

import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
import com.sun.jna.Pointer; public interface JnaNanovoice extends Library {
public static final String JNA_LIBRARY_NAME = "nanovoice";
public static final NativeLibrary JNA_NATIVE_LIB = NativeLibrary.getInstance(JnaNanovoice.JNA_LIBRARY_NAME);
public static final JnaNanovoice INSTANCE = (JnaNanovoice)Native.loadLibrary(JnaNanovoice.JNA_LIBRARY_NAME, JnaNanovoice.class); //直接加载第三方动态库 //定义接口AppCallback,继承自com.sun.jna.Callback
public interface AppCallback extends Callback {
void dataReceived(Pointer data, int datalen);
} //动态库的函数声明
int nano_open(AppCallback cb);
int nano_close();
}

  c层和JNA层变量类型有所差异,需要转换:

  推荐一个转换工具 :jnaeratorStudio.jar   使用方法:java -jar jnaeratorStudio.jar

  (2)调用c库函数,其中Java回调接口需要进一步实现, NanoVoiceRecord.java 中JNA调用部分代码截取如下:

package com.lxl.nanosic.voice;

import android.util.Log;
import com.sun.jna.Pointer;
import java.util.LinkedList; public class NanoVoiceRecord { private final String TAG = "NanoVoiceRecord";/**
* 回调函数
*/
private static JnaNanovoice.AppCallback mDataCallback; ......   /** API 2:开始录音 **/
public void start() {
  ......
    // JNA接口
mDataCallback = new JnaNanovoice.AppCallback() {
// 实现接口中的回调
public void dataReceived (Pointer data, int datalen){
if(null != data){
byte[] buffer = data.getByteArray(0, datalen);
int res = OnDataReceived(buffer, datalen);
Log.w(TAG, "...OnDataReceived = " + res + "m_in_q.size=" + m_in_q.size());
} else {
Log.e(TAG, "...Callback data is null !!!");
}
}
};
// 开始录音并传入回调
JnaNanovoice.INSTANCE.nano_open(mDataCallback);
} /** API 3:停止录音 **/
public void stop()
{
JnaNanovoice.INSTANCE.nano_close(); //调用JNA接口退出录音
isRecording=false;
} ......   /**
* 处理c层回调上来的遥控器语音数据方法
*/
public int OnDataReceived(byte[] buffer, int size) {
byte[] bytes_pkg;
int bufferLength; if(m_in_q==null){
return 0;
} bytes_pkg = buffer.clone(); if (m_in_q.size() > 6) { //最多缓存6个包
m_in_q.removeFirst();
}
m_in_q.add(bytes_pkg); ......
}

  

  至此便实现了Java层通过JNA对c层函数的直接调用:

   JNA实践Demo(包含转换jar工具)已传至Git Hub : https://github.com/dragonforgithub/JnaDemo
 
 

Android:JNA实践(附Demo)的更多相关文章

  1. winserver的consul部署实践与.net core客户端使用(附demo源码)

    winserver的consul部署实践与.net core客户端使用(附demo源码)   前言 随着微服务兴起,服务的管理显得极其重要.都知道微服务就是”拆“,把臃肿的单块应用,拆分成多个轻量级的 ...

  2. Android 浮动窗口进阶——画中画,浮动视频(附Demo)

    今天继续上一篇Android顶层窗口.浮动窗口的进阶应用.上一篇主要讲解了WindowManager服务和如何使用WindowManager编写一个顶层窗口.今天主要是讲讲如何在顶层窗口里面播放视频, ...

  3. 开源分享:谷歌大佬联合打造《高级Kotlin强化实战(附Demo)》

    Kotlin 以其简洁的特性而闻名,而在我们的实践中,更加简洁就意味着更加高效.事实上,在使用 Kotlin 的专业 Android 开发者中,有多达 67% 的人表示 Kotlin 已经帮助他们提升 ...

  4. fir.im Weekly - 2016 年 Android 最佳实践列表

    2016 年已经过去一半,你在年初制定的成长计划都实现了吗? 学海无涯,技术成长不是一簇而就的事情.本期 fir.im Weekly 推荐 王下邀月熊_Chevalier的 我的编程之路--知识管理与 ...

  5. 学习笔记TF066:TensorFlow移动端应用,iOS、Android系统实践

    TensorFlow对Android.iOS.树莓派都提供移动端支持. 移动端应用原理.移动端.嵌入式设备应用深度学习方式,一模型运行在云端服务器,向服务器发送请求,接收服务器响应:二在本地运行模型, ...

  6. Atitit.嵌入式web 服务器 java android最佳实践

    Atitit.嵌入式web 服务器 java android最佳实践 1. Android4.4.21 2. 自己的webserver1 3. CyberHTTP for Java  cybergar ...

  7. 基于socket的客户端和服务端聊天简单使用 附Demo

    功能使用 服务端 分离一个不停接受客户端请求的线程 接受不客户端请求的线程中,再分离就收消息的线程 几大对象分别是 IPEndPoint IP终结点 服务端Socket,绑定终结点Bind,启动监听L ...

  8. Android最佳性能实践(三)——高性能编码优化

    在前两篇文章当中,我们主要学习了Android内存方面的相关知识,包括如何合理地使用内存,以及当发生内存泄露时如何定位出问题的原因.那么关于内存的知识就讨论到这里,今天开始我们将学习一些性能编码优化的 ...

  9. Android最佳性能实践(二)——分析内存的使用情况

    由于Android是为移动设备开发的操作系统,我们在开发应用程序的时候应当始终把内存问题充分考虑在内.虽然Android系统拥有垃圾自动回收机制,但这并不意味着我们就可以完全忽略何时去分配或释放内存. ...

随机推荐

  1. kubernetes之pod调度

    调度规则 deployment全自动调度: 运行在哪个节点上完全由master的scheduler经过一系列的算法计算得出, 用户无法进行干预 nodeselector定向调度: 指定pod调度到一些 ...

  2. JSON 对象和字符串

    JSON 对象和字符串 粘贴自:https://www.cnblogs.com/cstao110/p/3762056.html Q:什么是"JSON字符串",什么是"JS ...

  3. Objective-C语法总结收集

    PART1--详解Objective-C语法快速参考 一.XCode.Objective-C.Cocoa说的是几样东西? 答案:三样东西. XCode:你可以把它看成是一个开发环境,就好像Visual ...

  4. JavaScript实现数据的双向绑定

    接触到Angulr.js和Vue.js后,提到最多的就是双向绑定 下面将用JavaScript实现数据的双向绑定 <!DOCTYPE html> <html> <head ...

  5. AI行业精选日报_人工智能(12·23)

    日本探索用人工智能指挥交通 据日本共同社报道,日本一家机构正在研究开发一套新的交通系统,将应用人工智能技术分析数据来缓解城市交通拥堵.报道称,在日本新能源和产业技术综合开发机构研发的这套系统中,人工智 ...

  6. shell实现并发控制

    需求:并发检测1000台web服务器状态(或者并发为1000台web服务器分发文件等)如何用shell实现?                                              ...

  7. 4-windows启用账户锁定计数器

    1.打开本地策略编辑器 命令:gpedit.msc 2.找到账户锁定策略 3.右键属性,设置登录无效次数 注:这个策略修改完后,不需要重新服务器就能生效

  8. Java8-Stream-No.12

    import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.UUID; i ...

  9. 2018-2019 ICPC, NEERC J. Streets and Avenues in Berhattan(DP)

    题目链接:https://codeforc.es/contest/1070/problem/J 题意:给出一个长度为 k 的字符串,选出 n 个和 m 个不同位置的字符构成两个字符串,使得两个字符串相 ...

  10. Ubuntu 蓝牙鼠标一段时间失效的问题

    问题: 我有一个小巧的蓝牙鼠标,但有一个问题. 当它不使用一段时间时,它会关闭. 好的我得按按钮把它打开. 但是我发现,在我在蓝牙小程序下单击"连接"之前,它不会再被Ubuntu识 ...