AndroidStudio中使用JNI的两种方式

0x01 前言

  本文讲述使用Android Studio通过静态注册、动态注册使用JNI的方法,以及加载第三方so文件的方法

 

0x02 Android Studio静态注册的方式使用JNI

  1. 添加native接口

复制代码
public class MainActivity extends Activity implements OnClickListener {

    static{
        System.loadLibrary("JniTest");
    }

    private native int Add(double num1,double num2);
    private native int Sub(double num1,double num2);
    private native int Mul(double num1,double num2);
    private native int Div(double num1,double num2);


    @Override
    protected void onCreate(Bundle savedInstanceState) {
    }
}
复制代码

  在Java类中使用System.loadLibrary("JniTest")加载我们要写的so库名称,Add/Sub/Mul/Div这四个方法在Java类中声明就可以使用了。

 

  2.Build->Make Project
  验证工程中并无其他错误,并对工程进行编译,生成.class文件
  在Build/intermediates/classes/debug里面

 

  3.javah 生成.h文件

  cmd 进入工程目录在工程的app/src/main/java ,执行 javah com.example.caculate.MainActivity 命令,就会生成so库所需要的.h文件

  在/app/src/main/下建立jni目录,将.h拷贝进去

 

  4.jni目录下新建一个.c文件,完成so库的函数实现(注:这里的Android.mk文件并不需要,可以不写,用法在下面会提到)

  
  


  5.Build->Make Project  会报错,这里在android studio中添加ndk路径编译生成so文件

        ①在local.properties文件中增加ndk的路径

 

 

  ②在/app/目录下的build.gradle文件里增加 so的名称

ndk {
  moduleName "JniTest"
  abiFilters "armeabi", "armeabi-v7a", "x86"
}

 

  6.Build->Make Project 就可以编译出so文件了
  生成的so在app/Build/intermediates/ndk/debug/lib下面

 

  7.点击运行,就可以使用我们实现的so中的代码了

 

 (注:在so库中实现在原结果基础上加2)

 

  使用模拟器利用busybox安装grep命令之后,我们可以通过/proc/<pid>/maps文件中保存的进程加载模块,查看我们写的so文件是否被加载了。

 

  8.我们JNI的实现文件

  ①com_example_caculate_MainActivity.h文件

复制代码
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_caculate_MainActivity */

#ifndef _Included_com_example_caculate_MainActivity
#define _Included_com_example_caculate_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_caculate_MainActivity
 * Method:    Add
 * Signature: (DD)I
 */
JNIEXPORT jint JNICALL Java_com_example_caculate_MainActivity_Add
  (JNIEnv *, jobject, jdouble, jdouble);

/*
 * Class:     com_example_caculate_MainActivity
 * Method:    Sub
 * Signature: (DD)I
 */
JNIEXPORT jint JNICALL Java_com_example_caculate_MainActivity_Sub
  (JNIEnv *, jobject, jdouble, jdouble);

/*
 * Class:     com_example_caculate_MainActivity
 * Method:    Mul
 * Signature: (DD)I
 */
JNIEXPORT jint JNICALL Java_com_example_caculate_MainActivity_Mul
  (JNIEnv *, jobject, jdouble, jdouble);

/*
 * Class:     com_example_caculate_MainActivity
 * Method:    Div
 * Signature: (DD)I
 */
JNIEXPORT jint JNICALL Java_com_example_caculate_MainActivity_Div
  (JNIEnv *, jobject, jdouble, jdouble);

#ifdef __cplusplus
}
#endif
#endif
复制代码

  ②so库中实现函数的main.c文件

复制代码
#include <jni.h>
#define jintJNICALL
#ifndef _Included_com_example_caculate_MainActivity
#define _Included_com_example_caculate_MainActivity
#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT jintJNICALL Java_com_example_caculate_MainActivity_Add
        (JNIEnv *env, jobject obj, jdouble num1, jdouble num2)
{
    return (jint)(num1 + num2+2);
}


JNIEXPORT jintJNICALL Java_com_example_caculate_MainActivity_Sub
        (JNIEnv *env, jobject obj, jdouble num1, jdouble num2)
{
    return (jint)(num1 - num2+2);
}


JNIEXPORT jintJNICALL Java_com_example_caculate_MainActivity_Mul
        (JNIEnv *env, jobject obj, jdouble num1, jdouble num2)
{
    return (jint)(num1 * num2+2);
}

JNIEXPORT jintJNICALL Java_com_example_caculate_MainActivity_Div
        (JNIEnv *env, jobject obj, jdouble num1, jdouble num2)
{
    if (num2 == 0) return 0;
    return (jint)(num1 / num2+2);
}
#ifdef __cplusplus
}
#endif
#endif
复制代码

 

 0x03 Android Studio动态注册的方式使用JNI

  1.jni目录下直接编写so库中的.c文件

  JNI_Onlad会作为so库被加载后的第一个执行函数,最后通过RegisterNatives函数将JNI函数注册

按 Ctrl+C 复制代码
按 Ctrl+C 复制代码

 (注:这里Android.mk文件也不需要,在下面会提到)

 

  2.在Java类中添加native接口,加载JniTest.so,以及声明native函数,声明之后,函数可以直接使用。

复制代码
public class MainActivity extends Activity implements OnClickListener {

    static{
        System.loadLibrary("JniTest");
    }

    private native int Add(double num1,double num2);
    private native int Sub(double num1,double num2);
    private native int Mul(double num1,double num2); private native int Div(double num1,double num2); @Override protected void onCreate(Bundle savedInstanceState) { } }
复制代码

  

   3.make Project 生成so库,如果之前没有修改/app/build.gradle文件和在local.properties中指定ndk路径则会报错。报错参考静态使用JNI中的步骤5,指定ndk路径,并且指定so名称和输出的架构。

  

  生成成功,则在/app/build/intermediates/ndk/debug/lib目录下生成相应的so文件

  

 

  4.在虚拟机中运行

      (注:这里的结果在原结果上加1)



 0x04 Android Studio加载第三方库

  1.使用ndk生成so文件

  ①建立jni目录(随便在哪个地方)

  ②编写so库中的.c函数,这里完全使用0x03 Android Studio动态注册的方式使用JNI中的c文件,使用动态注册的方式

  ③编写Android.mk文件(单独使用ndk编译so文件的时候需要用到)

复制代码
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := JniTest
LOCAL_SRC_FILES := MyJniCalc.c
LOCAL_SHARED_LIBRARIES := libandroid_runtime
include $(BUILD_SHARED_LIBRARY)
复制代码

  ④使用cmd进入jni目录,执行ndk-build,生成so文件

  

  

  2.加载生成的so文件,打包进apk中

  ①我们在/app目录下建立libs目录,将我们的so文件拷贝进去

  这里可以使用ndk自己生成的so文件,也可以使用其他第三方so文件

  

  

  ②改写/app/build.gradle文件,编译的时候将so生成上图中的libJniTest.jar文件

复制代码
apply plugin: 'com.android.application'

android {
    compileSdkVersion 16
    buildToolsVersion "23.0.3"

    defaultConfig {
        applicationId "com.example.caculate"
        minSdkVersion 8
        targetSdkVersion 16
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }

    sourceSets.main {
        jni.srcDirs = []
        jniLibs.srcDir 'src/main/libs'
    }

    task nativeLibsToJar(type: Zip, description: "create a jar archive of the native libs") {
        destinationDir file("$projectDir/libs")
        baseName "libJniTest"
        extension "jar"
        from fileTree(dir: "libs", include: "**/*.so")
        into "lib"
    }

    tasks.withType(JavaCompile) {
        compileTask -> compileTask.dependsOn(nativeLibsToJar)
    }

}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:support-v4:18.0.0'
    compile files('libs/libJniTest.jar')
}
复制代码

  其中into "lib" 是生成的jar文件存放的目录,include: "**/*.so" 为所依赖的so文件

 

 

   ③在Java类中添加so的接口

复制代码
public class MainActivity extends Activity implements OnClickListener {

    static{
        System.loadLibrary("JniTest");
    }

    private native int Add(double num1,double num2);
    private native int Sub(double num1,double num2);
    private native int Mul(double num1,double num2);
    private native int Div(double num1,double num2);


    @Override
    protected void onCreate(Bundle savedInstanceState) {
    }
}
复制代码

  

  4.Make Project,点击运行

  这里不需要指定ndk路径,so库的名称也不需要在/app/build.gradle中指定,在Android.mk中指定

(注:这里结果在原结果上加1)

 

0x05 总结

  这里是Android Studio中的使用方法,刚开始也是各种百度,弄得很复杂,在后面的学习中也懂得了很多,所以今天将使用方法重新整理了一遍,希望大家可以不要浪费太多时间。静态注册方法主要要用javah生成.h文件,显得比较复杂,每次添加函数都要重新生成.h文件,不过如果知道函数名称的格式也可以不生成.h文件,实践中,在jni目录下只有main.c文件也是可以运行成功的。动态注册方法直接在函数中注册比较容易动态扩展,但是需要对注册的数据类型有所了解,可以参考静态方法生成的.h文件中有对应的数据类型。加载第三方库感觉是最实用的,不管是so文件加密,还是使用不开源的so库,都需要加载已经生成的so文件。

    注意/app/build.gradle中的sdk版本要改成自己android studio中sdk有的版本,如果没有也可根据android studio提示下载。

  代码下载:http://pan.baidu.com/s/1dFyWHhf

  

identity 身份认证 购VIP最低享 7 折! triangle vip 30元优惠券将在 04:24:36 后过期 去使用 triangle 数据可视化是将复杂的数据集通过图表、图像等视觉元素进行呈现,以便于人们更容易地理解和解读数据。在“数据可视化期末课设~学生成绩可视化分析.zip”这个压缩包中,我们可以看到一系列与数据可视化相关的资源,包括Jupyter代码、HTML图片、答辩PPT以及Word文档,这些内容涵盖了数据可视化的基础到高级应用,适合于完成一个全面的期末课程设计项目。 Jupyter代码是使用Python编程语言进行数据处理和可视化的主要工具。在这个项目中,学生可能使用了pandas库来加载和清洗数据,可能涉及到的数据处理步骤包括去除重复值、处理缺失值以及数据类型转换等。接着,他们可能使用matplotlib或seaborn库来创建各种图表,如直方图、散点图、箱线图等,以展示学生成绩的分布、对比和趋势。此外,更高级的可视化库如plotly或bokeh可能也被用来实现交互式图表,增加用户对数据的理解深度。 保存的HTML图片是Jupyter Notebook的输出结果,它展示了代码运行后的可视化效果。这些图片可以直观地揭示学生成绩的统计特征,例如平均分、标准差、最高分和最低分等。通过颜色编码或者图例,我们可以识别出不同科目或者不同班级的表现,帮助分析教学质量和学生学习情况。 答辩PPT则可能包含项目的概述、目的、方法、结果和结论。在PPT中,学生可能会详细阐述他们选择特定可视化方法的理由,如何解读图表,以及从数据中得出的洞察。此外,PPT的制作也是展示其表达和沟通能力的重要部分,要求清晰、有逻辑地组织信息。 Word文档可能是项目报告,详细记录了整个过程,包括数据来源、预处理步骤、使用的可视化技术、分析结果以及可能遇到的问题和解决方案。报告中的数据分析部分会详细解释图表背后的含义,例如通过对比不同学科的分数分布,找出哪些科目可能存在困难,或者分析成绩与特定因素(如性别、年级等)的关系。 这个压缩包提供了完整的数据可视化项目实例,涉及了数据获取、处理、可视化和解释的一系列步骤,对于学习和掌握数据可视化技能非常有价值。通过这样的练习,学生不仅能够提高编程技巧,还能培养数据驱动思维和问题解决能力,为未来从事数据分析或相关领域的工作打下坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值