android-jni与java参数传递(续集)

继续上一篇的问题,我们来给出解决方案!

前文地址:http://blog.csdn.net/andyhuabing/article/details/7551230

问题解决方案三:

重点解决:native函数及jmethodID与jfieldID的大多的问题


对于这点的话,我想到的方案就是利用String对象对参数进行封装,只需要在java端及jni端进行打包
和解析即可,这样子的话函数数目大大减小就只有两个函数了,下面就来看具体解决之案吧。


a、利用xml进行传输
一个典型的xml组织方式:


//-------------------xml---------------
<struct name="BBB">
    <member name="abc" type="int"> 334 </member>
    <member name="kkk" type="int[]">
        <array>444</array>
        <array>55</array>
        <array>333</array>
        <array>25</array>
    </member>
    <member name="yu" type="struct">
        <member name="jii" type="string">hi!</member>
        <member name="g44" type="string">word</member>
    </member>
    <member name="gh" type="struct[]">
        <array>
            <member name="ab" type="int">777</member>
            <member name="cd" type="string">ok</member>
        </array>
        <array>
            <member name="ab" type="int">777</member>
            <member name="cd" type="string">ok</member>
        </array>
    </member>


</struct>


这种格式在C++层利用sprintf组包,利用tinyxml进行解包即可,大概的核心代码如下:


拼包:

	char buf[MAX_BUFFER_LEN] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
	char *p = buf;
	char *q = p;
	p += strlen(buf) ;
	p += sprintf(p, "<element>\n");

	p += sprintf(p, "\t<byMessageType>%d</byMessageType>\n",byMessageType);

	p += sprintf(p, "\t<SCDCAPVODBuyInfo>\n");
	p += sprintf(p, "\t\t<m_dwProgramID>%d</m_dwProgramID>\n",pPVODBuyInfo->m_dwProgramID);
	p += sprintf(p, "\t\t<m_wTvsID>%d</m_wTvsID>\n",pPVODBuyInfo->m_wTvsID);
	p += sprintf(p, "\t\t<m_wExpiredDate>%d</m_wExpiredDate>\n",pPVODBuyInfo->m_wExpiredDate);
	p += sprintf(p, "\t\t<m_dwOriginalWatchTimes>%d</m_dwOriginalWatchTimes>\n",pPVODBuyInfo->m_dwOriginalWatchTimes);
	p += sprintf(p, "\t\t<m_dwOriginalWatchDuration>%d</m_dwOriginalWatchDuration>\n",pPVODBuyInfo->m_dwOriginalWatchDuration);
	p += sprintf(p, "\t\t<m_dwOriginalWatchTraffic>%d</m_dwOriginalWatchTraffic>\n",pPVODBuyInfo->m_dwOriginalWatchTraffic);
	p += sprintf(p, "\t\t<m_wPrice>%d</m_wPrice>\n",pPVODBuyInfo->m_wPrice);
	p += sprintf(p, "\t\t<m_wSlotID>%d</m_wSlotID>\n",pPVODBuyInfo->m_wSlotID);
	p += sprintf(p, "\t</SCDCAPVODBuyInfo>\n");

	p += sprintf(p, "</element>\n");

基本上如上所示了。。。


解包:
/**
 * 通用XML解析方式列表
 */

static int testXMLParse(const char* buf, const char* filename) {
	TiXmlDocument doc;
	TiXmlElement* rootelement = 0;
	TiXmlElement* itemelement = 0;
	TiXmlAttribute* itemAttr;
	const char *name = NULL;
	const char *value = NULL;

	if (buf != NULL) {
		doc.Parse(buf);
	} else if (filename != NULL) {
		doc.LoadFile(filename);
	}

	if (doc.Error()) {
		LOGE("Error in %s: %s\n", doc.Value(), doc.ErrorDesc());
		return -1;
	}

	rootelement = doc.FirstChildElement();

#if 1 //平面式解析通用格式
	itemelement = rootelement->FirstChildElement();
	while (itemelement != NULL) {
		name = itemelement->GetText();
		value = itemelement->Value();

		LOGV("element name = %s,value=%s \n", name, value);

		itemelement = itemelement->NextSiblingElement();
	}

#else //嵌套式解析通用格式
	while(rootelement != NULL) {
		itemelement = rootelement->FirstChildElement();

		while (itemelement != NULL) {
			name = itemelement->GetText();
			value = itemelement->Value();

			//TODO
			LOGV("element name = %s,value=%s \n",name,value);

			if(strcmp("SCDCAIPPVPrice",value) == 0) {
				TiXmlElement* itemElement = itemelement->FirstChildElement();
				while(itemElement!=NULL) {
					itemAttr = itemElement->FirstAttribute();
					while (itemAttr != NULL) {
						name = itemAttr->Name();
						value = itemAttr->Value();
						printf("price name = %s,value=%s \n",name,value);
						itemAttr = itemAttr->Next();
					}
					itemElement = itemElement->NextSiblingElement();
				}
			}

			itemAttr = itemelement->FirstAttribute();
			while (itemAttr != NULL) {
				name = itemAttr->Name();
				value = itemAttr->Value();

				//TODO
				LOGV("attribute name = %s,value=%s \n",name,value);

				itemAttr = itemAttr->Next();
			}

			itemelement = itemelement->NextSiblingElement();
		}

		rootelement = doc.NextSiblingElement();
	}
#endif

	return 0;
}


在JAVA层xml解包,常见的XML解析器分别为DOM解析器、SAX解析器和PULL解析器
根据函数调用的特性采用PULL解析器即可,这部分网上大把的代码,在此就不复述了。


b、利用json方式,这种方式更简单
我们与xml格式来个对比,你可以发现它相当的简单,成员"member":value 或 "member":"string"
结构则用"{" + xxx  + "}" 表示,数组则加 "[" + yyy + "]"


///-----------------json-------------
"{
"abc":334,
"kkk":[444,55,333,25],
"yu":{
    "jii":"hi!",
    "g44":"word"
}
"gh":[
    {"ab":777,"cd":"ok"},
    {"ab":777,"cd":"ok"}
]
}"


///------------- java示例代码---------------
import 	org.json.JSONTokener;

void aa(){
 String json = "{"
         + "  \"abc\": \"334\", "
         + "  \"kkk\": [ 444,55,333,25 ], "
	 + "  \"tom\": { \"a\": \"xxx\", \"b\": 100 ,\"c\": [33,44]} "
         + "}";

 JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
 String query = object.getString("query");
 JSONArray locations = object.getJSONArray("locations");
 int iv = object.getJSONObject("tom").getInt("b");
 String sv= object.getJSONObject("tom").getString("a");
 int iv1 = object.getJSONObject("tom").getJSONArray.("c").getInt(1);
}

///------------- C++示例代码---------------
下载了json的开源代码,然后对其接口进行了封装非常好用..


struct mmm_t {
	int a;
	int b[4];
	struct {
		int c1, c2;
	} c;
	struct {
		int d1;
		char*d2;
	} d[2];
	float e;
};

/* 对成员一级级的进行取值,比如取c1值,先取得c结构,然后再取c1和c2 */
int get_struct_mmm1(json_t*p, struct mmm_t*m) {
	int i;
	json_t*pa = NULL, *po = NULL;
	p = mjson_child(p);
	m->a = mjson_get_number(p);
	pa = mjson_get_array((p = mjson_next(p)));
	for (i = 0; i < 4; ++i) {
		m->b[i] = mjson_get_array_number(pa);
		pa = mjson_next(pa);
	}
	po = mjson_get_object((p = mjson_next(p)));
	m->c.c1 = mjson_get_number(po);
	m->c.c2 = mjson_get_number((po = mjson_next(po)));
	pa = mjson_get_array((p = mjson_next(p)));
	for (i = 0; i < 2; ++i) {
		po = mjson_get_array_object(pa);
		m->d[i].d1 = mjson_get_number(po);
		m->d[i].d2 = mjson_get_string((po = mjson_next(po)));
		pa = mjson_next(pa);
	}
	m->e = mjson_get_float((p = mjson_next(p)));
	return 0;
}

/* 对成员直接进取取值,比如取c1,直接使用m.c.c1,取数组m.b[2] */
int get_struct_mmm(json_t*p, struct mmm_t*m) {
	int i;
	char buf[128];
	m->a = mjson_locate_number(p, "a");
	for (i = 0; i < 4; ++i) {
		sprintf(buf, "b[%d]", i);
		m->b[i] = mjson_locate_number(p, buf);
	}
	m->c.c1 = mjson_locate_number(p, "c.c1");
	m->c.c2 = mjson_locate_number(p, "c.c2");
	for (i = 0; i < 2; ++i) {
		sprintf(buf, "d[%d].d1", i);
		m->d[i].d1 = mjson_locate_number(p, buf);
		sprintf(buf, "d[%d].d2", i);
		m->d[i].d2 = mjson_locate_string(p, buf);
	}
	m->e = mjson_locate_float(p, "e");
	return 0;
}


因此最终的解决方案就是:


只需要定义一个native函数:



private static native String native_call_camodule_methods(String name,String value);
使用json格式传递返回值及函数参数,输入值value传入,输出值通过返回值返回


C++调用JAVA函数,也只使用一个函数
public String CAModuleCallStaticObjectMethod(String Function,String value);


具体的json封包及解析放到单独两个文件中,其余的代码全部可以通用,适合多CA移植功能的apk编写。



你可能感兴趣的:(java,json,xml,String,struct,null)