Android - 编写强引用Java对象


JAVA有个垃圾回收机制,没有引用的对象会被虚拟机在整理内存时进行回收,所以使用弱引用java对象时,而实际调用为持久对象时将会出现问题。并且这个问题有时会随机出现,这个会内存整理回收时机有关。

下面,说下对于在JNI中使用JAVA中对象代码编写方法:

JAVA类方法编写:

  1. public class TestModule{  
  2.     static native boolean native_init(WeakReference<TestModule> wo);  
  3.       
  4.     /* 构造函数中传递JAVA弱应用对象给JNI层 */  
  5.     public TestModule() {  
  6.         native_init(new WeakReference<TestModule>(this));  
  7.     }  
  8.   
  9.     ...  
  10.       
  11.     /* 提供给JNI调用的JAVA方法 */  
  12.     static String native_callback(Object wo, int i, String json) {  
  13.         try {  
  14.             WeakReference<CDCAModule> r = (WeakReference<TestModule>) wo;  
  15.             CDCAModule m = r.get();  
  16.             if (m != null)  
  17.                 return m.callback.callback(i, json);  
  18.         } catch (Throwable e) {  
  19.             e.printStackTrace();  
  20.         }  
  21.         return null;  
  22.     }  
  23. }  

JNI 编写方法:

  1. static jobject   g_java_peer = NULL;  
  2. static jmethodID g_callback = NULL;  
  3.   
  4. /* 对应JAVA层native_init函数 */  
  5. JNIEXPORT jboolean JNICALL Java_com_test_TestModule_native_init(JNIEnv *e,  
  6.         jclass clazz, jobject wo) {  
  7.     if (wo == NULL)  
  8.         throw_runtime_exception(e, "");  
  9.           
  10.     /** 
  11.      * 如果这个JAVA对象,垃圾回收时不予释放掉,使用弱引用转换成强引用对象,如此 
  12.      *  则仅用户进行主动释放时此对象才无效 
  13.      */  
  14.     if (g_java_peer == NULL)  
  15.         g_java_peer = e->NewGlobalRef(wo);  
  16.   
  17.     /* 获取得到JAVA中定义的方法 */  
  18.     if ((g_callback = e->GetStaticMethodID(clazz, "native_callback",  
  19.             "Ljava/lang/Object;ILjava/lang/String")) == NULL)  
  20.         return JNI_FALSE;  
  21.     return JNI_TRUE;  
  22. }  
  23.   
  24. char*jniCallJavaTestModuleMethod(int id, const char*json, char*buf, int len) {  
  25.     JNIEnv*e = NULL;  
  26.     jstring ret = NULL;  
  27.     char *p = NULL;  
  28.     int rlen;  
  29.   
  30.     if (id < 0 || buf == NULL || len <= 0)  
  31.         return NULL;  
  32.     /* 这里注意,JNIEnv是一个线程相关的变量,所以使用javaAttachThread保证取得当前线程的Jni环境变量*/  
  33.     if ((e = javaAttachThread("test-thread")) == NULL)  
  34.         return NULL;  
  35.           
  36.     /* 调用JAVA方法 */  
  37.     if ((ret = (jstring) e->CallStaticObjectMethod((jclass)g_java_peer, g_callback,  
  38.             json ? e->NewStringUTF(json) : NULL)) == NULL)  
  39.         return NULL;  
  40.     p = buf;  
  41.     if ((rlen = e->GetStringLength(ret)) > len) {  
  42.         char*p = (char*)calloc(1,rlen);  
  43.         if (p == NULL)  
  44.             return NULL;  
  45.     }  
  46.     e->GetStringUTFRegion(ret, 0, rlen, p);  
  47.     return p;  
  48. }

在JNI中提供三种类型的引用:

1、Local Reference 本地引用,函数调用时传入jobject或者jni函数创建的jobejct,其特点就是一旦JNI层函数返回,jobject就被垃圾回收掉,所以需要注意其生命周期。可以强制调用DeleteLocalRef进行立即回收。

jstring pathStr = env->NewStringUTF(path)

....

env->DeleteLocalRef(pathStr);

2、Global Reference 全局引用 ,这种对象如不主动释放,它永远都不会被垃圾回收

创建: env->NewGlobalRef(obj);

释放: env->DeleteGlobalRef(obj)

3、Weak Global Reference 弱全局引用,一种特殊的 Global Reference ,在运行过程中可能被垃圾回收掉,所以使用时请务必注意其生命周期及随时可能被垃圾回收掉,比如内存不足时。

使用前可以利用JNIEnv的 IsSameObject 进行判定它是否被回收

env->IsSameObject(obj1,obj2);

更多Android相关信息见Android 专题页面 http://www.bkjia.com/topicnews.aspx?tid=11

相关内容