android ndk jni层访问java对象小结

来源:互联网 发布:大学java 教不教线程 编辑:程序博客网 时间:2024/05/21 04:05

一.



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 -landroidLOCAL_LDLIBS    := -lloginclude $(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=trueandroid.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)#endifextern "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
原创粉丝点击