Android上的C/C++调用Java问题

http://www.h3-embedded.com/thread-262-1-1.html


基本上来说,在androidC/C++调用Java,和在其他平台上调用是一致的。网上一收,一大箩筐。我在这里没什么好多说明的。这里,我想谈一下,在android上,多线程C/C++调用Java要遵守的规则。
最近,我在android上使用Curl库。网络通讯,我想没有同学会想使用singlethread去等待网络另一端,而hung住用户的操作吧。所以多线程不失为一个方法。同时,我想让user知道当前网络通讯的状态,比如下载速度,那么自然而然会想到用回调函数去update这些信息。那么问题来了,在Android上,典型的一个应用程序,首先由上层Javacode开启Thread开始一个下载,那么这个Thread就会调用JNI层中真正下载的函数,姑且叫做downloadFuncdownloadFunc使用Curltodownload,同时会注册回调函数叫做downloadProgress。那么这个回调函数就是运行在另一个线程中的。Okay,我们先来看一段:
8.1.4 Obtaining a JNIEnv Pointer in Arbitrary Contexts

WeexplainedearlierthataJNIEnvpointerisonlyvalidinitsassociatedthread.ThisisgenerallynotaproblemfornativemethodsbecausetheyreceivetheJNIEnvpointerfromthevirtualmachineasthefirstargument.Occasionally,however,itmaybenecessaryforapieceofnativecodenotcalleddirectlyfromthevirtualmachinetoobtaintheJNIEnvinterfacepointerthatbelongstothecurrentthread.Forexample,thepieceofnativecodemaybelongtoa"callback"functioncalledbytheoperatingsystem,inwhichcasetheJNIEnvpointerwillprobablynotbeavailableasanargument.

YoucanobtaintheJNIEnvpointerforthecurrentthreadbycallingtheAttachCurrentThreadfunctionoftheinvocationinterface:


JavaVM*jvm;/* already set */

f()
{
JNIEnv*env;
(*jvm)->AttachCurrentThread(jvm,(void**)&env,NULL);
.../* use env */
}
Whenthecurrentthreadisalreadyattachedtothevirtualmachine,Attach-Current-ThreadreturnstheJNIEnvinterfacepointerthatbelongstothecurrentthread.

TherearemanywaystoobtaintheJavaVMpointer:byrecordingitwhenthevirtualmachineiscreated,byqueryingforthecreatedvirtualmachinesusingJNI_GetCreatedJavaVMs,bycallingtheJNIfunctionGetJavaVMinsidearegularnativemethod,orbydefiningaJNI_OnLoadhandler.UnliketheJNIEnvpointer,theJavaVMpointerremainsvalidacrossmultiplethreadssoitcanbecachedinaglobalvariable.



//-----------------------------------------------------------------------分割线--------------------------------------------------------------------------------------
大概的用中文说明一下:通常JavacallJNI中的函数,那么这个函数的第一参数:是JNIEnv*指针;所以假如我们要使用JNIEnv*指针,那么我们直接使用就好了。但是,有些情况下,比如系统的回调函数,就不会有JNIEnv*指针作为第一个传入参数。这个时候,我们能使用(*jvm)->AttachCurrentThread(jvm,(void**)&env,NULL)来创建一个在回调函数中的JNIEnv*指针。而jvm是进程内的共享对象,所以,只要我们在JNI_OnLoad中保存jvm对象就好了。那么我们就可以跨线程使用JNIEnv *指针了。



此外,我使用curlprogresscallbackfunction的时候,出现了如下错误:
01W/dalvikvm(16890):ReferenceTableoverflow(max=512)
02W/dalvikvm(16890):Last10entriesinJNIlocalreferencetable:
03W/dalvikvm(16890): 502:0x44a9e110cls=Ljava/lang/String; (28bytes)
04W/dalvikvm(16890): 503:0x44a9e908cls=Ljava/lang/String; (28bytes)
05W/dalvikvm(16890): 504:0x44a9e908cls=Ljava/lang/String; (28bytes)
06W/dalvikvm(16890): 505:0x44a9f358cls=Ljava/lang/String; (28bytes)
07W/dalvikvm(16890): 506:0x44a9f358cls=Ljava/lang/String; (28bytes)
08W/dalvikvm(16890): 507:0x44a9fca0cls=Ljava/lang/String; (36bytes)
09W/dalvikvm(16890): 508:0x44a9fca0cls=Ljava/lang/String; (36bytes)
10W/dalvikvm(16890): 509:0x44b94180cls=Ljava/lang/String; (28bytes)
11W/dalvikvm(16890): 510:0x44b94180cls=Ljava/lang/String; (28bytes)
12W/dalvikvm(16890): 511:0x449a6768cls=Ljava/lang/String; (28bytes)
13W/dalvikvm(16890): JNIlocalreferencetablesummary(512entries):
14W/dalvikvm(16890): 1ofLjava/lang/Class;164B
15W/dalvikvm(16890): 507ofLjava/lang/String;28B (432unique)
16W/dalvikvm(16890): 3ofLjava/lang/String;36B (2unique)
17W/dalvikvm(16890): Memoryhelddirectlybytrackedrefsis12344bytes
18E/dalvikvm(16890): FailedaddingtoJNIlocalreftable(has512entries)
19I/dalvikvm(16890): "DownloadThread"prio=5tid=7RUNNABLE
20I/dalvikvm(16890): |group="main"sCount=0dsCount=0s=Nobj=0x449ff6a0
21self=0x26f4d0
22I/dalvikvm(16890): |sysTid=16898nice=0sched=0/0cgrp=default
23handle=2543832



网上一搜,发现也有老兄碰到过类似的情况。说是资源没有释放。资源?我几乎没有申请什么资源啊。只是传回去一个jstringjint。难道?JNIEnv->NewUTFString()中的资源要释放?结果我用google了一把,发现不用我们来手动去release。由JavaVM来管理。这个回调函数大概每秒调用一次,难道JavaVM没时间去释放?看起来,这个回调函数被调用的太频繁了,所以ReferenceTableoverflow。这个table好想只能容纳512slot.超过512,就不能FailedaddingtoJNIlocalreftable.想想referencetable是在heap上,我干脆只传jintJavalayer好啦。那么jint这个是在stack上的,函数一旦执行完成的时候,stack就会自动被释放。果然,修改后,就不再出现这个错误了。

更多相关文章

  1. Android系统框架和几种调用流程
  2. 详解 Android(安卓)的 Activity 组件
  3. 无废话Android之android下junit测试框架配置、保存文件到手机内
  4. Android混合开发-(Android与Web的交互)
  5. 《Android深入透析》之Android事件分发机制
  6. Android(安卓)Alarm驱动源代码分析(Alarm.c)
  7. 如何在Android中使用OpenCV
  8. 实例分析android中的Binder通信机制(1)
  9. Android(安卓)的Camera架构介绍

随机推荐

  1. 用python完成1-100的加法
  2. python多线程文件传输范例(C/S)
  3. [Python]PDF合成小程序PDF合成小程序
  4. 关于python return 和 print 的区别
  5. python基础练习--列表问题
  6. python list range 字符串的截取 如 text
  7. 如何将两个列表中的数据写入csv中的列?
  8. Python list 交集,并集,差集
  9. Python 卡方检验、克雷姆值
  10. 运用Python语言编写获取Linux基本系统信