zoukankan      html  css  js  c++  java
  • Android:JNA实践(附Demo)

    一、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
     
     
  • 相关阅读:
    中国历史朝代公元对照简表
    [Solved] DashBoard – Excel Service: The data sources may be unreachable, may not be responding, or may have denied you access.
    Delete/Remove Project from TFS 2010
    Sharepoint site showing system account instead of my username on the top right corner.
    你的成功在于你每天养成的习惯
    Internet Information Services is running in 32bit emulation mode. Correct the issue listed above and rerun setup.
    Prepare to back up and restore a farm (Office SharePoint Server 2007)
    Word中字号与磅值的对应关系
    How to: Change the Frequency for Refreshing the Data Warehouse for Team System
    UI Automation in WPF/Silverlight
  • 原文地址:https://www.cnblogs.com/blogs-of-lxl/p/11013139.html
Copyright © 2011-2022 走看看