[心缘地方]同学录
首页 | 功能说明 | 站长通知 | 最近更新 | 编码查看转换 | 代码下载 | 常见问题及讨论 | 《深入解析ASP核心技术》 | 王小鸭自动发工资条VBA版
登录系统:用户名: 密码: 如果要讨论问题,请先注册。

[备忘]痛苦的Flex上传文件之进度条显示~~~

上一篇:[转帖]SMTP协议的邮件路由过程
下一篇:[备忘]hibernate如何快速复制已有的对象,来新增记录

添加日期:2013/4/7 16:44:15 快速返回   返回列表 阅读4917次
费了牛劲,终于搞定了,直接贴代码了~~~
参考了:
http://hi.baidu.com/nstarzcm/item/3b0963d65ce411cf1a72b408#a229efd920147e2b10df9bac


<?xml version="1.0" encoding="utf-8"?>
<s:TitleWindow xmlns:fx="http://ns.adobe.com/mxml/2009" 
           xmlns:s="library://ns.adobe.com/flex/spark" 
           xmlns:mx="library://ns.adobe.com/flex/mx" width="100%"
           height="100%" xmlns:ns1="*"
           creationComplete="creationHandler();" 
           title="报表模板上传"
           close="titlewindow1_closeHandler(event)" 
           xmlns:reporttypewebservice="services.reporttypewebservice.*">
    <fx:Script>
        <![CDATA[
            import cn.com.xxxx.event.PagerCloseEvent;
            import cn.com.xxxx.utils.Constants;
            
            import flash.net.FileReference;
            import flash.net.FileReferenceList;
            
            import mx.collections.ArrayCollection;
            import mx.controls.Alert;
            import mx.core.mx_internal;
            import mx.events.CloseEvent;
            import mx.events.FlexEvent;
            import mx.managers.PopUpManager;
            import mx.rpc.AsyncResponder;
            import mx.rpc.AsyncToken;
            import mx.rpc.events.FaultEvent;
            import mx.rpc.events.ResultEvent;
            
            import valueObjects.Version;
            
            //自定义的关闭事件
            private var pagerCloseEvent:PagerCloseEvent = new PagerCloseEvent();
            
            //选择文件
            private var selectFileList:FileReferenceList = new FileReferenceList(); 
            
            //选择的文件的数组
            [Bindable]
            public var selectedFileArray:ArrayCollection = new ArrayCollection();
            
            //当前版本
            public var currVersion:Version = new Version();
            
            //当前上传文件的下标
            private var currFileIndex:uint = 0;
            
            //上传是否已开始
            [Bindable]
            public var uploadStartFlag:Boolean = false;
            
            //记录上传成功的function,以备删除
            public var lastFunc:Function = null;
            
            private function creationHandler():void{
                
            }
            
            protected function titlewindow1_closeHandler(event:CloseEvent):void
            {
                //上传开始了,不允许关闭
                if(!uploadStartFlag)
                {
                    this.dispatchEvent(pagerCloseEvent);
                    PopUpManager.removePopUp(this);
                }
            }
            
            
            //显示行号
            private function lfRowNum(item:Object, column:int):String
            {
                var index:int=dataGrid.dataProvider.getItemIndex(item) + 1;
                return String(index);
            }

            protected function button1_clickHandler(event:MouseEvent):void
            {
                var fileTypes:FileFilter = new FileFilter("报表模板 (*.xml, *.xsl, *.js)", "*.xml; *.xsl; *.js;");
                var allTypes:Array = new Array( fileTypes );
                
                try
                {
                    selectFileList.browse(allTypes);//不限制类型,就直接browse()即可
                    selectFileList.addEventListener(Event.SELECT, selectHandler1);
                }
                catch (error:Error) 
                {
                    Alert.show("文件选择出现错误,请选择正确的文件");
                }
            }
            
            /**
             * 如果文件被选中,则执行该方法
             * */
            private function selectHandler1(event:Event):void
            {
                //所有文件,放到selectedFileArray中
                var upLoadFileList:FileReferenceList = FileReferenceList(event.target);
                for(var i:int=0;i<upLoadFileList.fileList.length;i++){
                    var f:FileReference = FileReference(upLoadFileList.fileList[i]); 
                    
                    var obj:Object= new Object();
                    obj.fileName = f.name;
                    obj.fileSize = f.size;
                    obj.fileType = f.type;
                    obj.fileRefrence = f;
                    obj.currValue = 0; //已上传字节数
                    obj.uploadOk = false; //是否上传完毕
                    selectedFileArray.addItem(obj);
                }
            }
            
            /**
             * 开始上传.
             * */
            protected function doUpload_clickHandler(event:MouseEvent):void
            {
                currFileIndex = 0;
                uploadStartFlag = true;
                uploadNextFile();
            }
            
            /**
             * 上传下一个文件.
             * */
            protected function uploadNextFile():void
            {
                if(currFileIndex < selectedFileArray.length)
                {
                    //已上传OK,跳过
                    if(selectedFileArray[currFileIndex].uploadOk)
                    {
                        currFileIndex++;
                        uploadNextFile();
                    }
                    else
                    {
                        //载入文件数据
                        var upLoadFile:FileReference = FileReference(selectedFileArray[currFileIndex].fileRefrence); 
                        upLoadFile.addEventListener(Event.COMPLETE,onLoadComplete);
                        upLoadFile.load();
                    }
                    
                }else{
                    uploadStartFlag = false;
                    Alert.show("上传完毕。");
                }
            }
            
            /*
            * 文件数据载入完毕. 
            */
            private function onLoadComplete(e:Event):void
            {
                //主动删除监听器
                var upLoadFile:FileReference = FileReference(e.target);
                upLoadFile.removeEventListener(Event.COMPLETE,onLoadComplete);
                
                //上传数据
                uploadReportTypeFileResult.token = reportTypeWebService.uploadReportTypeFile(currVersion.id,upLoadFile.name,upLoadFile.data);
                
                //一定要删除旧的监听器,否则非常混乱
                if(uploadReportTypeFileResult.hasEventListener(ResultEvent.RESULT))
                {
                    uploadReportTypeFileResult.removeEventListener(ResultEvent.RESULT,lastFunc);
                }
                
                //成功处理
                uploadReportTypeFileResult.addEventListener(ResultEvent.RESULT,
                    function(event:ResultEvent):void 
                    {
                        //记住该function,以备删除
                        lastFunc = arguments.callee;
                        
                        //更新当前上传字节数
                        selectedFileArray[currFileIndex].currValue = upLoadFile.size;
                        selectedFileArray[currFileIndex].uploadOk = true;
                        
                        //下标+1,上传下一个
                        currFileIndex++;
                        uploadNextFile();
                    });
                
                //失败处理
                uploadReportTypeFileResult.addEventListener(FaultEvent.FAULT,
                    function(info:Object):void 
                    {
                        //失败
                        Alert.show(upLoadFile.name);
                        
                        //下标+1
                        currFileIndex++;
                        uploadNextFile();
                    });
            }
        >>
    </fx:Script>
    <fx:Declarations>
        <s:CallResponder id="getReportTypeListResult"/>
        <reporttypewebservice:ReportTypeWebService id="reportTypeWebService" fault="Alert.show(event.fault.faultString + '\n' + event.fault.faultDetail)" showBusyCursor="true"/>
        <s:CallResponder id="uploadReportTypeFileResult"/>
        <!-- 将非可视元素(例如服务、值对象)放在此处 -->
    </fx:Declarations>
    <s:VGroup width="100%"
              height="100%"
              horizontalAlign="left"
              textAlign="left">
            <s:VGroup width="100%"
                      paddingLeft="10"
                      paddingRight="10"
                      height="305">
                
    <mx:DataGrid width="100%" height="300" id="dataGrid" dataProvider="{selectedFileArray}">
        <mx:columns>
            <mx:DataGridColumn labelFunction="lfRowNum" width="40" headerText="序号"/>
            <mx:DataGridColumn headerText="文件名称" dataField="fileName" width="300"/>
            <mx:DataGridColumn headerText="文件大小" dataField="fileSize" width="100"/>
            <mx:DataGridColumn headerText="文件类型" dataField="fileType" width="100"/>
            <mx:DataGridColumn width="300" headerText="状态">
                <mx:itemRenderer>
                    <fx:Component>
                        <mx:HBox width="100%" paddingLeft="2" horizontalGap="2">
                            
                                <fx:Script>
                                    <![CDATA[
                                        import mx.collections.ArrayCollection;
                                        import mx.controls.DataGrid;
                                        import mx.controls.Alert;
                                        
                                        //取消,现在没调用
                                        private function cancel():void{
                                            data.fileRefrence.cancel();
                                            progress.label = "已取消";
                                        }
                                        
                                        //绑定数据时的方法
                                        override public function set data(value:Object):void{
                                            super.data = value; //一定要留着
                                            
                                            //根据currValue显示当前进度
                                            progress.setProgress(data.currValue,data.fileRefrence.size);
                                            
                                            //旧的监听器没用了,删除
                                            if(data.fileRefrence.hasEventListener(ProgressEvent.PROGRESS))
                                            {
                                                data.fileRefrence.removeEventListener(ProgressEvent.PROGRESS,data.func);
                                            }
                                            
                                            //添加新的监听器
                                            data.fileRefrence.addEventListener(ProgressEvent.PROGRESS,progressHandler);
                                            data.func = progressHandler;
                                        }
                                        
                                        //监听进度
                                        private function progressHandler(event:ProgressEvent):void{
                                            trace("equal:"+(event.target==data.fileRefrence));
                                            
                                            //不是当前文件的进度,忽略掉
                                            if(event.target==data.fileRefrence)
                                            {
                                                progress.setProgress(event.bytesLoaded,data.fileRefrence.size);
                                                data.currValue = event.bytesLoaded; //保存进度
                                            }
                                        }

                                        //删除,上传开始后,不让删除,免得下标混乱。
                                        private function deleteItem(data:Object):void {
                                            if(!this.outerDocument.uploadStartFlag)
                                            {
                                                var index:int = this.outerDocument.selectedFileArray.getItemIndex(data);
                                                this.outerDocument.selectedFileArray.removeItemAt(index);
                                            }else{
                                                Alert.show("已开始上传,不能删除。");
                                            }
                                        }
                                    >>
                                </fx:Script>
                            <mx:ProgressBar id="progress" width="100%" label="%3%%"
                                            mode="manual" minimum="0" maximum="{data.fileRefrence.size}"
                                            labelPlacement="center">
                            </mx:ProgressBar>
                            <mx:LinkButton width="20" click="deleteItem(data as Object)" toolTip="从列表中删除" icon="@Embed('assets/delete.gif')">
                            </mx:LinkButton>
                        </mx:HBox>
                    </fx:Component>
                </mx:itemRenderer>
            </mx:DataGridColumn>
        </mx:columns>
    </mx:DataGrid></s:VGroup>
        <s:HGroup width="95%"
                  verticalAlign="middle">
            <mx:Spacer width="50%"/>
            <s:Button label="选择文件" click="button1_clickHandler(event)"/>
            <s:Button id="clearListBtn" label="清空列表" click="selectedFileArray.removeAll()" enabled="{(selectedFileArray.length>0) && (uploadStartFlag==false)}"/>
            <s:Button id="uploadBtn" label="开始上传" click="doUpload_clickHandler(event)" enabled="{(selectedFileArray.length>0) && (uploadStartFlag==false)}"/>
            <s:Button id="closeBtn"
                      label="关闭"
                      click="{dispatchEvent(new CloseEvent(CloseEvent.CLOSE))}"
                      enabled="{uploadStartFlag==false}"/>
        </s:HGroup>
        <s:HGroup width="50%"
                  verticalAlign="middle"
                  height="5">
        </s:HGroup>
        </s:VGroup>
    </s:TitleWindow>



服务端是Web Service,大概就这么几行:


    public void uploadReportTypeFile(String versionId, String fileName,
            byte[] fileData) throws CommonException {
        System.out.println(fileName);
        
    }


和普通的调用一样,只是传了个byte[]而已。

以下是问题的根源,比较乱,写不明白了,供参考吧:
另有一个参考:
文件上传与进度条监控的烦人问题http://hi.baidu.com/nstarzcm/item/40d812083ee369dcdde5b030
--------------------------------------------------------------
比如11条记录,初始显示1-10,那么会执行1-10行数据的set data方法,11的不会执行。
向下滚动一行,会执行11的set data方法,其它的不会执行。此时1行数据隐藏了。
向上滚动一行,会执行1的set data方法,其它的不会执行,此时11行数据隐藏了。
也就是,itemRenderer对象是很少的,要显示哪行数据时,就随便拿一个闲置的itemRenderer,往里set data。
结果就是,一个itemRenderer对象是N多行共用,想用itemRenderer来保持一行数据的状态是不行的了。
所以,还是把状态数据,放到data本身里面吧,然后set data时现更新控件什么的。
烦~~~

下面是关于上传进度条的混乱~~
=====================================================================================
比如共30条数据,初始显示1到10.
itemRenderer的set data():
------------------------------------------------------------
文件1---->进度条1,文件1添加监挺气,文件1的上传字节数传递给进度条1,
文件2---->进度条2,
文件3---->进度条3,
...
文件10---->进度条10
------------------------------------------------------------
(1)先不动滚动条:
进度条1-->进度条10,显示正常。
但是,11-30行数据,由于没有显示,所以根本没有执行set data方法。
在监挺气里,更新data行的currValue就不会执行了。
所以,在上传OK的代码里,直接更新了data行里的currValue字段为文件size。
这样,当滚动条拉下来时,进度条直接显示currValue,也就是100%了。

如果,滚动条拉下来时,文件没上传完毕,也没关系。
因为,这时,set data方法执行了,监挺气被添加了,它会更新currValue。

唯一可能的问题点是:
滚动条拉下来后,开始是显示0%的,监挺气被添加之前的一瞬间,上传完毕了。
监挺气被添加上,也没用了,不会触发了。所以进度条此时就显示0%,但实际上是100%。
上下拉拉滚动条,让该行隐藏再显示,就正常了。小问题,不管啦。

(2)还有一个问题,
假设上传开始后,向下滚动了滚动条,显示11-20行~~
------------------------------------------------------------
文件11---->进度条1,文件11添加监挺气,文件1的上传字节数传递给进度条1,
文件12---->进度条2,
文件13---->进度条3,
...
文件20---->进度条10
------------------------------------------------------------
注意,进度条还是1-10,因为进度条是itemRenderer内的,itemRenderer是重用的。

这时,文件1的字节数会传给进度条1,文件11的字节数也传给进度条1.
所以,进度条显示会很混乱。
需要判断event.target与当前行的文件是一致的,才更新进度。
如文件1的字节数过来,就忽略,文件11的字节数过来才更新。

所以,实际上,此时,文件1的进度是无人接收的。
好在,当你想看文件1时,滚动条拉过去,set data执行,
如果已完成,就是100%了,没完成,则会添加监挺气,有进度条监听进度了,就OK了。
只是,进度可能会跳跃一下。

开始显示1-10,然后显示11-20,然后显示1-10,那么文件1实际上就有两个监挺气了。
实际上,之前那个监挺气没什么用了,因为它的监听者现在在为其它行服务,
所以,删掉它即可。
-------------------------------------------------------------------
Flex全都是异步调用,全都是事件触发,好烦啊~~

如果你的事件很乱,那么一定是触发乱了。

添加触发之前,一定看看有没有旧的触发,删掉它,否则后患无穷~~切记~~
----------------------------------------------------------------------

 

评论 COMMENTS
没有评论 No Comments.

添加评论 Add new comment.
昵称 Name:
评论内容 Comment:
验证码(不区分大小写)
Validation Code:
(not case sensitive)
看不清?点这里换一张!(Change it here!)
 
评论由管理员查看后才能显示。the comment will be showed after it is checked by admin.
CopyRight © 心缘地方 2005-2999. All Rights Reserved