一: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引用,否则会导致当前线程阻塞。