2.1 解决“浏览器卡顿”
解决办法是,改为异步加载。这样浏览器可以继续工作,下载完成后会触发回调函数。
xml_loadFile函数支持异步加载,只需将第2个参数设为回调函数就行了。我们还可以利用闭包函数,来简化回调函数的编写。
“加载并做xsl转换”这个操作比较固定,我们可以写一个函数来封装它(doload)。同时还可以作一些界面改进,比如我为它加了点线边框、加载状态提示、展开/折叠等功能——
// 显示或隐藏控件
function setShow(ctl, isShow, _display)
{
if (null==ctl) return;
ctl.style.display = isShow?(_display||"inline"):"none";
ctl.style.visibility = isShow?"visible":"hidden";
}
// 展开/折叠 显示
function click_show(ctl)
{
var s = ctl.value;
var isShow = ("+"==s);
ctl.value = isShow?"-":"+";
var divdoc = ctl.parentNode.lastChild;
setShow(divdoc, isShow);
}
// 显示xml
function showxml(xsl, divdoc, xmlDoc)
{
if (null==divdoc) return;
if (null==xmlDoc)
{
divdoc.innerHTML = "error!";
return;
}
// == main ==
divdoc.innerHTML = xml_transformNode(xmlDoc, xsl);
}
// 加载xml
function doload(xsl, url, desc)
{
// 创建边框div
var divrect = document.createElement("div");
divrect.className = "div_border";
divrect.title = url;
divrect.innerHTML = "<input type='button' value='-' οnclick='click_show(this)'>" +
" " + url + "<br />" +
((""!=desc)?("<b>desc</b>: " + desc + "<br />"):"")+
"<div name='divdoc'>loading...</div>";
// add
var divShow = getRef("divShow");
divShow.appendChild(divrect);
divShow.appendChild(document.createElement("br")); // 空一行
// 加载xml
xml_loadFile(url, function(xmlDoc, isError){
// 用xsl转换xml
var divdoc = divrect.lastChild;
showxml(xsl, divdoc, isError?null:xmlDoc);
});
}
doload函数完工后,我们来修改init函数。原来是这样处理的——
var xmlDoc = xml_loadFile("https://dl-ssl.google.com/android/repository/repository-5.xml");
var divShow = getRef("divShow");
divShow.innerHTML = xml_transformNode(xmlDoc, xslRepository);
现在改为调用doload函数——
doload(xslRepository, "https://dl-ssl.google.com/android/repository/repository-5.xml", "main");
2.2 解决“没有附加SDK”
现在需要找到附加SDK信息存放在哪里。再次打开SDK Manager的“log”窗口——
[url2.png]
“https://dl-ssl.google.com/android/repository/addons_list-1.xml”是什么呢?打开看看——
<?xml version="1.0" encoding="UTF-8"?>
<sdk:sdk-addons-list
xmlns:sdk="http://schemas.android.com/sdk/android/addons-list/1">
<sdk:addon-site>
<sdk:url>https://dl-ssl.google.com/android/repository/addon.xml</sdk:url>
<sdk:name>Google Inc.</sdk:name>
</sdk:addon-site>
<sdk:addon-site>
<sdk:url>http://www.echobykyocera.com/download/echo_repository.xml</sdk:url>
<sdk:name>KYOCERA Corporation</sdk:name>
</sdk:addon-site>
<sdk:addon-site>
<sdk:url>http://developer.lgmobile.com/sdk/android/repository.xml</sdk:url>
<sdk:name>LG Electronics</sdk:name>
</sdk:addon-site>
<sdk:addon-site>
<sdk:url>http://innovator.samsungmobile.com/android/repository/repository.xml</sdk:url>
<sdk:name>Samsung Electronics</sdk:name>
</sdk:addon-site>
<sdk:addon-site>
<sdk:url>http://developer.sonyericsson.com/edk/android/repository.xml</sdk:url>
<sdk:name>Sony Ericsson</sdk:name>
</sdk:addon-site>
</sdk:sdk-addons-list>
将SDK Manager的“log”窗口向下滚,也发现了类似信息——
[url3.png]
这是一个两级关系:addons_list-1.xml是存放了“各个厂商信息”的一个列表,从中可以找到厂商的xml文件地址。然后厂商的xml文件存放了SDK文件的地址。
观察厂商的xml文件,发现它使用了不同的名称空间,所以得再建立一个xsl转换文件(addon.xsl)。其实标签名很接近的,编写addon.xsl并不困难。
xsl转换不能处理这样的2级关系,得编写JavaScript处理addons_list-1.xml,再对列表中的xml文件做xsl转换。
处理addons_list-1.xml也应该设计为异步加载。但由于其代码比较复杂,闭包函数不太适合,最好专门写一个回调函数——
// 处理附加SDK列表
function onload_addons(xmlDoc, isError)
{
// UI
var divAddons = getRef("divAddons");
if (isError)
{
divAddons.innerHTML = "addons_list-1.xml: error!"
return;
}
setShow(divAddons, false); // 加载成功,隐藏本div
// Parse
var nodes=xmlDoc.documentElement.childNodes;
for(var i=0; i<nodes.length; i++)
{
var nod = nodes[i];
if ("sdk:addon-site"==nod.nodeName)
{
var sUrl = xml_text(nod.selectSingleNode("sdk:url"));
var sName = xml_text(nod.selectSingleNode("sdk:name"));
// load
doload(xslAddon, sUrl, sName);
}
}
}
然后在init函数中添加一行,异步加载addons_list-1.xml——
xml_loadFile("https://dl-ssl.google.com/android/repository/addons_list-1.xml", onload_addons);
2.3 全部代码
全部代码为——
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Anroid SDK URL 2</title>
<style type="text/css">
.div_border
{
border:red dotted thin;
padding: 2px;
}
</style>
<script type="text/javascript" src="zyllibjs_xml.js"></script>
<script type="text/javascript">
var xslRepository =null;
var xslAddon =null;
// 取得命名对象
function getRef(id)
{
if (document.getElementById) return document.getElementById(id); // DOM
if (document.all) return document.all[id]; // IE4
if (document.layers) return document.layers[id]; // Netscape4
returnnull;
}
// 显示或隐藏控件
function setShow(ctl, isShow, _display)
{
if (null==ctl) return;
ctl.style.display = isShow?(_display||"inline"):"none";
ctl.style.visibility = isShow?"visible":"hidden";
}
// 展开/折叠 显示
function click_show(ctl)
{
var s = ctl.value;
var isShow = ("+"==s);
ctl.value = isShow?"-":"+";
var divdoc = ctl.parentNode.lastChild;
setShow(divdoc, isShow);
}
// 显示xml
function showxml(xsl, divdoc, xmlDoc)
{
if (null==divdoc) return;
if (null==xmlDoc)
{
divdoc.innerHTML ="error!";
return;
}
// == main ==
divdoc.innerHTML = xml_transformNode(xmlDoc, xsl);
}
// 加载xml
function doload(xsl, url, desc)
{
// 创建边框div
var divrect = document.createElement("div");
divrect.className ="div_border";
divrect.title = url;
divrect.innerHTML ="<input type='button' value='-' οnclick='click_show(this)'>"+
" "+ url +"<br />"+
((""!=desc)?("<b>desc</b>: "+ desc +"<br />"):"")+
"<div name='divdoc'>loading...</div>";
// add
var divShow = getRef("divShow");
divShow.appendChild(divrect);
divShow.appendChild(document.createElement("br")); // 空一行
// 加载xml
xml_loadFile(url, function(xmlDoc, isError){
// 用xsl转换xml
var divdoc = divrect.lastChild;
showxml(xsl, divdoc, isError?null:xmlDoc);
});
}
// 处理附加SDK列表
function onload_addons(xmlDoc, isError)
{
// UI
var divAddons = getRef("divAddons");
if (isError)
{
divAddons.innerHTML ="addons_list-1.xml: error!"
return;
}
setShow(divAddons, false); // 加载成功,隐藏本div
// Parse
var nodes=xmlDoc.documentElement.childNodes;
for(var i=0; i<nodes.length; i++)
{
var nod = nodes[i];
if ("sdk:addon-site"==nod.nodeName)
{
var sUrl = xml_text(nod.selectSingleNode("sdk:url"));
var sName = xml_text(nod.selectSingleNode("sdk:name"));
// load
doload(xslAddon, sUrl, sName);
}
}
}
// 初始化
function init()
{
// Load XSL
xslRepository = xml_loadFile("repository.xsl");
xslAddon = xml_loadFile("addon.xsl");
// Load main
doload(xslRepository, "https://dl-ssl.google.com/android/repository/repository-5.xml", "main");
// Load addons_list
xml_loadFile("https://dl-ssl.google.com/android/repository/addons_list-1.xml", onload_addons);
}
</script>
</head>
<body onload="init()">
<h1>Anroid SDK URL(安卓SDK地址)</h1><br />
<div id="divShow"></div>
<div id="divAddons" class="div_border">addons_list-1.xml: loading...</div>
</body>
</html>
2.4 小结
运行效果为——
[sdkurl2.png]
成功的显示了核心SDK与Google附加SDK的下载地址。而且现在有展开折叠按钮方便观看。
还有可以改进的地方吗?仔细观察后发现,现在存在2点不足——
1.其他厂商显示异常。这是因为命名空间冲突,官网上的命名空间已更新至第3版(xmlns:sdk="http://schemas.android.com/sdk/android/addon/3"),而很多厂商仍在使用第1版的命名空间。
2.绝对地址显示异常。xml中有时给出的是绝对地址,而xsl转换只能使用简单的字符串连接,造成绝对地址显示异常。
怎么办呢?请听下回分解。