下载池
由于http下载是异步事件,也就是说下载完成需要由系统调用onWIFI32事件来确定下载完成,这就导致了:
- http下载是一个单线程,无法并发
- 如果某个控件含有下载功能,比如urljpg,控件内支持下载jpg,当多个这种控件放在同一个页面中时,会启动多个下载任务,造成资源混乱,无法完成正常操作
因此我们构建了下载池,把需要下载的任务统一放在下载池中,逐一下载,将并行的任务变成整体的串行任务;详细实现如下:
实现
首先下载池我们构建在appbase这个全局控件中,主要代码如下:
//本代码在appbase控件代码中
//属性:
str dnpool=""; //下载池存储 ,这是一个strlist,一行一个下载url
/* 下载池: 存储在属性:dnpool中 是一个strlist
url|addr|size|mode //bin url
url|x|x|x| //str url
*/
//方法:
int dnpool_chk(str url,int bs){
//检测url是否存在
int i;
int count;
str s;
url=strreplace(url,"|","#SU#"); //转义
count=strlist_count(bs);
for (i=0;i<count;i++){
s=explode_str(strlist_get(bs,i),"|",0);
if(s==url){
return i;
}
}
return -1;
}
void dnpool_add(str url,int addr,int size,int mode){
//添加一个待下载
int bs;
str s;
int js;
bs=strlist_creat(dnpool);
//根据url查重
js=dnpool_chk(url,bs);
if (js==-1){
if (size==0){
s=url+"|x|x|x";
}else{
s=url+"|"+addr+"|"+size+"|"+mode;
}
strlist_add(bs,s);
}
}
int dnpool_start(){
//下载 有内容下载返回1 无内容返回0 busy返回2
int bs;
str s;
str url;
str ss;
int addr;
int size;
int mode;
//echo("\r\ndnpool='"+dnpool+"';\r\n");
if (dnpool=="") return 0;
if ($dnpool_busy==1) return 2;
bs=strlist_creat(dnpool);
s=strlist_get(bs,0);
url=explode_str(s,"|",0);
url=strreplace(url,"#SU#","|"); //转义
if (url=="") return 0;
ss=explode_str(s,"|",1);
$dnpool_busy=1; //busy标志置位
if (ss=="*"){
//get str模式
wifi_httpget(url);
}
else{
//dnbin模式
addr=explode_num(s,"|",1);
size=explode_num(s,"|",2);
mode=explode_num(s,"|",3);
wifi_httpdnbin(url,addr,size,mode);
}
strlist_del(bs,0);
return 1;
}
void dnpool_run(){
//dnpool调用入口
//$dnpool_type 0-无 1-add 2-run
//bind dnpool_url url
//$dnpool_addr,$dnpool_size,$dnpool_mode
int r;
if ($dnpool_type==2){
r=dnpool_start();
}
if ($dnpool_type==1){
str url;
url=bind_get("dnpool_url");
dnpool_add(url,$dnpool_addr,$dnpool_size,$dnpool_mode);
r=dnpool_start();
}
if (r==0)
{ $dnpool_type=0;
}
}
//事件:
void onWIFI32(int m){
int msgnum;
str s;
msgnum=wifi_getinfo(2);
if (m==7){
//mqtt 协议的处理代码(此处略)
}
if (m==4){ //httpdnbin 下载二进制数据完成
$dnpool_busy=0; //下载完成
//---下面代码是执行其他控件注册到onWIFI32上的钩子代码,完成回调
hook_run("onWIFI32","*","*"); //获取onWIFI32所有的hook项目,并可赋值
hook_set(wifi_getinfo(5)); //url
hook_set(wifi_getinfo(19)); //size
}
if (m==3) //httpget
{ $dnpool_busy=0; //下载完成
..... //对应处理代码,此处略
}
}
调用
本例中以url为样本,详细介绍调用方法:
//此代码在urljpg控件代码中
//属性:
int st=0; //状态 =0表示未下载 =1表示已下载
//方法:
void create()
{ //设定hook钩子,将urljpg.doWIFI这个方法钩在appbase的onWIFI32事件上
hook_add("onWIFI32","urljpg","doWIFI");
}
void show()
{ //在此书写刷新前景的语句
//automode(bc); or tranmode(n); //选择显示模式,具体讲解请参见语句说明书
automode(bc);
if ((url!="")&(st==0)){
//wifi_httpdnbin(url,0xa0000,256000,1);
bind_set("dnpool_url",url);
$dnpool_type=1;
$dnpool_addr=0xa0000;
$dnpool_size=256000;
$dnpool_mode=1;
callappbase("dnpool_run"); //调用appbase中的下载池入口,通过Bind以及$全局变量的方法传入参数
label(16,x1,y1,x2,y2,"loading....",15,63,0);
}
if (st==1){
label(16,x1,y1,x2,y2,"",15,63,0);
pic(x1,y1,picn);
$dnpool_type=2; //启动下一个
callappbase("dnpool_run"); //调用下载池启用下一个下载
}
}
//事件:
void doWIFI() //处理bin下载完成之后的事件
{
//wifi_httpdnbin
str jurl;
jurl=hook_get(0); //url
//获取URL,如果有多个不同的下载,可以通过URL来识别
if (jurl==url){ //如果是a.jpg,则显示
int size;
size=hook_get(1); //获取下载的a.jpg的实际尺寸
jpg_decode(0xa0000,size,picn); //解码JPG到0号位置,该位置对应图片2048号
st=1; //下载完成
}
}
执行步骤讲述:
页面上放置两个urljpg控件,分别是u1和u2,u1下载a.jpg; u2下载b.jpg
- 1、u1和u2在create方法中将自身的doWIFI事件挂载appbase的onWIFI32事件下
- 2、u1和u2在执行show方法时,调用下载池将url传入下载池中,并启动第一个url的下载(a.jpg的下载);
- 3、当下载完成后,在appbase.onWIFI32中,使用hook回调 u1和u2 的doWIFI事件;
- 4、在u1和u2的doWIFI事件中,u1的url与下载一致,因此被解码;而u2的下载地址不一致,因此u2无反应
- 5、u1的jpg解码后,调用u1.show方法,将jpg这个pic显示到界面上,并且调用下载池启动下一个url的下载;
- 6、下载池管理中,第二个url下载启动
- 7、当下载完成后,在appbase.onWIFI32中,使用hook回调 u1和u2 的doWIFI事件;
- 8、在u1和u2的doWIFI事件中,u2的url与下载一致,因此被解码;而u1的下载地址不一致,因此u1无反应
- 9、u2的jpg解码后,调用u2.show方法,将jpg这个pic显示到界面上,并且调用下载池启动下一个url的下载;
- 10、此时下载池中为空,也就是字符串dnpool为空,dnpool_run调用后直接返回,于是整个下载完成;