android ndk jni层访问java对象小结

20 篇文章 0 订阅

一.



android studio2.2.3采用ndk-build编译C++项目的流程:

  

1.创建的项目切换到project视图下,在main目录下新建一个jni目录


2.jni目录下新建一个Android.mk文件:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := testjni	//需要生成的so库文件,可自定义
LOCAL_C_INCLUDES+= $(LOCAL_PATH)
SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp)
SRC_FILES := $(SRC_FILES:$(LOCAL_PATH)/%=%)

LOCAL_SRC_FILES := $(SRC_FILES)

#LOCAL_LDLIBS    := -llog -landroid
LOCAL_LDLIBS    := -llog

include $(BUILD_SHARED_LIBRARY)

3.build文件的配置:


apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    defaultConfig {
        applicationId "com.example.lxb.ndk_1"
        minSdkVersion 22
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

        ndk{
            moduleName "testjni"
            abiFilters "armeabi"	//这里可添加支持cpu架构
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        ndkBuild {
            path 'src/main/jni/Android.mk'	//选用mk的方式编译项目,将mk文件选择link C++之后自动生成,也可手动配置
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.1.1'
    testCompile 'junit:junit:4.12'
}

3.在gradle.properties 添加下面一行


# Project-wide Gradle settings.

# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.

# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html

# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true

android.useDeprecatedNdk=true		//添加这一行

4.jni类:

package com.example.lxb.ndk_1.ndk;

/**
 * Created by lxb on 2017/3/21.
 */

public class HelloJni {

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

    public static native String getJniString();


    public native int operateArray(int[] a, int[] b);

    public native static String strConcat(String str1, String str2);

    public native int[] getIntArray(int size);

    public native void sortIntArray(int[] ints);


    public native void accessJavaMethod();

    /**
     * 实例方法,在C++中调用
     *
     * @return
     */
    public String InstanceMethod() {
        return "JNI中通过方法id来调用java中的实例方法";
    }

    /**
     * 静态方法,在C++中调用
     *
     * java返回信息,在jni层打印出来
     * @return
     */
    public static String staticMethod() {
        return "JNI中通过方法id来调用静态方法";
    }

    /**
     * jni层传入信息,在java层打印出来
     * @param info
     */
    public static void printInfo(String info){

        System.out.println("51------------copy info from jni is: "+info);
    }


    /**
     * C++中测试调用带参数的方法
     *
     * @param info
     * @return
     */
    public String paramMethod(String info) {
        return info;
    }


    /**
     * c++能过原生方法调用带有多个不同类型的参数方法
     *
     * @param a
     * @param str
     * @param array
     * @return
     */
    public String MuitleParamMethod(int a, String str, int[] array) {
        int total = 0;
        for (int i = 0; i < array.length; i++) {
            total += array[i];
        }
        String result = a + str + total;
        return result;
    }


    public native void callJavaObjMethod();

    //public native void callJavaObjField();

    public native void callJavaObjField(TestObj obj);
}

5.测试用的java类:

package com.example.lxb.ndk_1.ndk;



/**
 * Created by lxb on 2017/3/22.
 */

public class TestObj {


    public String name ;
    private int age;

    public static int num = 21;

    public int sex;


    public TestObj(){
        this.name = "liuhulai";

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    /**
     * 实例方法,在C++中调用
     *
     * @return
     */
    public String InstanceMethod() {
        return "JNI中通过方法id来调用java中的实例方法";
    }

    /**
     * 静态方法,在C++中调用
     *
     * java返回信息,在jni层打印出来
     * @return
     */
    public static String staticMethod() {
        return "JNI中通过方法id来调用静态方法";
    }


    @Override
    public String toString() {
        String sTmp = "名字:" + name + "年龄:" + age;
        return sTmp;
    }
}

6.mainactivity:

package com.example.lxb.ndk_1;

import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import com.example.lxb.ndk_1.ndk.HelloJni;
import com.example.lxb.ndk_1.ndk.TestObj;

/**
 * ndk-build编译方式
 */
public class MainActivity extends Activity {

    HelloJni jniObj;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        jniObj = new HelloJni();

    }

    private void initView() {

        Button jniStr = (Button) findViewById(R.id.btn_jnistr);
        Button jniArray = (Button) findViewById(R.id.btn_jniarray);
        Button jniString = (Button) findViewById(R.id.btn_jnistring);
        Button jniReturnArray = (Button) findViewById(R.id.btn_jni_return_array);
        Button jniSortArray = (Button) findViewById(R.id.btn_jniarray_sort);
        Button jniAccessJavaField = (Button) findViewById(R.id.btn_jni_access_java_field);
        Button jnicalljavamethod = (Button) findViewById(R.id.btn_jni_call_java_method);
        Button jnicalljavaObj = (Button) findViewById(R.id.btn_jni_call_java_obj);

        Button jnicalljavaObjField = (Button) findViewById(R.id.btn_jni_obj_field);
        Button jnicalljavaObjMethod = (Button) findViewById(R.id.btn_jni_call_obj_medthod);

        EventClick eventClick = new EventClick();
        jniStr.setOnClickListener(eventClick);
        jniArray.setOnClickListener(eventClick);
        jniString.setOnClickListener(eventClick);
        jniReturnArray.setOnClickListener(eventClick);
        jniSortArray.setOnClickListener(eventClick);
        jniAccessJavaField.setOnClickListener(eventClick);
        jnicalljavamethod.setOnClickListener(eventClick);
        jnicalljavaObj.setOnClickListener(eventClick);
        jnicalljavaObjField.setOnClickListener(eventClick);
        jnicalljavaObjMethod.setOnClickListener(eventClick);

    }

    private class EventClick implements View.OnClickListener {

        @Override
        public void onClick(View v) {

            switch (v.getId()) {
                case R.id.btn_jnistr:
                    System.out.println("40------------------jnistr:" + jniObj.getJniString());
                    break;

                case R.id.btn_jniarray:
                    int[] a = {1, 2, 3};
                    int[] b = {4, 5, 6};
                    System.out.println("40------------------jnistr:" + jniObj.operateArray(a, b));
                    break;

                case R.id.btn_jnistring:
                    System.out.println("55-------------opertion string:" + jniObj.strConcat("liuhulai", "刘小兵"));
                    break;

                case R.id.btn_jni_return_array:

                    int[] jniarray = jniObj.getIntArray(10);
                    System.out.println("65---------------get array from jni:");
                    for (int i = 0; i < jniarray.length; i++) {
                        System.out.print(jniarray[i] + " ");
                    }

                    break;

                case R.id.btn_jniarray_sort:

                    int[] sort = {9,0,7,6,8,5,3,4,2,1};
                    jniObj.sortIntArray(sort);
                    System.out.println("排序后的数组为:");
                    for (int x:sort) {
                        System.out.print(" "+x);
                    }

                    break;

                case R.id.btn_jni_access_java_field:
                    break;

                case R.id.btn_jni_call_java_method:
                    jniObj.accessJavaMethod();
                    break;

                case R.id.btn_jni_call_java_obj:
                    break;

                case R.id.btn_jni_obj_field:

                    TestObj obj = new TestObj();
                    jniObj.callJavaObjField(obj);
                    System.out.println("114--------------jni修改java对象之后的值 为:"+obj.getName() + " : age:  "+obj.getAge() + "  修改静态变量值为:  "+TestObj.num);

                    break;

                case R.id.btn_jni_call_obj_medthod:
                    jniObj.callJavaObjMethod();
                    break;
            }
        }
    }
}

7.cpp文件

//
// Created by lxb on 2017/3/21.
//

#include<jni.h>
#include<com_example_lxb_ndk_1_ndk_HelloJni.h>
#include "string.h"
#include "stdlib.h"
#include "time.h"
//定义随机数产生宏 表示产生0~x之间的随机数
#define random(x) (rand()%x)

#include<android/log.h>  //引入Adnroid打印日志文件


#define LOG    "NDKTest"                                                    // 日志打印标识
#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG,__VA_ARGS__)   // 对应AdnroidDEBUGg模式,下类似
#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG,__VA_ARGS__)
#define LOGW(...)  __android_log_print(ANDROID_LOG_WARN,LOG,__VA_ARGS__)
#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG,__VA_ARGS__)
#define LOGF(...)  __android_log_print(ANDROID_LOG_FATAL,LOG,__VA_ARGS__)

#ifndef NULL
#define NULL   ((void *) 0)
#endif

extern "C" {

    JNIEXPORT jstring JNICALL Java_com_example_lxb_ndk_11_ndk_HelloJni_getJniString
            (JNIEnv *env, jclass) {
        char *result = "2017-----------this is jnistring C++";

        jstring jstr = env->NewStringUTF(result);

        return jstr;
    }

    JNIEXPORT jint JNICALL Java_com_example_lxb_ndk_11_ndk_HelloJni_operateArray(JNIEnv *env, jobject,
                                                                                 jintArray arr1,
                                                                                 jintArray arr2) {

        jint *carr;
        jint *carr2;

        jint i, sum = 0;

        carr = env->GetIntArrayElements(arr1, 0);
        carr2 = env->GetIntArrayElements(arr2, 0);

        if (carr == NULL || carr2 == NULL) {
            return 0;
        }

        for (i = 0; i < env->GetArrayLength(arr1); i++) {
            sum += carr[i] * carr2[i];
        }

        env->ReleaseIntArrayElements(arr1, carr, 0);
        env->ReleaseIntArrayElements(arr2, carr2, 0);

        return sum;
    }


    JNIEXPORT jstring JNICALL Java_com_example_lxb_ndk_11_ndk_HelloJni_strConcat
            (JNIEnv *env, jclass clazz, jstring str1, jstring str2) {

        //jstring转换成const char*指针,使用const修饰符表示其内容不可被修改
        //引用类型不能直接使用都需要进行一次转换,下面使用UTF方式进行转换
        const char *c1 = env->GetStringUTFChars(str1, NULL);        //jstring 类型的str1转换为char* 指针类型 ,此时java层传过来的类型为jstring
        const char *c2 = env->GetStringUTFChars(str2, NULL);

        //计算新字符串的长度
        int size = strlen(c1) + strlen(c2);

        //创建一个新的字符串,这里长度+1是为了使字符串有结尾标记'\0'
        char *n_char = new char[size + 1];

        //利用C标准库提供的字符串操作方法对字符串进行连接,这里需要include"string.h"头文件
        strcpy(n_char, c1);
        strcat(n_char, c2);

        //将生成的新字符串转换成UTFjstring
        jstring rs = env->NewStringUTF(n_char);     //发生转换

        //删除刚刚分配的内存 避免引起内存泄漏
        delete[] n_char;

        //通知JVM虚拟机Native代码不在持有字符串的引用,说明白点,就是告诉虚拟机我不使用它了,你可以回收了。
        //因为在JVM中如果对象被引用,那么对象将不会被回收。
        //这里为什么要传递jstring和生成的char*呢?是因为char*有可能是jstring的拷贝,如果是拷贝,那么char*就应该被删除。
        env->ReleaseStringUTFChars(str1, c1);
        env->ReleaseStringUTFChars(str2, c2);

        return rs;

    }

    JNIEXPORT jintArray JNICALL Java_com_example_lxb_ndk_11_ndk_HelloJni_getIntArray
            (JNIEnv *env, jobject jobj, jint size){


        srand((int)time(0));         //用时间变量初始化随机数产生器

        jint* rs = new jint[size];     //创建一个新jint* 指针类型

        for (int i=0;i<size;i++)
        {

            rs[i] = random(100);      //调用宏产生0~100的随机数
        }

        jintArray array = env->NewIntArray(size);     //通过JNIEnvNewIntArray方法new一个jintArray对象,进行转换

        env->SetIntArrayRegion(array,0,size,rs);    //把产生的随机数值赋值给jintArray

        return array;
    }

    JNIEXPORT void JNICALL Java_com_example_lxb_ndk_11_ndk_HelloJni_sortIntArray
        (JNIEnv *env, jobject obj, jintArray array){

        jsize size = env->GetArrayLength(array);    //获取数组长度,其他数组也适用


        //将数组转换为jni层的指针
        jint* jints = env->GetIntArrayElements(array,NULL);


        //采用冒泡排序进行
        for (int i = 0; i <size-1 ; ++i) {
            for (int j = 0; j <size-1-i ; ++j) {
                if(jints[j] < jints[j+1])
                {
                    int t=jints[j];
                    jints[j]=jints[j+1];
                    jints[j+1]=t;
                }
            }
        }

        //将排序结果更新到Java数组中,第三个参数等于0表明更新到原数组并释放所有元素
        env->ReleaseIntArrayElements(array,jints,0);
        return;

    }


    JNIEXPORT void JNICALL Java_com_example_lxb_ndk_11_ndk_HelloJni_accessJavaMethod
        (JNIEnv *env, jobject obj){



        jclass ClassJNI = env->FindClass("com/example/lxb/ndk_1/ndk/HelloJni");     //查找类名

        jmethodID returnStringID = env->GetMethodID(ClassJNI, "InstanceMethod", "()Ljava/lang/String;");      //类名  方法名  形参类型,返回类型(java当中的返回类型)

        jstring jstr =(jstring)env->CallObjectMethod(obj,returnStringID);        //调用带返回参数的java方法
        const char *c_str = env->GetStringUTFChars(jstr, NULL);                  // 4. unicode编码的java字符串转换成C风格字符串
        LOGI("java中的方法执行结果是:%s",c_str);


        //调用有输入参数与返回值的方法
        jmethodID paramID = env->GetMethodID(ClassJNI, "paramMethod", "(Ljava/lang/String;)Ljava/lang/String;");

        jstring param = env->NewStringUTF("这是java方法中需要的参数");

        jstring jstr2 =(jstring)env->CallObjectMethod(obj, paramID, param);

        const char *c_str2 = env->GetStringUTFChars(jstr2, NULL);       //将字符串进行转换到jni层可以访问的类型

        LOGI("调用有输入参数与返回值的方法java中的方法执行结果是:%s",c_str2);



        //调用java中需要多个参数的方法
        jmethodID muitleParamId = env->GetMethodID( ClassJNI, "MuitleParamMethod", "(ILjava/lang/String;[I)Ljava/lang/String;");

        jint a=119;
        jstring tmp_jstr = env->NewStringUTF("liuzheyu");               //转换一个jni层的字符串
        jintArray ret = env->NewIntArray(3);                            //转换一个jni层的 实例化一个一维数组
        jint* buffer = new jint[1024];                                  //固定数组,测试用,注意别溢出
        for (int i = 0; i < 3; i++)
        {
            buffer[i]=i;
        }
        env->SetIntArrayRegion(ret, 0, 3, buffer);          //NativeType类型(jint)数组中,拷贝0~y数据到jintArray对象中

        jstring jstr3 =(jstring)env->CallObjectMethod(obj,muitleParamId,a,tmp_jstr,ret);         //调用带返回参数的java方法
        const char *c_str3 = env->GetStringUTFChars(jstr3, NULL);                                // 4. unicode编码的java字符串转换成C风格字符串
        LOGI("调用java中多个参数的方法结果是:%s",c_str3);
        env->DeleteLocalRef(ret);           //释放申请的jintArray,防止内存泄露 ,方式二:delete[] ret;
        env->DeleteLocalRef(tmp_jstr);
        env->DeleteLocalRef(jstr3);


        //访问java中的静态方法,打印java中静态方法返回的信息
        jmethodID staticId = env->GetStaticMethodID(ClassJNI,"staticMethod","()Ljava/lang/String;");
        jstring jstr_4 = (jstring) env->CallStaticObjectMethod(ClassJNI,staticId);
        const char * c_str4 = env->GetStringUTFChars(jstr_4,NULL);
        LOGI("访问java中的静态方法中结果是:%s",c_str4);



        //C++传入信息到java层打印出来,通过访问java的静态方法实现
        jmethodID mid = env->GetStaticMethodID(ClassJNI, "printInfo", "(Ljava/lang/String;)V");
        jstring jstr_44 = env->NewStringUTF("这条信息来自jni");  //这条信息来自jni转换为jstring类型
        //3.调用printInfo方法并传递参数
        //env->CallStaticVoidMethod(cls, mid, "JNI invoke Java Static Method");会报错,这种方法不允许
        //所以String参数需要通过NewStringUTF生成jstring使用
        env->CallStaticVoidMethod(ClassJNI, mid, jstr_44);


    }

    JNIEXPORT void JNICALL Java_com_example_lxb_ndk_11_ndk_HelloJni_callJavaObjMethod
        (JNIEnv *env, jobject cls){


        jclass clazz = NULL;
        jobject jobj = NULL;
        jmethodID mid_construct = NULL;
        jmethodID mid_instance = NULL;
        jstring str_arg = NULL;
        // 1、从classpath路径下搜索ClassMethod这个类,并返回该类的Class对象
        clazz = env->FindClass("com/example/lxb/ndk_1/ndk/TestObj");
        if (clazz == NULL) {
            LOGI("找不到'com/example/lxb/ndk_1/ndk/TestObj'这个类");
            return;
        }

        // 2、获取类的默认构造方法ID
        mid_construct = env->GetMethodID(clazz, "<init>","()V");
        if (mid_construct == NULL) {
            LOGI("找不到默认的构造方法");
            return;
        }

        // 3、查找实例方法的ID
        mid_instance = env->GetMethodID(clazz, "InstanceMethod", "()Ljava/lang/String;");
        if (mid_instance == NULL) {
            return;
        }

        // 4、创建该类的实例
        jobj = env->NewObject(clazz,mid_construct);
        if (jobj == NULL) {
            LOGI("com/example/lxb/ndk_1/ndk/TestObj类中找不到InstanceMethod方法");
            return;
        }

        // 5、调用对象的实例方法
        str_arg = env->NewStringUTF("我是实例方法");

        //env->CallVoidMethod(jobj,mid_instance,str_arg,200);
        jstring jstr =(jstring)env->CallObjectMethod(jobj,mid_instance);        //调用带返回参数的java方法
        const char *c_str = env->GetStringUTFChars(jstr, NULL);                  // 4. unicode编码的java字符串转换成C风格字符串
        LOGI("258-------java对象中的实例方法执行结果是:%s",c_str);

        // 删除局部引用
      /*  env->DeleteLocalRef(clazz);
        env->DeleteLocalRef(jobj);
        env->DeleteLocalRef(str_arg);*/





        //测试调用java对象中的静态方法
        jmethodID objStaticID = env->GetStaticMethodID(clazz,"staticMethod","()Ljava/lang/String;");
        if(objStaticID == NULL){
            LOGI("未找到'com/example/lxb/ndk_1/ndk/TestObj 里的staticMethod 方法");
            return;
        }
        //jstring sStatic = env->NewStringUTF("我是静态方法的参数");
        jstring jStaticStr = (jstring)env->CallStaticObjectMethod(clazz,objStaticID);
        const char *c_str2 = env->GetStringUTFChars(jStaticStr, NULL);                  // 4. unicode编码的java字符串转换成C风格字符串
        LOGI("275-------java对象中的静态方法执行结果是:%s",c_str2);


        env->DeleteLocalRef(clazz);
        env->DeleteLocalRef(jobj);
        env->DeleteLocalRef(str_arg);

    }

    JNIEXPORT void JNICALL Java_com_example_lxb_ndk_11_ndk_HelloJni_callJavaObjField(JNIEnv *env,jobject cls,jobject obj){

        jclass clazz = NULL;
        jfieldID fid = NULL;
        jstring j_str = NULL;
        jstring j_newStr = NULL;
        const char *c_str = NULL;


        clazz = env->GetObjectClass(obj);         // 1.查找需要调用的java,找到之后会默认调用构造方法
        if (clazz == NULL) {
            return;
        }

        fid = env->GetFieldID(clazz,"name", "Ljava/lang/String;");           // 2. 获取类实例变量name的属性ID
        if (fid == NULL) {
            return;
        }


        j_str = (jstring)env->GetObjectField(obj,fid);                     // 3. 获取实例变量name的值

        c_str = env->GetStringUTFChars(j_str,NULL);                          // 4. unicode编码的java字符串转换成C风格字符串
        if (c_str == NULL) {
            return;
        }
        LOGI("315--------获取到java对象的实例变量name = %s\n", c_str);
        env->ReleaseStringUTFChars(j_str, c_str);

        j_newStr = env->NewStringUTF("name from C String");                 // 5. 修改实例变量str的值

        if (j_newStr == NULL) {
            return;
        }

        env->SetObjectField(obj, fid, j_newStr);


        // 6.删除局部引用
        /*env->DeleteLocalRef( clazz);
        env->DeleteLocalRef(j_str);
        env->DeleteLocalRef(j_newStr);*/



        //获取静态变量
        jfieldID staticFieldID = env->GetStaticFieldID(clazz,"num","I");    //1.获取静态变量名
        if(staticFieldID == NULL){
            LOGI("未发现类中的静态变量num");
            return;
        }
        jint nNum = env->GetStaticIntField(clazz,staticFieldID);    //2.获取变量值
        LOGI("340------------静态变量num值为:%d\n",nNum);


        env->SetStaticIntField(clazz, staticFieldID, 27);                     // 4.修改静态变量num的值

        // 删除属部引用
        env->DeleteLocalRef(clazz);
        env->DeleteLocalRef(j_str);
        env->DeleteLocalRef(j_newStr);
    }


}















生成头文件的方法:在adnroid studio 终端那一栏下使用javah试:

D:\demo\NDK_1\app\src\main>javah -d jni -classpath ./java com.example.lxb.ndk_1.ndk.HelloJni


8.测试结果:

                                                               Remote Branch                    : 
                                                               Reconstruct Branch               : 
03-22 17:12:29.942 16717-16743/com.example.lxb.ndk_1 I/OpenGLRenderer: Initialized EGL, version 1.4
03-22 17:12:31.801 16717-16717/com.example.lxb.ndk_1 I/NDKTest: 315--------获取到java对象的实例变量name = liuhulai
03-22 17:12:31.801 16717-16717/com.example.lxb.ndk_1 I/NDKTest: 340------------静态变量num值为:21
03-22 17:12:31.801 16717-16717/com.example.lxb.ndk_1 I/System.out: 114--------------jni修改java对象之后的值 为:name from C String : age:  0  修改静态变量值为:  27


9.结果图:

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/layout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:layout_weight="1"
            android:id="@+id/btn_jnistr"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="获取jni字符串" />

        <Button
            android:layout_weight="1"
            android:id="@+id/btn_jniarray"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="获取jni数组" />

        <Button
            android:layout_weight="1"
            android:id="@+id/btn_jnistring"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="string类型交互" />

    </LinearLayout>



    <LinearLayout
        android:id="@+id/layout2"
        android:layout_below="@+id/layout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:layout_weight="1"
            android:id="@+id/btn_jni_return_array"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="获取jni返回数组" />

        <Button
            android:layout_weight="1"
            android:id="@+id/btn_jniarray_sort"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="jnijava数组排序" />

    </LinearLayout>


    <LinearLayout
        android:id="@+id/layout3"
        android:layout_below="@+id/layout2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:layout_weight="1"
            android:id="@+id/btn_jni_access_java_field"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="jni访问java属性" />

        <Button
            android:layout_weight="1"
            android:id="@+id/btn_jni_call_java_method"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="jni调用java方法" />

        <Button
            android:layout_weight="1"
            android:id="@+id/btn_jni_call_java_obj"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="jni调用java对象" />

    </LinearLayout>

    <TextView
        android:id="@+id/txt_1"
        android:layout_below="@+id/layout3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="jni操作java任意对象:"/>

    <LinearLayout
        android:id="@+id/layout4"
        android:layout_below="@+id/txt_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:layout_weight="1"
            android:id="@+id/btn_jni_obj_field"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="访问属性-静态,非静态" />

        <Button
            android:layout_weight="1"
            android:id="@+id/btn_jni_call_obj_medthod"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="访问方法-静态,非静态" />



    </LinearLayout>



</RelativeLayout>






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值