• 简单JNI使用demo


    android中使用JNI的小例子,直接上代码。

    首先是Java类JniClient,定义native方法,User实体类就不上代码了,就简单定义了三个属性,name、age、sex。

     1 package com.example.ndkdemo;
     2 
     3 public class JniClient {
     4     
     5     /**
     6      * 通过JNI简单输出字符串
     7      * @return
     8      */
     9     static public native String printStr();
    10     
    11     /**
    12      * 通过JNI简单进行整形加法操作
    13      * @param a
    14      * @param b
    15      * @return
    16      */
    17     static public native int addInt(int a, int b);
    18     
    19     /**
    20      * 通过JNI输入JAVA对象信息
    21      * @param user
    22      * @return
    23      */
    24     static public native String printUser(User user);
    25     
    26     /**
    27      * 通过JNI创建java对象
    28      * @param name
    29      * @param age
    30      * @param sex
    31      * @return
    32      */
    33     static public native User newUser(String name, int age, String sex);
    34     
    35     /**
    36      * 通过JNI调用无参构造函数创建java对象并且设置相应属性值
    37      * @param name
    38      * @param age
    39      * @param sex
    40      * @return
    41      */
    42     static public native User newUserNoArgs(String name, int age, String sex);
    43 }

    然后使用cmd进入工程的classes目录通过javah命令生成c代码的头文件,命令:javah com.example.ndkdemo.JniClient ,这里生成的文件名字为:com_example_ndkdemo_JniClient.h

    在工程下面新建一个jni目录,将生成的头文件拷贝到jni目录下面,创建com_example_ndkdemo_JniClient.c文件,在com_example_ndkdemo_JniClient.c文件里面实现各个native方法,代码如下:

      1 #include "com_example_ndkdemo_JniClient.h"
      2 #include <stdlib.h>
      3 #include <stdio.h>
      4 
      5 // 引入log头文件
      6 #include <android/log.h>
      7 // log标签
      8 #define TAG "jniCLient"
      9 // 定义info信息
     10 #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__)
     11 // 定义debug信息
     12 #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
     13 // 定义error信息
     14 #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__)
     15 
     16 
     17 #ifdef __cplusplus
     18 extern "C"
     19 {
     20 #endif
     21 /*
     22  * Class:     com_example_ndkdemo_JniClient
     23  * Method:    printStr
     24  * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
     25  */
     26 JNIEXPORT jstring JNICALL Java_com_example_ndkdemo_JniClient_printStr
     27   (JNIEnv *env, jclass arg)
     28 {
     29     jstring str = (*env)->NewStringUTF(env, "HelloWorld from JNI !");
     30     LOGI("log from jni");
     31     return str;
     32 }
     33 
     34 /*
     35 * Class:     com_example_ndkdemo_JniClient
     36 * Method:    AddInt
     37 * Signature: (II)I
     38 */
     39 JNIEXPORT jint JNICALL Java_com_example_ndkdemo_JniClient_addInt
     40   (JNIEnv *env, jclass arg, jint a, jint b)
     41 {
     42     return a + b;
     43 }
     44 
     45 /**
     46  * printUser
     47  * jclass arg:因为方法为static,所以需要传入jclass参数,表明是哪个类的方法
     48  */
     49 /**
     50  *1)如果是C++代码,则用(*env),如果是C代码,则用env,否则报错: request for member 'GetObjectClass' in something not a structure or union
     51  *2)所有方法都加了一个参数env,否则报错:too few arguments to function '(*env)->GetObjectClass'
     52  *3)不能把.C文件改成.CPP文件,否则没有规则可以创建“out/apps/JNI_0529/armeabi/objs/JNI_0529/android_jni_MyJNINative.o”需要的目标“apps/JNI_0529/proje*ct/jni/android_jni_MyJNINative.c”
     53  * 一个小例子错误真多啊!!NDK不简单啊!!
     54  */
     55 JNIEXPORT jstring JNICALL Java_com_example_ndkdemo_JniClient_printUser
     56   (JNIEnv *env, jclass arg, jobject obj)
     57 {
     58     LOGI("add from jni--打印用户信息--");
     59     //获得obj对象的类
     60     jclass cls_objClass = (*env)->GetObjectClass(env, obj);
     61     /**
     62      * 获得obj对象中特定方法getName的id
     63      * env
     64      * cls_objClass         方法所属类
     65      * getName              方法名字
     66      * ()Ljava/lang/String; 方法签名
     67      */
     68     jmethodID nameMethodId = (*env)->GetMethodID(env, cls_objClass, "getName", "()Ljava/lang/String;");
     69     /**
     70      * 调用obj对象的特定方法getName
     71      * obj      调用方法的目标对象
     72      * nameMethodId   调用方法的方法名
     73      * ...    后面还可以添加方法需要的参数
     74      */
     75     jstring js_name = (jstring)(*env)->CallObjectMethod(env, obj, nameMethodId);
     76     //将jstring转为c中的字符数组
     77     const char * name = (char *)(*env)->GetStringUTFChars(env, js_name, 0);
     78 
     79     jmethodID ageMethodId = (*env)->GetMethodID(env, cls_objClass, "getAge", "()I");
     80     jint ji_age = (*env)->CallIntMethod(env, obj, ageMethodId);
     81 
     82     jmethodID sexMethodId = (*env)->GetMethodID(env, cls_objClass, "getSex", "()Ljava/lang/String;");
     83     jstring js_sex = (jstring)(*env)->CallObjectMethod(env, obj, sexMethodId);
     84     const char * sex = (char *)(*env)->GetStringUTFChars(env, js_sex, 0);
     85 
     86     //打印信息
     87     LOGI("user info----name:%s, age:%d, sex:%s.", name, ji_age, sex);
     88 
     89     //释放资源
     90     (*env)->ReleaseStringUTFChars(env, js_name, name);
     91     (*env)->ReleaseStringUTFChars(env, js_sex, sex);
     92 //    printf("%s", str);
     93     return js_name;
     94 }
     95 
     96 /**
     97  * 创建一个对象(调用有参构造函数)
     98  */
     99 JNIEXPORT jobject JNICALL Java_com_example_ndkdemo_JniClient_newUser
    100   (JNIEnv *env, jclass arg, jstring name, jint age, jstring sex)
    101 {
    102     //创建一个class的引用,使用类的全包名
    103     jclass cls = (*env)->FindClass(env, "com/example/ndkdemo/User");
    104     //注意这里方法的名称是"<init>",它表示这是一个构造函数
    105     jmethodID id = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
    106     //获得一实例,后面接构造函数参数
    107 //    jobject obj = (*env)->NewObject(env, cls, id, name, age, sex);
    108     jstring jname = (*env)->NewStringUTF(env, "jni-liuling");
    109     jstring jsex = (*env)->NewStringUTF(env, "jni-男");
    110     jobject obj = (*env)->NewObject(env, cls, id, jname, 18L, jsex);
    111 
    112     return obj;
    113 }
    114 
    115 /**
    116  * 创建一个对象(调用无参构造函数)
    117  */
    118 JNIEXPORT jobject JNICALL Java_com_example_ndkdemo_JniClient_newUserNoArgs
    119   (JNIEnv *env, jclass arg, jstring name, jint age, jstring sex)
    120 {
    121     //创建一个class的引用,使用类的全包名
    122     jclass cls = (*env)->FindClass(env, "com/example/ndkdemo/User");
    123     //注意这里方法的名称是"<init>",它表示这是一个构造函数
    124     jmethodID id = (*env)->GetMethodID(env, cls, "<init>", "()V");
    125     //获得一实例,后面接构造函数参数
    126     jobject obj = (*env)->NewObject(env, cls, id);
    127     jstring jname = (*env)->NewStringUTF(env, "jni-liuling");
    128     jstring jsex = (*env)->NewStringUTF(env, "jni-男");
    129 
    130     //获取jfieldID
    131     jfieldID nameId = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;");
    132     jfieldID ageId = (*env)->GetFieldID(env, cls, "age", "I");
    133     jfieldID sexId = (*env)->GetFieldID(env, cls, "sex", "Ljava/lang/String;");
    134     (*env)->SetObjectField(env, obj, nameId, jname);
    135     (*env)->SetIntField(env, obj, ageId, 18L);
    136     (*env)->SetObjectField(env, obj, sexId, jsex);
    137 
    138     return obj;
    139 }
    140 
    141 #ifdef __cplusplus
    142 }
    143 #endif

    代码注释写的很详细,就不多讲了。

    下面创建在jni目录下面创建编译文件Android.mk,内容如下:

    1 LOCAL_PATH := $(call my-dir)
    2 include $(CLEAR_VARS)
    3 LOCAL_MODULE := NDKDemo
    4 LOCAL_SRC_FILES := com_example_ndkdemo_JniClient.c
    5 LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib -llog
    6 include $(BUILD_SHARED_LIBRARY)

    编译过程可以参考网上的,网上很多。下面是在android中调用的代码:

     1 package com.example.ndkdemo;
     2 
     3 import android.os.Bundle;
     4 import android.support.v7.app.ActionBarActivity;
     5 import android.util.Log;
     6 import android.view.View;
     7 import android.view.View.OnClickListener;
     8 import android.widget.Button;
     9 import android.widget.EditText;
    10 import android.widget.Toast;
    11 
    12 public class MainActivity extends ActionBarActivity {
    13 
    14     static {
    15         System.loadLibrary("NDKDemo");
    16     }
    17     
    18     @Override
    19     protected void onCreate(Bundle savedInstanceState) {
    20         super.onCreate(savedInstanceState);
    21         setContentView(R.layout.activity_main);
    22         findViewById(R.id.button).setOnClickListener(new OnClickListener() {
    23             @Override
    24             public void onClick(View v) {
    25                 //调用jni返回字符串
    26                 //Toast.makeText(MainActivity.this, JniClient.printStr(), Toast.LENGTH_LONG).show();
    27                 User user = new User("刘玲", 25, "男hahaah");
    28                 String name = JniClient.printUser(user);
    29                 Log.e("name", name + "");
    30 //                User user = JniClient.newUser("liuling", 18, "男");
    31 //                User user = JniClient.newUserNoArgs("liuling", 18, "男");
    32 //                Toast.makeText(MainActivity.this, user.toString(), Toast.LENGTH_LONG).show();
    33             }
    34         });
    35         final EditText num1 = (EditText) findViewById(R.id.num1);
    36         final EditText num2 = (EditText) findViewById(R.id.num2);
    37         final EditText result = (EditText) findViewById(R.id.result);
    38         Button addBtn = (Button) findViewById(R.id.addBtn);
    39         
    40         addBtn.setOnClickListener(new OnClickListener() {
    41             @Override
    42             public void onClick(View v) {
    43                 int n1 = Integer.valueOf(num1.getText().toString().trim());
    44                 int n2 = Integer.valueOf(num2.getText().toString().trim());
    45                 int n3 = JniClient.addInt(n1, n2);
    46                 result.setText(n3 + "");
    47             }
    48         });
    49         
    50     }
    51 
    52     
    53 }

    这里要注意14-16行,一定要加载so文件。

  • 相关阅读:
    黑马视频-事务
    黑马视频—循环
    黑马视频-子查询
    黑马视频-索引
    黑马视频-SQL之case
    总结 总结
    设计模式总结
    全局变量 /static全局变量 /局部变量/成员变量/extern 分析
    runtime 内涵篇
    runtime 使用总结
  • 原文地址:https://www.cnblogs.com/liuling/p/2015-8-7-1.html
Copyright © 2020-2023  润新知