王学岗NDK系列(三):cc++调用java数组+JNI引用

一:C/C++访问java基本类型数组
1,作为参数传入
1)通过GetIntArrayElements接收数组指针
看下MainActivity类的代码

package com.example.acer.test_18_02_21;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    int[] a=new int[10];

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
        for(int i=0;i<10;i++){
            a[i]=i;
        }
        temp(a);
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
    public  native int[] temp(int[] a);
}

看下native-lib代码

#include <jni.h>
#include <string>
#include <android/log.h>

extern "C"
JNIEXPORT jstring

JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject jobj) {
    std::string hello = "Hello 我乃张飞是也from C++";
    return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT jintArray JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_temp(JNIEnv *env, jobject instance,
                                                         jintArray jintArray1) {
    //指针a与数组jintArray1进行关联
    jint *a = env->GetIntArrayElements(jintArray1, NULL);
    //获取数组的长度
    jsize jiasize=env->GetArrayLength(jintArray1);
     for(int i=0;i<jiasize;i++){
         //输出类型 target
         __android_log_print(ANDROID_LOG_ERROR,"JNI_tempp","%d",a[i]);
     }
    // TODO
    //释放 jintArray1与a的关联
    env->ReleaseIntArrayElements(jintArray1, a, 0);
    return jintArray1;
}

看下native-lib中的打印输出

02-23 14:06:22.235 3622-3622/com.example.acer.test_18_02_21 E/JNI_tempp: 0
02-23 14:06:22.235 3622-3622/com.example.acer.test_18_02_21 E/JNI_tempp: 1
02-23 14:06:22.235 3622-3622/com.example.acer.test_18_02_21 E/JNI_tempp: 2
02-23 14:06:22.235 3622-3622/com.example.acer.test_18_02_21 E/JNI_tempp: 3
02-23 14:06:22.235 3622-3622/com.example.acer.test_18_02_21 E/JNI_tempp: 4
02-23 14:06:22.235 3622-3622/com.example.acer.test_18_02_21 E/JNI_tempp: 5
02-23 14:06:22.235 3622-3622/com.example.acer.test_18_02_21 E/JNI_tempp: 6
02-23 14:06:22.235 3622-3622/com.example.acer.test_18_02_21 E/JNI_tempp: 7
02-23 14:06:22.235 3622-3622/com.example.acer.test_18_02_21 E/JNI_tempp: 8
02-23 14:06:22.235 3622-3622/com.example.acer.test_18_02_21 E/JNI_tempp: 9

2)通过GetIntArrayRegion复制数组
MainActivity类不用动,看下native-lib文件

#include <jni.h>
#include <string>
#include <android/log.h>

extern "C"
JNIEXPORT jstring

JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject jobj) {
    std::string hello = "Hello 我乃张飞是也from C++";
    return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT jintArray JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_temp(JNIEnv *env, jobject instance,
                                                         jintArray jintArray1) {
    //获取数组的长度
    jsize jiasize=env->GetArrayLength(jintArray1);
    //C中的数组需要固定的长度
    jintArray b[jiasize];
    //将Java数组复制到b数组中
    //四个参数1,java中的数组;2,数组开始复制的位置;3,数组的长度;4,jni环境下的数组指针,数组名直接代表数组的指针
    env->GetIntArrayRegion(jintArray1, 0, jiasize, (jint *) b);
    for(int i=0;i<jiasize;i++){
        //输出类型 target
        __android_log_print(ANDROID_LOG_ERROR,"JNI_tempp","%d",b[i]);
    }
    return jintArray1;
}

或者这样写

#include <jni.h>
#include <string>
#include <android/log.h>

extern "C"
JNIEXPORT jstring

JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject jobj) {
    std::string hello = "Hello 我乃张飞是也from C++";
    return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT jintArray JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_temp(JNIEnv *env, jobject instance,
                                                         jintArray jintArray1) {
    //获取数组的长度
    jsize jiasize=env->GetArrayLength(jintArray1);
    //C中的数组需要固定的长度
    jint b[jiasize];
    //将Java数组复制到b数组中
    //四个参数1,java中的数组;2,数组开始复制的位置;3,数组的长度;4,jni环境下的数组指针,数组名直接代表数组的指针
    env->GetIntArrayRegion(jintArray1, 0, jiasize, b);
    for(int i=0;i<jiasize;i++){
        //输出类型 target
        __android_log_print(ANDROID_LOG_ERROR,"JNI_tempp","%d",b[i]);
    }
    return jintArray1;
}

ps:接收数组指针时要用指针类型接收,复制数组时要用数组复制
2,未作为参数传入
1)通过GetArrayElements接收数组指针
MainActivity类,

package com.example.acer.test_18_02_21;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    int[] a=new int[10];

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        for(int i=0;i<10;i++){
            a[i]=i;
        }
        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());

        temp(a);
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
    public  native int[] temp(int[] a);
}

我们看下native-lib文件

#include <jni.h>
#include <string>
#include <android/log.h>

extern "C"
JNIEXPORT jstring

JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject jobj) {
    jclass cls = env->GetObjectClass(jobj);
    //注意第三个参数,是数组签名
    jfieldID jid = env->GetFieldID(cls, "a", "[I");
    jintArray jiarr = (jintArray) env->GetObjectField(jobj, jid);
    //指针a与数组jintArray1进行关联
    jint *a = env->GetIntArrayElements(jiarr, NULL);
    //获取数组的长度
    jsize jiasize = env->GetArrayLength(jiarr);
    for (int i = 0; i < jiasize; i++) {
        //输出类型 target
        __android_log_print(ANDROID_LOG_ERROR, "JNI_tempp", "%d", a[i]);
    }

    //释放 jintArray1与a的关联
    env->ReleaseIntArrayElements(jiarr, a, 0);
    std::string hello = "Hello 我乃张飞是也from C++";
    return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT jintArray JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_temp(JNIEnv *env, jobject instance,
                                                         jintArray jintArray1) {
    return jintArray1;
}

看下打印输出结果

02-23 16:00:26.941 2932-2932/com.example.acer.test_18_02_21 E/JNI_tempp: 0
02-23 16:00:26.945 2932-2932/com.example.acer.test_18_02_21 E/JNI_tempp: 1
02-23 16:00:26.945 2932-2932/com.example.acer.test_18_02_21 E/JNI_tempp: 2
02-23 16:00:26.949 2932-2932/com.example.acer.test_18_02_21 E/JNI_tempp: 3
02-23 16:00:26.949 2932-2932/com.example.acer.test_18_02_21 E/JNI_tempp: 4
02-23 16:00:26.949 2932-2932/com.example.acer.test_18_02_21 E/JNI_tempp: 5
02-23 16:00:26.949 2932-2932/com.example.acer.test_18_02_21 E/JNI_tempp: 6
02-23 16:00:26.949 2932-2932/com.example.acer.test_18_02_21 E/JNI_tempp: 7
02-23 16:00:26.949 2932-2932/com.example.acer.test_18_02_21 E/JNI_tempp: 8
02-23 16:00:26.949 2932-2932/com.example.acer.test_18_02_21 E/JNI_tempp: 9

2)通过GetArrayRegion复制数组
我们看下native-lib文件

#include <jni.h>
#include <string>
#include <android/log.h>

extern "C"
JNIEXPORT jstring

JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject jobj) {
    jclass cls = env->GetObjectClass(jobj);
    //注意第三个参数,是数组签名
    jfieldID jid = env->GetFieldID(cls, "a", "[I");
    jintArray jiarr = (jintArray) env->GetObjectField(jobj, jid);
    //获取数组的长度
    jsize jiasize = env->GetArrayLength(jiarr);
    //创建数组
    jint b[jiasize];
    env->GetIntArrayRegion(jiarr,0,jiasize,b);
    for (int i = 0; i < jiasize; i++) {
        //输出类型 target
        __android_log_print(ANDROID_LOG_ERROR, "JNI_tempp", "%d", b[i]);
    }
    std::string hello = "Hello 我乃张飞是也from C++";
    return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT jintArray JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_temp(JNIEnv *env, jobject instance,
                                                         jintArray jintArray1) {
    return jintArray1;
}

看下输出的结果

02-23 16:21:14.970 3539-3539/com.example.acer.test_18_02_21 E/JNI_tempp: 0
02-23 16:21:14.974 3539-3539/com.example.acer.test_18_02_21 E/JNI_tempp: 1
02-23 16:21:14.974 3539-3539/com.example.acer.test_18_02_21 E/JNI_tempp: 2
02-23 16:21:14.974 3539-3539/com.example.acer.test_18_02_21 E/JNI_tempp: 3
02-23 16:21:14.974 3539-3539/com.example.acer.test_18_02_21 E/JNI_tempp: 4
02-23 16:21:14.974 3539-3539/com.example.acer.test_18_02_21 E/JNI_tempp: 5
02-23 16:21:14.974 3539-3539/com.example.acer.test_18_02_21 E/JNI_tempp: 6
02-23 16:21:14.974 3539-3539/com.example.acer.test_18_02_21 E/JNI_tempp: 7
02-23 16:21:14.974 3539-3539/com.example.acer.test_18_02_21 E/JNI_tempp: 8
02-23 16:21:14.974 3539-3539/com.example.acer.test_18_02_21 E/JNI_tempp: 9

我们总结下为作为参数传入的步骤:
获取类
获取属性ID
通过通过GetObjectField方法获取数组(强转至jarray)
通过GetArrayElements接收数组指针
或者通过GetArrayRegion复制数组
二:C/C++访问java对象数组
1,作为参数传入
我们新建一个Son类

package com.example.acer.test_18_02_21;

/**
 * Created by acer on 2018/2/22.
 */

public class Son  {

    public Son(){
    }


    public void drive() {
        System.out.println("我正在学开车");

    }
}

看下ManiActivity类

package com.example.acer.test_18_02_21;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    Son[] son=new Son[3];

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        son[0]=new Son();
        son[1]=new Son();
        son[2]=new Son();
        callson(son);
        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());

    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
    public  native void callson(Son[] son);
}

看下native-lib文件

#include <jni.h>
#include <string>
#include <android/log.h>

extern "C"
JNIEXPORT jstring

JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject jobj) {
//    jclass cls = env->GetObjectClass(jobj);
//    //注意第三个参数,是数组签名
//    jfieldID jid = env->GetFieldID(cls, "a", "[I");
//    jintArray jiarr = (jintArray) env->GetObjectField(jobj, jid);
//    //获取数组的长度
//    jsize jiasize = env->GetArrayLength(jiarr);
//    //创建数组
//    jint b[jiasize];
//    env->GetIntArrayRegion(jiarr,0,jiasize,b);
//    for (int i = 0; i < jiasize; i++) {
//        //输出类型 target
//        __android_log_print(ANDROID_LOG_ERROR, "JNI_tempp", "%d", b[i]);
//    }
    std::string hello = "Hello 我乃张飞是也from C++";
    return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT void JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_callson(JNIEnv *env, jobject instance,
                                                    jobjectArray son) {
    // TODO
    //0表示第一个元素
    jobject  son1=env->GetObjectArrayElement(son ,0);
    jclass son_class = env->GetObjectClass(son1);
    jmethodID sonid = env->GetMethodID(son_class, "drive", "()V");
    //拿到对象后执行对象的方法
    env->CallVoidMethod(son1, sonid);
}

看下打印输出结果

02-23 17:02:39.490 4665-4665/? I/System.out: 我正在学开车

2,不作为 参数传入
Son类

package com.example.acer.test_18_02_21;

/**
 * Created by acer on 2018/2/22.
 */

public class Son  {

    public Son(){
    }


    public void drive() {
        System.out.println("我正在学开车");

    }
}

MainActivity类

package com.example.acer.test_18_02_21;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    Son[] son=new Son[3];

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        son[0]=new Son();
        son[1]=new Son();
        son[2]=new Son();
        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());

    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}

native-lib文件

#include <jni.h>
#include <string>
#include <android/log.h>

extern "C"
JNIEXPORT jstring

JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject jobj) {
    jclass cls = env->GetObjectClass(jobj);
    //数组的签名:[
    jfieldID jsonid = env->GetFieldID(cls,"son","[Lcom/example/acer/test_18_02_21/Son;");
    jobjectArray son = (jobjectArray) env->GetObjectField(jobj, jsonid);
    jobject son1=env->GetObjectArrayElement(son, 0);
    jclass son_class = env->GetObjectClass(son1);
    jmethodID jmid = env->GetMethodID(son_class, "drive", "()V");
    env->CallVoidMethod(son1, jmid);
    std::string hello = "Hello 我乃马超是也from C++";
    return env->NewStringUTF(hello.c_str());
}

运行结果

02-23 19:14:40.759 6675-6675/? I/System.out: 我正在学开车

PS数组操作函数总结


jsize GetArrayLength(JNIEnv *env, jarray array) 
返回数组元素个数(数组长度)

jobject GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index)  
返回对象数组元素中的对象

void SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value)  
将对象数组元素更改为新对象
//注意,以下两个方法成对出现
<type>* Get<type>ArrayElements(JNIEnv *env, jarray array, jboolean *isCopy)
获取基本类型数组中首元素的指针,isCopy不为NULL时,如果要复制数组就设置为JNI_TURE,不复制时设置为JNI_FALSE
//和上一个方法成对出现
void Release<type>ArrayElements(JNIEnv *env, jarray array, <type> elems[], jint mode)
通知虚拟机通过Get<type>ArrayElements拿到的指针不再需要了,进行释放缓冲区,mode为0(更新数组后释放),JNI_COMMIT(更新后不释放),JNI_ABORT(不更新就释放)

void Get<type>ArrayRegion(JNIEnv *env, jarray array, jint start, jint length, <type> elems[])  
复制java的基本类型数组到C/C++中

void Set <type>ArrayRegion(JNIEnv *env, jarray array, jint start, jint length, <type> elems[])
复制C/C++中的基本类型数组到java中

jobjectArray NewObjectArray(JNIEnv *env, jsize length,jclass elementClass, jobject initialElement);
新建一个对象数组,最后一个参数为元素初始化的对象

j<Type>Array New <Type> Array(JNIEnv *env, jsize length);
新建一个基本类型的数组

二JNI引用
1-局部引用
jobject NewLocalRef(JNIEnv *env, jobject ref);
新建一个局部引用
局部引用还包括各种JNI的接口创建(findclass,newobject,getobjectclass,newarray等)
局部引用在native方法调用的持续时间内有效。在native方法返回后,它们会自动释放。每个局部引用都需要一部分Java虚拟机资源。程序员需要确保native方法不会过分分配局部引用。虽然局部引用在native方法返回到Java之后会自动释放,但局部引用的过多分配可能会导致在执行native方法期间虚拟机内存就不足了。
void DeleteLocalRef(JNIEnv *env, jobject localRef);
用此方法可以主动释放局部引用的内存部分
2-全局引用
jobject NewGlobalRef(JNIEnv *env, jobject obj);
创建一个全局引用的对象
void DeleteGlobalRef(JNIEnv *env, jobject globalRef);
释放一个全局引用
3-局部引用和全局引用的主要区别
局部引用不可以C/C++的线程之间传递,函数之间也不能,会阻止GC回收对象
全局引用可以在C/C++的多个线程之间传递,如果不去手动释放,将会一直存在于内存之中,也会阻止GC去回收对象
4-引用使用中的辅助方法
jint EnsureLocalCapacity(JNIEnv *env, jint capacity);判断
在进入本地方法之前,VM自动确保至少可以创建16个本地引用。成功返回0; 否则返回一个负数并抛出一个 OutOfMemoryError。
为了向后兼容,VM会分配超出保证容量的局部引用。(作为调试支持,VM可能会向用户发出警告:局部引用太多,在JDK中,程序员可以提供 -verbose:jni命令行选项来打开这些消息。)如果没有更多的本地引用可以创建造超出保证的能力就会返回FatalError。
5-弱全局引用
一种运行期间可以被内存回收的全局引用
jweak NewWeakGlobalRef(JNIEnv *env, jobject obj);
创建一个弱全局引用

void DeleteWeakGlobalRef(JNIEnv *env, jweak obj);
释放弱全局引用

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值