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来实现的。是不是立马变得高大上了?







  • 相关阅读:
    loadrunner -27778 https连接问题
    https调试
    Session Alerts
    Pause Web Sessions
    Customize Web Sessions List
    单例模式:Java单例模式的几种写法及它们的优缺点
    Activity: launchMode 和 Intent.FLAG_ACTIVITY_CLEAR_TOP
    TextView: android:ellipsize="marquee" 跑马灯效果无效的问题
    Socket通信(1):搭建开发环境
    linux: QT安装时出现段错误segmentation fault
  • 原文地址:https://www.cnblogs.com/muyuge/p/6333564.html
Copyright © 2011-2022 走看看