一、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. String,StringBuffer,StringBuilder 的区别是什么

    Java中用于处理字符串常用的有三个类: 1.java.lang.String 2.java.lang.StringBuffer 3.java.lang.StrungBuilder 一.Java St ...

  2. Python 爬虫实现天气查询(可视化界面版)

    github项目地址:StarMan Python 实现天气查询的程序早已完成,近日开学无课,昨晚心血来潮想做一个较为友好的界面版本,便匆忙行动了起来. 在之前已有的程序的基础上使用Tkinter 模 ...

  3. springMVC的简单了解和环境搭建

    一,什么mvc 模型-视图-控制器(MVC)是一个众所周知的以设计界面应用程序为基础的设计思想.它主要通过 分离模型.视图及控制器在应用程序中的角色 将业务逻辑从界面中解耦.通常, 模型负责封装应用程 ...

  4. bat 获取当前文件夹的文件名

    bat 获取当前文件夹的文件名 @echo off pushd %1 & for %%i in (.) do set curr=%%~ni echo %curr% pause

  5. linux 没有界面内容显示不全解决办法

    1.管道 管道简单理解就是,使用管道意味着第一个命令的输出会作为第二个命令的输入,第二个命令的输出又会作为第三个命令的输入,依此类推.利用Linux所提供的管道符“|”将两个命令隔开,管道符左边命令的 ...

  6. js实现QQ跳转到支付宝APP并领取红包!附:动图demo

    前天我在sg开源了js实现微信跳转到支付宝并领红包的代码.https://segmentfault.com/a/11...于是朋友圈开始刷屏,各种套路,各种标题,再附上短链接,引起了很多人的好奇,然后 ...

  7. 获取DataFrame列名的3种方法

    df= pd.DataFrame({'a': range(10, 20), 'b': range(20, 30)}) df 1.链表推倒式 [column for column in df][a,b] ...

  8. Centos7 Memcached 安装

    1.Linux系统安装memcached,首先要先安装libevent库. yum install libevent libevent-devel 2.安装memcached yum install ...

  9. LDA的参数确定和主题数确定方法

    主题数确定:困惑度计算,画出曲线,选择拐点,避免信息丢失和主题冗余 https://blog.csdn.net/u014449866/article/details/80218054 参数调节: 方法 ...

  10. 2 MVC设计模式

    0 基础知识 (1)B/S与C/S结构 C/S(客户机/服务器 client/service):分为客户机和服务器两层,应用软件安装在客户端通过网络与服务器通信 B/S(liulanq/服务器 bro ...