Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android實現本地C代碼中創建Java對象及本地JNI對象的保存

Android實現本地C代碼中創建Java對象及本地JNI對象的保存

編輯:Android開發實例

本地C代碼中創建Java對象

創建Java域的對象就是創建Java類的實例,再調用Java類的構造方法。

以Bitmap的構建為例,Bitmap中並沒有Java對象創建的代碼及外部能訪問的構造方法,所以它的實例化必然是在JNI的c中實現的。

BitmapFactory.java中提供了得到Bitmap的方法,時序簡化為:

BitmapFactory.java ->BitmapFactory.cpp -> GraphicsJNI::createBitmap()  [graphics.cpp]


 

GraphicsJNI::createBitmap()[graphics.cpp]的實現:
 

  1. jobjectGraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, bool isMutable,  
  2.                                   jbyteArray ninepatch, intdensity)  
  3. {  
  4.     SkASSERT(bitmap != NULL);  
  5.     SkASSERT(NULL != bitmap->pixelRef());  
  6.  
  7.     jobject obj =env->AllocObject(gBitmap_class);  
  8.     if (obj) {  
  9.         env->CallVoidMethod(obj,gBitmap_constructorMethodID,  
  10.                             (jint)bitmap,isMutable, ninepatch, density);  
  11.         if (hasException(env)) {  
  12.             obj = NULL;  
  13.         }  
  14.     }  
  15.     return obj;  
  16. }  

而gBitmap_class的得到是通過:

  1. jclass c =env->FindClass("android/graphics/Bitmap");  
  2. gBitmap_class =(jclass)env->NewGlobalRef(c);  
  3. //gBitmap_constructorMethodID是Bitmap的構造方法(方法名用”<init>”)的jmethodID:  
  4. gBitmap_constructorMethodID= env->GetMethodID(gBitmap_class, "<init>",  
  5.                                            "(IZ[BI)V");  

 

總結一下,c中如何訪問Java對象的屬性:

1)        通過JNIEnv::FindClass()找到對應的jclass;

2)        通過JNIEnv::GetMethodID()找到類的構造方法的jfieldID;

3)        通過JNIEnv::AllocObject創建該類的對象;

4)        通過JNIEnv::CallVoidMethod()調用Java對象的構造方法。


 

本地JNI對象的保存

 

c域中某次被調用生成的對象,在其他函數調用時是不可見的,雖然可以設置全局變量但那不是好的解決方式,Android中通常是在Java域中定義一個int型的變量,在c域生成對象的地方,與這個Java域的變量關聯,在別的使用到的地方,在從這個變量中取值。


 

以JNICameraContext為例來說明:

JNICameraContext是android_hardware_camera.cpp中定義的類型,並會在cpp中生成對象,與Java中android.hardware.Camera的mNativeContext關聯。


在注冊native函數之前,c中就已經把Java域中的屬性的jfieldID得到了。通過下列方法


 

  1. jclass clazz = env->FindClass("android/hardware/Camera ");  
  2. jfieldID field = env->GetFieldID(clazz, " mNativeContext","I");  

 

如果執行成功,把field保存到上面圖中的fileds變量的context:jfieldID中。


 

生成cpp對象時,通過JNIEnv::SetIntField()設置為Java對象的屬性

 
  1. static void android_hardware_Camera_native_setup(JNIEnv *env, jobjectthiz,  
  2.     jobject weak_this, jintcameraId)  
  3. {  
  4.     // …  
  5.  
  6.     // We use a weak reference sothe Camera object can be garbage collected.  
  7.     // The reference is only used asa proxy for callbacks.  
  8.     sp<JNICameraContext>context = new JNICameraContext(env, weak_this, clazz, camera);  
  9.     // …  
  10.     // 該處通過context.get()得到context對象的地址,保存到了Java中的mNativeContext屬性裡  
  11.     env->SetIntField(thiz,fields.context, (int)context.get());  
  12. }  


而要使用時,又通過JNIEnv::GetIntField()獲取Java對象的屬性,並轉化為JNICameraContext類型:

  1. JNICameraContext* context =reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context));  
  2. if (context != NULL) {  
  3.     // …  
  4. }  

 

總結一下,c++中生成的對象如何保存和使用:

1)   通過JNIEnv::FindClass()找到對應的jclass;

2)   通過JNIEnv::GetFieldID()找到類中屬性的jfieldID;

3)   某個調用過程中,生成cpp對象時,通過JNIEnv::SetIntField()設置為Java對象的屬性;

4)   另外的調用過程中,通過JNIEnv::GetIntField()獲取Java對象的屬性,再轉化為真實的對象類型。


 

JNI完全詳解:http://mindprod.com/jgloss/jni.html

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved