王学岗NDK系列(四):JNI操作object+JNI操作string+JNI异常操作

一:jni中的Object操作
1,jobject AllocObject(JNIEnv *env, jclass clazz);
分配一个java对象,但是不调用构造函数,返回对象的引用若无法构造对象的时候返回NULL
我们创建一个Test类

package com.example.acer.test_18_02_21;

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

public class Test {
    public Test() {
 System.out.println("Test类的构造函数");
    }
    public void temp(){
        System.out.println("来自Test类的消息,我被调用了");
    }
}

在看下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 {
    Test test = new Test();

    // 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());
        testObject(test);
    }

    /**
     * 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 testObject(Test test);
}

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 void JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_testObject(JNIEnv *env, jobject instance,
                                                               jobject test) {
  jclass  cls = env->GetObjectClass(instance);

  /**
   * 分配一个Java对象:首先,拿到所分配对象的类;
   */
    //全包名:com.example.acer.test_18_02_21
    jclass testclass=env->FindClass("com/example/acer/test_18_02_21/Test");

    jmethodID  jmid=env->GetMethodID(testclass,"temp","()V");
    //分配一个对象
    jobject testAlloc=env->AllocObject(testclass);
    env->CallVoidMethod(testAlloc,jmid);
}

看下打印输出;

02-25 12:55:26.148 5874-5874/? I/System.out: Test类的构造函数
02-25 12:55:26.256 5874-5874/? I/System.out: 来自Test类的消息,我被调用了

说明Test类中temp()被调用了
2,jobject NewObject(JNIEnv *env, jclass clazz,jmethodID methodID, …);
创建一个新java对象,方法id为要调用的构造函数的id
构造函数的方法名为固定写法“”
MainActivity类与Test类不变,我们看下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 void JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_testObject(JNIEnv *env, jobject instance,
                                                               jobject test) {
  jclass  cls = env->GetObjectClass(instance);
    jclass testclass=env->FindClass("com/example/acer/test_18_02_21/Test");
    //test_init指的是构造方法,注意<init>,构造方法的固定写法
    jmethodID test_init=env->GetMethodID(testclass,"<init>","()V");
    jobject  test_new=env->NewObject(testclass,test_init);
    jmethodID  jmid=env->GetMethodID(testclass,"temp","()V");
    //调用Test类的temp方法
    env->CallVoidMethod(test_new,jmid);
}

看下运行结果

02-25 13:17:40.447 6434-6434/com.example.acer.test_18_02_21 I/System.out: Test类的构造函数
02-25 13:17:40.551 6434-6434/com.example.acer.test_18_02_21 I/System.out: Test类的构造函数
02-25 13:17:40.551 6434-6434/com.example.acer.test_18_02_21 I/System.out: 来自Test类的消息,我被调用了

3,jobjectRefType GetObjectRefType(JNIEnv* env, jobject obj);
返回obj参数对象的引用的类型,obj可以是任意方式的引用
JNIInvalidRefType = 0, //obj参数不是一个有效的引用
JNILocalRefType = 1, //obj参数是一个局部引用
JNIGlobalRefType = 2, //obj参数是一个全局引用
JNIWeakGlobalRefType = 3 //obj参数是一个弱全局引用
我们看下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 void JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_testObject(JNIEnv *env, jobject instance,
                                                               jobject test) {

    jclass testclass = env->FindClass("com/example/acer/test_18_02_21/Test");
    jmethodID test_init = env->GetMethodID(testclass, "<init>", "()V");
    jobject test_new = env->NewObject(testclass, test_init);


    jmethodID  jmid=env->GetMethodID(testclass,"temp","()V");
    //分配一个对象
    jobject testAlloc=env->AllocObject(testclass);

    jobjectRefType allocType=env->GetObjectRefType(testAlloc);
    jobjectRefType newType=env->GetObjectRefType(test_new);
    __android_log_print(ANDROID_LOG_ERROR,"JNI_tempp","%d   %d",allocType,newType);
}

看下打印输出

02-25 14:28:28.902 7367-7367/? E/JNI_tempp: 1   1

两个都是1,所以这两个引用都是局部引用
注意:调用env->DeleteLocalRef();方法后,不能在调用GetObjectRefType();

4,jboolean IsInstanceOf(JNIEnv *env, jobject obj,jclass clazz);
检查obj是否可以强转成clazz的对象,如果是返回JNI_TURE,否则返回JNI_FALSE,NULL对象可以转换成任何类
我们看下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 void JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_testObject(JNIEnv *env, jobject instance,
                                                            jobject test) {
    jclass  cls = env->GetObjectClass(instance);
    jclass testclass = env->FindClass("com/example/acer/test_18_02_21/Test");
    jmethodID test_init = env->GetMethodID(testclass, "<init>", "()V");
    jobject test_new = env->NewObject(testclass, test_init);
    jobject testAlloc=env->AllocObject(testclass);

    jboolean objiscls1=env->IsInstanceOf(testAlloc,testclass);
    jboolean objiscls2=env->IsInstanceOf(test_new,testclass);
    jboolean objiscls3=env->IsInstanceOf(testAlloc,cls);
    jboolean objiscls4=env->IsInstanceOf(test,cls);
    __android_log_print(ANDROID_LOG_ERROR,"JNI_tempp","%d   %d  %d   %d",objiscls1,objiscls2,objiscls3,objiscls4);
}

看下结果

02-25 15:18:37.840 8544-8544/? E/JNI_tempp: 1   1  0   0

1位真,0为假
5,jboolean IsSameObject(JNIEnv *env, jobject ref1,jobject ref2);
检查两个引用是否引用相同的Java对象。
ref1和ref2引用相同对象或者都是NULL的时候返回JNI_TURE,否则返回JNI_FALSE
我们看下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 我乃a马超是也from C++";
    return env->NewStringUTF(hello.c_str());
}

extern "C"
JNIEXPORT void JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_testObject(JNIEnv *env, jobject instance,
                                                            jobject test) {
    jclass  cls = env->GetObjectClass(instance);
    jfieldID jtestid = env->GetFieldID(cls,"test","Lcom/example/acer/test_18_02_21/Test;");
    jobject  test_from_java=env->GetObjectField(instance, jtestid);
    jboolean  jtestisSame1=env->IsSameObject(test,test_from_java);

    __android_log_print(ANDROID_LOG_ERROR,"JNI_temp","%d",jtestisSame1);

}

看下打印结果

02-25 16:14:21.034 10056-10056/com.example.acer.test_18_02_21 E/JNI_temp: 1

1表示同一个对象;说明同过参数传入的和通过属性Id获取的是同一个对象
二:JNI中string操作
1,jstring NewString(JNIEnv *env, const jchar *unicodeChars,jsize len);
创建一个string对象,来源为Unicode字符数组
看下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 {
    String str="你好,我来自Activity";

    // 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(str));
    }

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

}

看下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,jstrig str) {
    jchar char1[] = {'1','2','3','4','r','6','7','8','9','0'};
    //10输出几位
    jstring  jstring_unicode=env->NewString(char1, 10);
//    __android_log_print(ANDROID_LOG_ERROR,"JNI_temp","%s",jstring_unicode);

    std::string hello = "Hello 我乃马超是也from C++";
    return jstring_unicode;
}

运行结果屏幕显示为:1234r67890
2,jstring NewStringUTF(JNIEnv *env, const char *bytes);
以UTF-8编码的字符数组构造一个新string对象

#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,jstring str) {
    const char *char1 = "好样的qqq123";
    jstring jstring_utf=env->NewStringUTF(char1);

    std::string hello = "Hello 我乃马超是也from C++";
    return jstring_utf;
}

这里写图片描述
3,jsize GetStringLength(JNIEnv *env, jstring string);
返回字符串的长度
我们看先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,jstring str) {
    const char *char1 = "好样的qqq123";
    jstring jstring_utf=env->NewStringUTF(char1);

    std::string hello = "Hello 我乃马超是也from C++";

    jsize  strlen=env->GetStringLength(str);
    __android_log_print(ANDROID_LOG_ERROR,"JNI_temp","%d",strlen);
    return jstring_utf;
}

看下打印输出

02-25 17:11:42.870 11682-11682/? E/JNI_temp: 14

4,const jchar * GetStringChars(JNIEnv *env, jstring string,jboolean *isCopy);
返回指向字符串Unicode字符数组的指针,直到releasestringchars被调用之前这个指针都是有效的
void ReleaseStringChars(JNIEnv *env, jstring string,const jchar *chars);
释放访问chars的指针,这个指针是getstringchars获得的string的指针
注意这两个函数是成对出现的
看下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,jstring str) {
    const char *char1 = "好样的qqq123";
    jstring jstring_utf=env->NewStringUTF(char1);
    jsize  strlen=env->GetStringLength(str);
    jboolean  iscopy;
    //将jchar1与str绑定
    const jchar* jchar1=env->GetStringChars(str,&iscopy);
    //在这里可以对jchar1进行操作
    jchar1[5];
    //释放关联
    env->ReleaseStringChars(str,jchar1);

    __android_log_print(ANDROID_LOG_ERROR,"JNI_temp","%d",strlen);
    return jstring_utf;
}

5其它的字符数组操作
jsize GetStringUTFLength(JNIEnv *env, jstring string);
返回UTF-8表示形式的字符串的字节长度

const char * GetStringUTFChars(JNIEnv *env, jstring string,jboolean *isCopy);
获取指向UTF-8编码的字符串的指针,这个指针在被ReleaseStringUTFChars释放前都是有效的

void ReleaseStringUTFChars(JNIEnv *env, jstring string,const char *utf);
释放GetStringUTFChars获取到的指针

void GetStringRegion(JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf);
复制str中从start到len的字符以Unicode编码赋给给字符数组buf

void GetStringUTFRegion(JNIEnv *env, jstring str, jsize start, jsize len, char *buf);
将str中从start到len的Unicode编码的部分改成UTF-8编码并赋给buf

const jchar * GetStringCritical(JNIEnv *env, jstring string, jboolean *isCopy);
void ReleaseStringCritical(JNIEnv *env, jstring string, const jchar *carray);
这两个方法类似于Get/ReleaseStringChars,允许的状况下vm会返回一个string指针,否则创建一份副本。但是在这两个方法之间的代码中native代码不得发出任何的JNI引用,否则会导致当前线程阻塞。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值