AndroidNDK開發系列教程3:基本方法呼叫及傳參(續)
終於建了一個自己個人小站:https://huangtianyu.gitee.io,以後優先更新小站部落格,歡迎進站,O(∩_∩)O~~
上一節主要講解Java向native傳參,下面主要講解從native傳相應的資料到java層。
接著上一節,下面主要講解內容如下:
1. native向java返回字串型別
2. native向java返回java物件
3. native向java返回陣列型別
4. native向Java返回List物件
對於上面的每個都給出對應的例子。
本節所有案例程式碼均已放到GitHub上,歡迎下載:
https://github.com/huangtianyu/JNILearnCourse
1. native向java返回字串型別
傳基本資料型別很簡單,是什麼就傳什麼就行。傳字串型別也很簡單,具體jni程式碼如下:
extern "C"
JNIEXPORT jstring JNICALL
Java_zqc_com_example_NativeTest_jni2javaMethod1(JNIEnv *env, jobject instance) {
//jstring NewStringUTF(const char* bytes),jstring NewString(const jchar* unicodeChars, jsize len)
char *returnValue = "你在native做你的操作後,生成char*後,通過env->NewStringUTF即可返回Java的String型別";
return env->NewStringUTF(returnValue);
}
其中最主要用的是以下幾個方法:
//建立Unicode格式的jstring串
jstring NewString(const jchar* unicodeChars, jsize len)
{ return functions->NewString(this, unicodeChars, len); }
//獲取jstring長度
jsize GetStringLength(jstring string)
{ return functions->GetStringLength(this, string); }
//獲取jstring對應的字串,isCopy表示是否拷貝生成副本。
//這個函式返回一個指向特定jstring中字元順序的指標,該指標保持有效直到ReleaseStringChars函式被呼叫:
const jchar* GetStringChars(jstring string, jboolean* isCopy)
{ return functions->GetStringChars(this, string, isCopy); }
//釋放指標
void ReleaseStringChars(jstring string, const jchar* chars)
{ functions->ReleaseStringChars(this, string, chars); }
////建立UTF-8格式的jstring串
jstring NewStringUTF(const char* bytes)
{ return functions->NewStringUTF(this, bytes); }
//獲取utf字串的長度
jsize GetStringUTFLength(jstring string)
{ return functions->GetStringUTFLength(this, string); }
//同GetStringChars
const char* GetStringUTFChars(jstring string, jboolean* isCopy)
{ return functions->GetStringUTFChars(this, string, isCopy); }
//同ReleaseStringChars
void ReleaseStringUTFChars(jstring string, const char* utf)
{ functions->ReleaseStringUTFChars(this, string, utf); }
以上是處理字串常用的一些方法。
2 native向java返回java物件
具體看native的程式碼如下:
extern "C"
JNIEXPORT jobject JNICALL
Java_zqc_com_example_NativeTest_jni2javaMethod2(JNIEnv *env, jobject instance) {
jclass pcls = env->FindClass("zqc/com/example/Person");
jmethodID constructor = env->GetMethodID(pcls, "<init>", "()V");
jmethodID setIdMid = env->GetMethodID(pcls, "setId", "(J)V");
jmethodID setNameMid = env->GetMethodID(pcls, "setName", "(Ljava/lang/String;)V");
jmethodID setAgeMid = env->GetMethodID(pcls, "setName", "(I)V");
jobject person = env->NewObject(pcls, constructor);
env->CallVoidMethod(person, setIdMid, 100L);
env->CallVoidMethod(person, setNameMid, env->NewStringUTF("天宇"));
env->CallVoidMethod(person, setAgeMid, 18);
return person;
}
常用新建Object的方法由以下幾個:
//將傳遞給建構函式的所有引數緊跟著放在 methodID 引數的後面。NewObject() 收到這些引數後,將把它們傳給所要呼叫的Java 方法。
jobject NewObject(jclass clazz, jmethodID methodID, ...)
{
va_list args;
va_start(args, methodID);
jobject result = functions->NewObjectV(this, clazz, methodID, args);
va_end(args);
return result;
}
//將傳遞給建構函式的所有引數放在 va_list 型別的引數 args 中,該引數緊跟著放在 methodID 引數的後面。NewObject() 收到這些引數後,將把它們傳給所要呼叫的 Java 方法。
jobject NewObjectV(jclass clazz, jmethodID methodID, va_list args)
{ return functions->NewObjectV(this, clazz, methodID, args); }
//將傳遞給建構函式的所有引數放在jvalues型別的陣列args中,該陣列緊跟著放在methodID引數的後面。NewObject() 收到陣列中的這些引數後,將把它們傳給所要呼叫的 Java 方法。
jobject NewObjectA(jclass clazz, jmethodID methodID, jvalue* args)
{ return functions->NewObjectA(this, clazz, methodID, args); }
//測試物件是否為某個類的例項。
jboolean IsInstanceOf(jobject obj, jclass clazz)
{ return functions->IsInstanceOf(this, obj, clazz); }
//測試兩個引用是否引用同一 Java 物件。
jboolean IsSameObject(jobject ref1, jobject ref2)
{ return functions->IsSameObject(this, ref1, ref2); }
//分配新 Java 物件而不呼叫該物件的任何建構函式。返回該物件的引用。
//該方法會丟擲:InstantiationException:如果該類為一個介面或抽象類。OutOfMemoryError:如果系統記憶體不足。
jobject AllocObject(jclass clazz)
{ return functions->AllocObject(this, clazz); }
//判斷某個Object是否是某個class的具體例項
jboolean (*IsInstanceOf)(JNIEnv*, jobject, jclass);
3 native向java返回陣列型別
3.1 基本型別陣列
這裡直接看native層程式碼如下:
extern "C"
JNIEXPORT jintArray JNICALL
Java_zqc_com_example_NativeTest_jni2javaMethod3(JNIEnv *env, jobject instance) {
int nat[] = {2, 1, 4, 3, 5};
jintArray jnat = env->NewIntArray(5);
env->SetIntArrayRegion(jnat, 0, 5, nat);
return jnat;
}
基本資料型別陣列都有相應的env->NewXXXArray(jsize length);通過該方法可以生成對應的陣列。
jbooleanArray NewBooleanArray(jsize length)
{ return functions->NewBooleanArray(this, length); }
jbyteArray NewByteArray(jsize length)
{ return functions->NewByteArray(this, length); }
jcharArray NewCharArray(jsize length)
{ return functions->NewCharArray(this, length); }
jshortArray NewShortArray(jsize length)
{ return functions->NewShortArray(this, length); }
jintArray NewIntArray(jsize length)
{ return functions->NewIntArray(this, length); }
jlongArray NewLongArray(jsize length)
{ return functions->NewLongArray(this, length); }
jfloatArray NewFloatArray(jsize length)
{ return functions->NewFloatArray(this, length); }
jdoubleArray NewDoubleArray(jsize length)
{ return functions->NewDoubleArray(this, length); }
在生成了對應的陣列後,可以通過setXXXArrayRegion(jxxxArray array, jsize start, jsize len, const jchar* buf)來填充陣列
void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len,
const jboolean* buf)
{ functions->SetBooleanArrayRegion(this, array, start, len, buf); }
void SetByteArrayRegion(jbyteArray array, jsize start, jsize len,
const jbyte* buf)
{ functions->SetByteArrayRegion(this, array, start, len, buf); }
void SetCharArrayRegion(jcharArray array, jsize start, jsize len,
const jchar* buf)
{ functions->SetCharArrayRegion(this, array, start, len, buf); }
void SetShortArrayRegion(jshortArray array, jsize start, jsize len,
const jshort* buf)
{ functions->SetShortArrayRegion(this, array, start, len, buf); }
void SetIntArrayRegion(jintArray array, jsize start, jsize len,
const jint* buf)
{ functions->SetIntArrayRegion(this, array, start, len, buf); }
void SetLongArrayRegion(jlongArray array, jsize start, jsize len,
const jlong* buf)
{ functions->SetLongArrayRegion(this, array, start, len, buf); }
void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len,
const jfloat* buf)
{ functions->SetFloatArrayRegion(this, array, start, len, buf); }
void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len,
const jdouble* buf)
{ functions->SetDoubleArrayRegion(this, array, start, len, buf); }
3.2 物件型別陣列
直接看native程式碼:
extern "C"
JNIEXPORT jobjectArray JNICALL
Java_zqc_com_example_NativeTest_jni2javaMethod4(JNIEnv *env, jobject instance) {
jclass cls = env->FindClass("zqc/com/example/Person");
jmethodID cMid = env->GetMethodID(cls, "<init>", "()V");
jclass pcls = env->FindClass("zqc/com/example/Person");
jmethodID cmid = env->GetMethodID(pcls, "<init>", "()V");
jmethodID setNameMid = env->GetMethodID(pcls, "setName", "(Ljava/lang/String;)V");
jmethodID setAgeMid = env->GetMethodID(pcls, "setAge", "(I)V");
jobject obj = env->NewObject(pcls, cmid);
env->CallVoidMethod(obj, setNameMid, env->NewStringUTF("天宇"));
int len = 3;
jobjectArray joa = env->NewObjectArray(len, cls, obj);
for (int i = 0; i < len; ++i) {
jobject tmp = env->GetObjectArrayElement(joa,i);
env->CallVoidMethod(tmp, setAgeMid, i + 10);
}
return joa;
}
其在native生成的方法是 jobjectArray joa = env->NewObjectArray(len, cls, obj);
//第一個參數列示生成的長度,第二參數列示裡面元素的物件類,第三個表示原始初始化時的值。在生成後每個元素都是該值。
jobjectArray NewObjectArray(jsize length, jclass elementClass,
jobject initialElement)
{ return functions->NewObjectArray(this, length, elementClass,
initialElement); }
4 native向Java返回List物件
直接看native程式碼如下:
extern "C"
JNIEXPORT jobject JNICALL
Java_zqc_com_example_NativeTest_jni2javaMethod5(JNIEnv *env, jobject instance) {
jclass listCls = env->FindClass("java/util/ArrayList");//獲得ArrayList類引用
jmethodID listCon = env->GetMethodID(listCls, "<init>", "()V");//獲取建構函式的methodID
jmethodID addMid = env->GetMethodID(listCls,"add","(Ljava/lang/Object;)Z");//獲取add函式的methodID
jobject listObj = env->NewObject(listCls, listCon);//利用NewObject建立一個ArrayList物件
jobject jperon = Java_zqc_com_example_NativeTest_jni2javaMethod2(env, instance);//利用上面方法新建一個Person物件
env->CallBooleanMethod(listObj, addMid, jperon);//在listObj中add一個Person物件
//返回ArrayList的物件
return listObj;
}
對應jni而言,List,ArrayList以及Map,HashMap,Set,HashSet都只是一個Object,對應於jni而言也就都是jobject,操作jobject都可以用最開始介紹的方法。
總結
jni裡面的方法很多,多用用就熟悉了。常用的上面都有,自己之前還總結了很多常用的型別轉換函式。以後有時間再寫篇部落格分享下。不會就要查手冊:http://www.ceeger.com/Script/AndroidJNI/AndroidJNI.html
相關文章
- AndroidNDK開發系列教程6:JNI函式註冊(JNI_OnLoad)Android函式
- Js呼叫Java方法並互相傳參JSJava
- Flutter小白教程系列(五) --- 頁面路由導航及傳參Flutter路由
- Metal 系列教程(1)- Metal 介紹及基本使用
- java 方法呼叫,形參改變,實參是否發生改變Java
- JNI開發系列③C語言呼叫Java欄位與方法C語言Java
- jQuery .click()方法傳參jQuery
- Exploit開發系列教程-Heap
- Exploit開發系列教程-Windbg
- 微信開發系列教程(二)
- 硬體開發系列教程
- 關於iOS-WebService SOAP AFNetworking~> 2.6.3 XML傳參呼叫方法iOSWebXML
- 『React Navigation 3x系列教程』createMaterialTopTabNavigator開發指南ReactNavigation
- 『React Navigation 3x系列教程』createDrawerNavigator開發指南ReactNavigation
- androidndkAndroid
- vue路由傳參的三種基本方式Vue路由
- iOS開發NSURLConnection 斷點續傳iOS斷點
- 分析結果,方法傳參
- C#微信開發系列教程C#
- 『React Navigation 3x系列教程』createBottomTabNavigator開發指南ReactNavigation
- 『React Navigation 3x系列教程』之createStackNavigator開發指南ReactNavigation
- ArcGIS for iOS 開發系列(1) – 基本概念iOS
- 呼叫鏈系列四:呼叫鏈上下文傳遞
- JVM系列-方法呼叫的原理JVM
- VUE3 之 元件傳參Vue元件
- ASP.NET4.5Web API及非同步程式開發系列(3)ASP.NETWebAPI非同步
- 一文搞懂 ARM 64 系列: 一文搞懂 ARM 64 系列: 函式呼叫傳參與返回值函式
- 『React Navigation 3x系列教程』之React Navigation 3x開發指南ReactNavigation
- 微信開發常用文件及參考資料
- 微信程式開發系列教程(一)開發環境搭建開發環境
- get方式傳參的以post方法傳的解決方法
- 微信小程式開發系列教程三:微信小程式的除錯方法微信小程式除錯
- React 元件建立方法及父元件向子元件傳參(基礎)React元件
- MySQL系列:檢視基本操作(3)MySql
- python傳遞實參的方法Python
- 以太坊錢包開發系列3 - 展示錢包資訊及發起簽名交易
- Exploit開發系列教程-Mona 2& SEH
- 微信小程式開發–視訊教程系列微信小程式