20120711我的JNI编程小结

这段时间很忙,一直没有机会来记录和总结一下。

在dmr这端,需要的本地方法有nativesetup,来通知java层建立环境。主要代码在dmrJNI.cpp中实现。

c++层,则使用notify()函数将事件通知给java层。这里用到了回调函数。

dmrJNI.cpp文件中的全局变量:

NPT_SET_LOCAL_LOGGER("platinum.media.renderer")

static PLT_UPnP upnp;
static PLT_DeviceHostReference device;

static bool upnprun = false;
static bool deviceAdded = false;
static NPT_String rendererName;
static NPT_String uuid;

// 设置全局对象,规定在一个apk里只能有一个renderer。否则就会引起混乱
static jobject player = NULL;
static JavaVM*   gJavaVM = NULL;

static jclass clazz = NULL;
static jmethodID postEventMethodID = NULL;
extern  DataBuffer g_DataBuf;

本地方法:

extern "C" {
	JNIEXPORT void JNICALL Java_com_hoperun_renderer_PlayerDNRControl_nativesetup(JNIEnv *env, jobject obj, jobject param);
    JNIEXPORT jint JNICALL Java_com_hoperun_renderer_PlayerDNRControl_deviceStart(JNIEnv *env, jobject obj,jstring name);
    JNIEXPORT jint JNICALL Java_com_hoperun_renderer_PlayerDNRControl_modifyName(JNIEnv *env, jobject obj,jstring newName);
    JNIEXPORT jint JNICALL Java_com_hoperun_renderer_PlayerDNRControl_deviceStop(JNIEnv *env, jobject obj); 
	JNIEXPORT jstring JNICALL Java_com_hoperun_renderer_PlayerDNRControl_getDeviceName(JNIEnv *env, jobject obj);
	JNIEXPORT jstring JNICALL Java_com_hoperun_renderer_PlayerDNRControl_getDeviceUUID(JNIEnv *env, jobject obj);
	JNIEXPORT void JNICALL Java_com_hoperun_renderer_PlayerDNRControl_writeData(JNIEnv *env, jobject obj, jint position, jint duration);
};

关键函数实现:

// 其实这个函数主要就是为了保存对象(媒体播放器实例),留其他地方调用
JNIEXPORT  void JNICALL Java_com_hoperun_renderer_PlayerDNRControl_nativesetup(JNIEnv *env, jobject obj, jobject param)
{
	NPT_LogManager::GetDefault().Configure("plist:.level=INFO;.handlers=ConsoleHandler;.ConsoleHandler.colors=off;.ConsoleHandler.filter=42");
	NPT_LOG_INFO("baojinyu .-----nativesetup-----1");	
	
	//获取全局引用对象,这里不能用player=param
	player = env->NewGlobalRef(param);
		
	//JavaVM只有一个,在这里获取并保存。由于可能有以外发生,添加了第二次获取的代码。
	env->GetJavaVM(&gJavaVM);
	if (env->ExceptionOccurred())
	{
		NPT_LOG_INFO("baojinyu .-----nativesetup-2----GetJavaVM fail.");
		return;
	}
	if(gJavaVM == NULL)
	{
		NPT_LOG_INFO("baojinyu .------gJavaVM == NULL, assignment value again.");
		env->GetJavaVM(&gJavaVM);
		if (env->ExceptionOccurred())
		{
			NPT_LOG_INFO("baojinyu .-----nativesetup-2----GetJavaVM fail.");
			return;
		}
	}
	NPT_LOG_INFO("baojinyu .-----nativesetup-3----GetJavaVM success.");
		
    //clazzID,cannot get it through "FindClass",会提示找不到这个类。这是觉得比较奇怪的地方。
    clazz = env->GetObjectClass(param);    
    if (env->ExceptionOccurred())
	{
		NPT_LOG_INFO("baojinyu .-----nativesetup-3----GetObjectClass fail.");
		return;
	}
    NPT_LOG_INFO("baojinyu .-----nativesetup-3----GetObjectClass success.");	
    
    //MethodID。通过clazzID获取方法ID,参数依次为:类名,方法名,方法的参数和返回值。
    postEventMethodID = env->GetStaticMethodID(clazz, "postEvent", "(Ljava/lang/Object;ILjava/lang/String;Ljava/lang/String;)V");
																		
    if (env->ExceptionOccurred())
	{
		NPT_LOG_INFO("baojinyu .-----nativesetup-4----GetStaticMethodID fail.");
		return;
	}
    NPT_LOG_INFO("baojinyu .-----nativesetup-4----GetStaticMethodID..success=====>nativesetup success!");   
   
}

关键函数实现:

//该方法在需要通知上层的事件中,有多处调用。这段代码还与上层java的代码相关。如果java代码中nativesetup中传过来的param为弱引用,则程序出错,会提示
//找不到相应的类。改为直接引用之后,问题就解决了。
void notify(int listenerType,const char* arg1,const char* arg2)
{	
	//NPT_LOG_INFO("baojinyu .-----notify-1");
	if(player == NULL) 
	{
		NPT_LOG_INFO("baojinyu-----player==NULL! notify fail.\n ");
		return;
	}

	//Get myEnv。JavaVM全局是惟一的,JNIEnv则是每个线程都有一个,因此它只能在自己的线程中获取。
	JNIEnv*   myEnv = NULL;
	//NPT_LOG_INFO("baojinyu .-----notify-2");
	gJavaVM->AttachCurrentThread(&myEnv,NULL);
	
	//NPT_LOG_INFO("baojinyu .-----notify-3 getenv success.");
	
    
	if(myEnv && clazz && postEventMethodID)
	{			
		//将uri转换后传给java		
		jstring jarg1 = myEnv->NewStringUTF((const char*)arg1);
		NPT_LOG_INFO_1("baojinyu notify : arg1--->\n%s|\n",(const char*)arg1);
		jstring jarg2 = myEnv->NewStringUTF((const char*)arg2);
		NPT_LOG_INFO_1("baojinyu notify: arg2--->\n%s|\n",(const char*)arg2);
		myEnv->CallStaticVoidMethod(clazz, postEventMethodID,player,listenerType,jarg1,jarg2);
		if (myEnv->ExceptionOccurred())
		{
			NPT_LOG_INFO("baojinyu .-----notify --CallStaticVoidMethod fail.");
			gJavaVM->DetachCurrentThread();
			return;
		}
	        //使用完毕,要释放。
		NPT_LOG_INFO("baojinyu .---------notify-success.");
		gJavaVM->DetachCurrentThread();
	}
}




你可能感兴趣的:(20120711我的JNI编程小结)