zoukankan      html  css  js  c++  java
  • Android Studio下使用NDK的流程

    我要重新拿回持之以恒徽章!!

    老规矩,先说看能学会什么:ANDROID STUDIO下NDK的使用方法。JNI的基本使用方法,C语言调用JAVA的方法。


    首先要下载NDK,如果你没有VPN可以来http://www.androiddevtools.cn/进行下载。下载后解压到任意目录。

    其次,新建一个安卓项目。在MainActivity里添加一个Native方法。

      public native void showDialog();

    这里不以HelloWorld举例了。来使用Java来调用C语言的方法,然后C语言的方法里再次调用java的方法来show一个dialog。这里在MainActivity写show()方法

       public void show(String message){
            AlertDialog.Builder bulider = new AlertDialog.Builder(this);
            bulider.setTitle("title");
            bulider.setMessage(message);
            bulider.show();
        }


    写完了之后 点击Builde里面的 MakeProject


    然后打开终端 进入app/src/main/java目录,键入以下命令来编译头文件

    cd app/src/main/java

    javah -d ../jni com.wingsofts.jniii.MainActivity

    之后再android studio下可以看到jni文件夹以及头文件,这个头文件的命名是 包名+类名


    然后我们再来配置我们的gradle,编辑app目录下的build.gradle文件,在defaultConfig函数内加入以下函数。

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

    然后再编辑local.properties。加入你的NDK路径(即刚解压的ndk)

    sdk.dir=/Users/wing/android-sdk
    ndk.dir=/Users/wing/android-ndk-r10e

    此时,ndk的配置以及完成。我们将要用C语言实现函数的内容。

    在jni文件夹下新建一个C文件。这里我起名叫做Hello。

    具体怎么实现呢 首先看一下我们编译好的头文件是什么内容

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class com_wingsofts_jniii_MainActivity */
    
    #ifndef _Included_com_wingsofts_jniii_MainActivity
    #define _Included_com_wingsofts_jniii_MainActivity
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     com_wingsofts_jniii_MainActivity
     * Method:    showDialog
     * Signature: ()V
     */
    JNIEXPORT void JNICALL Java_com_wingsofts_jniii_MainActivity_showDialog
      (JNIEnv *, jobject);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    

    看到其中有一个函数 返回值为void 名称叫做 Java_com_wingsofts_jniii_MainActivity_showDialog,哇塞,这个函数名有点长。仔细观察,发现函数名是由包名加类名加函数名命名这也就解释了java和c方法是怎么对应的。然后看他的参数。(JNIEnv *,jobject),这是啥。。怎么看不懂呢。。 没关系,我们再来看看他include的一个头,jni.h

    这里不全部贴出来了。只进行摘录

    typedef const struct JNINativeInterface* JNIEnv;
    typedef const struct JNIInvokeInterface* JavaVM;
    找到了以上语句。 原来这个JNIEnv 是一个JNINativieterface的指针,也就是说是一个环境。再来看

    typedef void*           jobject;
    typedef jobject         jclass;
    typedef jobject         jstring;
    typedef jobject         jarray;
    typedef jarray          jobjectArray;
    typedef jarray          jbooleanArray;
    typedef jarray          jbyteArray;
    typedef jarray          jcharArray;
    typedef jarray          jshortArray;
    typedef jarray          jintArray;
    typedef jarray          jlongArray;
    typedef jarray          jfloatArray;
    typedef jarray          jdoubleArray;
    typedef jobject         jthrowable;
    typedef jobject         jweak;

    因为java的数据类型和C不一样,所以现在要用别名实现。这里是对应表。 可以看到这个函数第二个参数其实是jobject 也就是一个函数指针。

    现在大概了解了。快来实现我的c函数吧。

    #include "com_wingsofts_jniii_MainActivity.h"
    
    
    JNIEXPORT void JNICALL Java_com_wingsofts_jniii_MainActivity_showDialog(JNIEnv* env,jobject jobj){
        jclass clazz = (*env)->FindClass(env,"com/wingsofts/jniii/MainActivity");
        jmethodID method = (*env)->GetMethodID(env,clazz,"show","(Ljava/lang/String;)V");
        (*env)->CallVoidMethod(env,jobj,method,(*env)->NewStringUTF(env,"c调用java"));
    
    
    
    
    }
    这里首先导入编译好的头文件。

    然后实现方法名和头文件里的一样。 这个函数的目的是:调用java的方法,这里选择show一个dialog。所以需要用c语言来调用showDialog方法。于是要用到反射。跟java内的反射一样,先需要获取class然后放到类加载器中 在获得方法,才可以调用。

    通过jni.h看到  jclass 就是java的 class    jmethodID就是java的Method 。

    1.获取class

    首先使用(*env)->的 findClass方法 传入环境变量 env 第二个参数是要寻找的类名  以路径的形式写。

    2.获取method

    获取到clazz之后 在获取其中的方法  仍然是使用(*env)->的GetMethodID方法。传入环境env Class clazz 然后是实例的方法名"show",最后一个是方法的签名。看起来样子很奇怪。其实也不奇怪,首先()里面的是参数的类型,因为java里传入的是一个String 所以这里是(Ljava/lang/String;) 后面跟着是返回值,因为是VOID所以这里是V。如果你不确定你写的方法对不对呢。还可以使用javap -s来查看方法的签名。

    3.调用方法

    这里因为返回值为void所以使用CallVoidMethod 如果是返回obj就是CallObjectMethod, 这些都可以从jni.h看到。前三个参数不做解释了,大家都明白。这里解释一下最后一个参数。这个参数就是show(String message)的参数。一看是String的花 如果直接写"c调用Java"是错误的。因为Java的字符串和C的字符串不是同一个类型。所以要调用NewStringUTF来转换一下。

    好了这时我们的C语言文件遍实现好了。

    快来运行一下试试。得到效果图


    看起来也许不是很炫酷。但是想想这时由java调用C 在用C调用java来实现的。是不是立马变得高大上了?







  • 相关阅读:
    创建Variant数组
    ASP与存储过程(Stored Procedures)
    FileSystemObject对象成员概要
    Kotlin 朱涛9 委托 代理 懒加载 Delegate
    Kotlin 朱涛 思维4 空安全思维 平台类型 非空断言
    Kotlin 朱涛7 高阶函数 函数类型 Lambda SAM
    Kotlin 朱涛16 协程 生命周期 Job 结构化并发
    Proxy 代理模式 动态代理 cglib MD
    RxJava 设计理念 观察者模式 Observable lambdas MD
    动态图片 Movie androidgifdrawable GifView
  • 原文地址:https://www.cnblogs.com/muyuge/p/6333564.html
Copyright © 2011-2022 走看看