zoukankan      html  css  js  c++  java
  • Android NDK 学习之传递类对象

    本博客主要是在Ubuntu 下开发,且默认你已经安装了Eclipse,Android SDK, Android NDK, CDT插件。

    在Eclipse中添加配置NDK,路径如下Eclipse->Window->Preferences->Android->NDK ,选择NDK的路径,然后Apply即可。

    新建一个名为AndroidJNI_Object的Android工程,新建一个jni的文件夹,其目录下文件树列表如下:

    ├── jni
    │   ├── Android.mk
    │   ├── Application.mk
    │   └── object
    │      ├── Android.mk
    │      ├── logger.h
    │      └── object_jni.c

    jni/Application.mk文件内容如下:

    APP_ABI := all

    jni/Android.mk,主要用来指定顺序执行所有子文件夹下面的makefile文件,内容如下:

    include $(call all-subdir-makefiles)

    jni/object/Android.mk,主要用来指定需要编译出的动态库的名称,以及需要编译的源文件,内容如下:

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE     := object_jni
    LOCAL_SRC_FILES := object_jni.c
    
    LOCAL_LDLIBS := -llog
    
    include $(BUILD_SHARED_LIBRARY)

    jni/object/logger.h 主要用来在JNI层打印日志,内容如下:

    #include <jni.h>
    #include <android/log.h>
    
    /**
     * 定义log标签
     */
    #define TAG "jni_logger"
    
    /**
     * 定义info信息
     */
    #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
    
    /**
     * 定义debug信息
     */
    #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
    
    /**
     * 定义error信息
     */
    #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)

    jni/object/object_jni.c,主要用来注册绑定java函数和native函数,以及java函数在c中相应函数的具体实现, 内容如下:

    #include "logger.h"
    
    #ifndef NULL
    #define NULL   ((void *) 0)
    #endif
    
    /**
     * 获取数组的大小
     */
    #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
    
    /**
     * 指定要注册的类,对应的完整的java类名
     */
    #define JNIREG_CLASS "com/clarck/jni/MainActivity"
    #define JNIPAR_CLASS "com/clarck/jni/Person"
    
    struct PersonOffsets
    {
        jfieldID  name;
        jfieldID  age;
        jfieldID  height;
    } gPersonOffsets;
    
    typedef struct tagPerson
    {
        char     mName[10];
        int        mAge;
        float    mHeight;
    } Person;
    
    static Person gPersons[] = {
            {"clarck", 25, 175},
            {"lilei", 30, 166},
            {"hanmeimei", 51, 172},
    };
    
    #define GPERSON_NUM NELEM(gPersons)
    
    JNIEXPORT jint JNICALL native_object(JNIEnv *env, jobject clazz, jobject person, jint index) {
        if ((int) index < 0 || (int) index >= GPERSON_NUM)
            return -1;
    
        //将Person数组中的第index个成员赋值给pPerson指针
        Person *pPerson = &gPersons[index];
        //设置java对象的person的mName
        jstring name = (*env)->NewStringUTF(env, pPerson->mName);
        (*env)->SetObjectField(env, person, gPersonOffsets.name, name);
        //设置java对象person的mAge
        (*env)->SetIntField(env, person, gPersonOffsets.age, pPerson->mAge);
        //设置java对象person的mHeight
        (*env)->SetFloatField(env, person, gPersonOffsets.height, pPerson->mHeight);
    
        LOGD("%s index-%d mName:%s, mAge:%d, mHeight:%f
    ",
                __func__, index, pPerson->mName, pPerson->mAge, pPerson->mHeight);
    
        return 0;
    }
    
    static void nativeClassInit(JNIEnv *env) {
        jclass personClass = (*env)->FindClass(env, JNIPAR_CLASS);
        gPersonOffsets.name     = (*env)->GetFieldID(env, personClass, "mName", "Ljava/lang/String;");
        gPersonOffsets.age      = (*env)->GetFieldID(env, personClass, "mAge", "I");
        gPersonOffsets.height     = (*env)->GetFieldID(env, personClass, "mHeight", "F");
    }
    
    /**
     * Java和JNI函数绑定
     */
    static JNINativeMethod method_table[] = {
            { "getPersonInfoByIndex", "(Lcom/clarck/jni/Person;I)I", (void*) native_object },
    };
    
    /**
     * 注册native方法到java中
     */
    static int registerNativeMethods(JNIEnv* env, const char* className,
            JNINativeMethod* gMethods, int numMethods) {
        jclass clazz;
        clazz = (*env)->FindClass(env, className);
        if (clazz == NULL) {
            return JNI_FALSE;
        }
    
        if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
            return JNI_FALSE;
        }
    
        return JNI_TRUE;
    }
    
    /**
     * 调用注册方法
     */
    int register_ndk_load(JNIEnv* env) {
        nativeClassInit(env);
        return registerNativeMethods(env, JNIREG_CLASS, method_table,
                NELEM(method_table));
    }
    
    JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
        JNIEnv* env = NULL;
        jint result = -1;
    
        if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
            return result;
        }
    
        register_ndk_load(env);
    
        //返回jni的版本
        return JNI_VERSION_1_4;
    }

    接着在Project中右键Android Tools->Add Native Support,最后java层调用如下:

    package com.clarck.jni;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.util.Log;
    
    public class MainActivity extends Activity {
        private Person mPerson = null;
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
            Log.d("Test", "onCreate");
            mPerson = new Person();
            for (int i = 0; i < 3; i++) {
                getPersonInfoByIndex(mPerson, i);
                Log.d("Test", "mPersion[" + i + "] -- " + mPerson);
            } 
        }
        
        private native int getPersonInfoByIndex(Person person, int index);
        
        static {
            System.loadLibrary("object_jni");
        }
        
    }
    package com.clarck.jni;
    
    public class Person {
        private String mName;
        private int mAge;
        private float mHeight;
        
        @Override
        public String toString() {
            return "mName: " + mName + ", mAge: " + mAge + ", mHeight: " + mHeight;
        }
        
    }

    运行结果如下:

    04-15 15:37:30.916: D/Test(31477): onCreate
    04-15 15:37:30.916: D/jni_logger(31477): native_object index-0 mName:clarck, mAge:25, mHeight:175.000000
    04-15 15:37:30.916: D/Test(31477): mPersion[0] -- mName: clarck, mAge: 25, mHeight: 175.0
    04-15 15:37:30.916: D/jni_logger(31477): native_object index-1 mName:lilei, mAge:30, mHeight:166.000000
    04-15 15:37:30.916: D/Test(31477): mPersion[1] -- mName: lilei, mAge: 30, mHeight: 166.0
    04-15 15:37:30.916: D/jni_logger(31477): native_object index-2 mName:hanmeimei, mAge:51, mHeight:172.000000
    04-15 15:37:30.916: D/Test(31477): mPersion[2] -- mName: hanmeimei, mAge: 51, mHeight: 172.0
  • 相关阅读:
    Pacbio三代基因组组装简介
    微生物组与代谢组关联分析
    软件架构学习小结
    Android中TextView中加图片,超链接,部分字或者背景变色。。。不断补充中
    Android 使用 ViewPager 实现左右滑动 Fragment
    Android 使用 ViewPager 实现左右滑动 View
    Android 使用 ViewPager 实现左右循环滑动图片
    Fragment 与 Activity 通信
    Android App 组件之 ListFragment
    Android 官方推荐: DialogFragment 创建对话框
  • 原文地址:https://www.cnblogs.com/tanlon/p/4428760.html
Copyright © 2011-2022 走看看