Просмотр полной версии : загрузка нескольких файлов в процентах
inozemcev
03.10.2011, 18:09
Увидел у 'зеленых носков' их загрузчик (http://www.greensock.com/loadermax/)и меня заинтересовало следующее : каким образом они определяют в процентах статус загрузки сразу нескольких файлов?
Получается что они получают полную информацию о количестве байт всех файлов еще до того, как они будут загружены. Каким образом они это могли бы реализовать?
Получают от сервера размеры файлов?
Все довольно просто. Смотри :
1. Узнаем сколько картинок = столько лоадеров. Макс собирает все лоадеры в кучу. Далее есть некая переменная 100 / лоадеры . И так допустим у нас 5 лоадеров - 100 / 5 = 20 . Тоесть каждый лоадер работает в режиме 20% об общего прогресса
2. Овералл = (curloader.bytesLoaded / curloader.bytesTotal)*loaderCounts * 20 ( что то типа того, тока с форумулой помоему напутадл ))
inozemcev
03.10.2011, 18:30
Маловероятно. Это обычная as3 библиотека.
Интересно можно ли узнавать количество байт подобным образом.
var bt:int;
var loader:URLLoader = new URLLoader (new URLRequest ('someResource'));
bt += loader.bitesTotal;
loader = new URLLoader (new URLRequest ('anotherResource'));
bt += loader.bitesTotal;
И таким образом получить общее кол во байт до загрузки файлов?
Конечно нельзя )) Поток открывается на событии open далее начинается прогресс - где идет получение.
Можно конечно запустить все лоадеры по прогрессу и как только прогресс отработал сразу закрыть поток, но успехов кроме как жуткие задержки перед началом общей загрузки это особых не принесет
inozemcev
03.10.2011, 18:39
Все довольно просто. Смотри :
1. Узнаем сколько картинок = столько лоадеров. Макс собирает все лоадеры в кучу. Далее есть некая переменная 100 / лоадеры . И так допустим у нас 5 лоадеров - 100 / 5 = 20 . Тоесть каждый лоадер работает в режиме 20% об общего прогресса
2. Овералл = (curloader.bytesLoaded / curloader.bytesTotal)*loaderCounts * 20 ( что то типа того, тока с форумулой помоему напутадл ))
На сколько я понял количество лоадеров, не обязательно и даже скорее почти всегда не равно количеству загрузок. Конкретно в этом лоадере есть параметр maxConnections который определяет максимальное количество лоадеров для параллельной загрузки.
В принципе можно делить оверол на общее кол-во загрузок и по загрузке каждого конкретного ресурса прибавлять некий процент - долю, но это не совсем точные данные в случае когда мы будем грузить два ресурса один большой другой маленький, визуально будет казаться что 50 процентов загрузилось быстро, а остальные 50 подвисли. Хотелось бы получить точный оверол, выраженный в количестве байт и по событию Event.Progress отнимать bitesLoaded конкретной загрузки, тем самым, обеспечив гибкую и плавную визуализацию процесса загрузки.
Cheburashka
03.10.2011, 20:17
Может я что-то не понял. Проблему тоже видимо не так понял.
Есть 3 загрузчика, которые одновременно загружают файлы:
var arLoaders : Array = [new Loader(), new Loader(), new Loader()]; // утрирую
По энтерфрейму или таймеру опрашиваем их:
var bytesLoaded : int = 0;
var bytesTotal : int = 0;
for (var i : int = 0; i < arLoaders.lenght; i++) {
var loader : Loader = Loader(arLoaders[i]);
bytesLoaded += loader.contentLoaderInfo.bytesLoaded;
bytesTotal += loader.contentLoaderInfo.bytesTotal;
}
trace(String((bytesLoaded / bytesTotal) * 100) + "%");
Или я все-таки не так понял задачу?
так то да, но врядли носки используют кучу лоадеров вместо одного :)
Cheburashka, проблема в том, что пока Loader не начал что-то грузить (не получил первый ответ от сервера), то contentLoaderInfo.bytesTotal у него 0. Например, если вдруг браузер может качать только в один поток, т.е. по очереди эти три лоадера будут грузить, то проценты у тебя три раза добегут до 100)
mikhailk
03.10.2011, 20:59
Не надо грузить параллельно.
У пользователей с плохим коннектом будут проблемы.
Я лично поступаю очень просто. Допустим, надо загрузить 5 библиотечных файлов от 400 до 800 кб каждый. Ставим их в очередь и последовательно грузим. При этом всю линейку прогресс-бара делим на количество загружаемых файлов, а внутри каждой сублинейки показываем прогресс загрузки соответствующего файла.
Работает очень симпатично.
Мне кажется зная количество загружаемых файлов не сложно будит построить такую загрузку.
создав общую переменную и к ней прибавлять то что показывает e.bytesLoaded / на количество загружаемых объектов, ну и естественно показывать то что хранится в общей переменной. Так не проще?
var allPathToFile:Array = ["img1.jpg", "img2.jpg", "img3.jpg"];
var currentObject:int = allPathToFile.lenght;
var allProgress:Number = 0;
var counter:Number = 0;
allLoaded (counter);
function allLoaded (e:int):void
{
loader = new loader(allPathToFile[counter])
// ...
function onLoad(e:Event):void
{
// ...
counter ++;
allLoaded (counter);
}
function onProgress(e:ProgressEvent):void
{
// по моему в такой ситуации приоритеты выставлять не нужно но я всё же поставил скобки для пущей уверенности.
allProgress += ((e.bytesTotal / e.bytesLoaded) * 100) / currentObject;
trace(allProgress + "%");
}
}
mikhailk
04.10.2011, 10:37
e.bytesTotal и e.bytesLoaded - это вроде внутри одного процесса загрузки (одного лоадера)
Ну, если внимательно посмотреть то я использую рекурсивный метод. Т.е. там где стоит "//..." подразумевается часть кода которая и добавляет/удаляет лиснеры и т.п., асам процесс идёт по очерёдно, друг за другом. Если не понятно объяснил не поленюсь накидать полный пример.
Vishapakahr
04.10.2011, 12:08
не проверил на практике толька что писал , но теоритически предпологается что будет работать
package movieclip {
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.net.URLRequest;
import flash.text.TextField;
public class MyLoader extends Sprite {
private var _contentArr:Array;
private var count:int = 0;
private var totalBytes:Number = 0;
private var currentLoaded:Number = 0;
private var bytesTotalArr:Array = [];
private var txt:TextField;
public function MyLoader(contentArr:Array) {
txt = new TextField();
txt.width = 200;
txt.height = 200;
addChild(txt);
this._contentArr = contentArr;
for (var i:int = 0; i < contentArr.length; i++)
{
var ldr:Loader = new Loader();
ldr.name = i.toString();
ldr.load(new URLRequest(contentArr[i]));
ldr.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, loading);
}
}
private function loading(e:ProgressEvent):void
{
if(e.bytesTotal){
e.target.removeEventListener(ProgressEvent.PROGRESS, loading);
totalBytes += e.bytesTotal;
txt.appendText('totalBytes: '+totalBytes+'\n');
bytesTotalArr.push(e.bytesTotal);
count ++;
if (count == contentArr.length) {
count = 0;
startLoading();
}
}
}
private function startLoading():void
{
var ldr:Loader = new Loader();
ldr.name = '0';
ldr.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onLoading);
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE,done);
ldr.load(new URLRequest(contentArr[0]));
}
private function onLoading(e:ProgressEvent):void
{
txt.appendText('content_'+e.target.name+' loading progress is: '+Math.round((currentLoaded+e.bytesLoaded)/totalBytes)+'\n');
}
private function done(e:Event):void
{
currentLoaded += bytesTotalArr[Number(e.target.name)];
count++;
txt.appendText('count: '+count+'\n');
if (count == contentArr.length) {
this.dispatchEvent(new Event('loadingComplete'));
}else{
var ldr:Loader = new Loader();
ldr.name = count.toString();
ldr.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onLoading);
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE,done);
ldr.load(new URLRequest(contentArr[count]));
}
}
public function get contentArr():Array {
return _contentArr;
}
}
}
inozemcev
04.10.2011, 13:06
Опять же вы привязываетесь к лоадерам. Еще раз говорю, что количество лоадеров и количество загрузок не одно и тоже - загрузок может быть 10, 20, 30 а лоадеров может быть 1, 2, 5 в зависимости от алгоритмов менеджера загрузок. Собственно я и так понимаю, что уперся в невозможность самого actionscript работать с непосредственно файлами. В случае, когда у нас есть сервер и серверный программист наверное будет правильнее получить оверал от сервера, в ином случае придется делать заглушки. Интересно можно ли с помощью HAXE как то обойти ограничения связанные с файловой системой и непосредственно узнать их размер перед загрузкой?
gloomyBrain
04.10.2011, 13:53
Как Вы себе это представляете? Может быть Вас это удивит, но HTTP-сервер в любом случае возвращает размер файла (заголовок Content-Length), однако происходит это после открытия соединения (как иначе можно получить размер файла, не спросив об этом сервер?). Файловая система тут вообще не при делах, равно как и HAXE
inozemcev
04.10.2011, 14:04
Хорошо, ну а если флеш лежит в том же месте, что и контент. И для оценки размера файлов я не задействую
htttp запрос, есть ли возможность работать с файлами исключительно в той же директории что и флеш?
gloomyBrain
04.10.2011, 14:20
Ну, если говорить об AIR - то да, есть свойство size у файлов.
Vishapakahr очень громоздка.
Вот проверенный вариант которым пользуюсь постоянно.
package
{
import flash.display.Bitmap;
import flash.display.Loader;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.net.URLRequest;
public class IMGLoader
{
private var allPath :Array = [];
private var allContent :Array = [];
private var counter :int = 0;
private var tmpProgress :Number = 0;
private var outProgress :Number = 0;
private var returnFunction:Function;
private var progressFunction:Function;
public function IMGLoader(path:Array, re:Function, pro:Function)
{
allPath = path;
returnFunction = re;
progressFunction= pro;
onLoadFile();
}
public function onLoadFile ():void
{
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, COMPLETE);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, IO_ERROR);
loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, PROGRESS);
loader.load(new URLRequest(allPath[counter]));
function IO_ERROR(e:IOErrorEvent):void {
// тут можно подставить что угодно,
// либо свою картинку в случае ошибки,
// либо оттянуть время и вновь попробовать её загрузить.
}
function COMPLETE(e:Event):void {
allContent.push(Bitmap(loader.content).bitmapData.clone()); // Копирую содержимое лоадера.
counter ++;
removeAllListener();
onLoadFile (); // так как всё идёт благополучно повторяю метод увеличивая счётчик.
// если все загрузки закончены возвращаем то что нафигачили и можно рубить класс.
if (allPath.length == allContent.length) OPERATIONCOMPLETE();
}
// возвращаем процесс загрузки.
function PROGRESS(e:ProgressEvent):void {
tmpProgress = ((e.bytesTotal / e.bytesLoaded) * 100) / allPath.length;
if (progressFunction != null) progressFunction.call(null, outProgress + tmpProgress);
}
function removeAllListener ():void {
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, COMPLETE);
loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, IO_ERROR);
loader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, PROGRESS);
loader = null;
outProgress += tmpProgress / allPath.length;
}
function OPERATIONCOMPLETE():void {
removeAllListener ();
if (returnFunction != null) returnFunction.call(null, allContent);
}
}
}
}
естественно, после многочисленных проб, просмотреть общую загрузку не удалось и сомневаюсь что удастся.
А если у кого и показан весь процесс, то это только если в xml - ке к пути каждой картинке добавлен её вес, после чего это дело суммируется и вычитается в процессе.
function in function .... ужасть
function in function .... ужасть
согласен, но во многом спасает и экономит, к тому же этот пример написания я довольно часто встречал в книге К.Мука "300 рецептов". Вот как то и приелось. Редко, но метко =)
мук так делает? не знал не знал...
Работает на vBulletin ® версия 3.7.3. Copyright ©2000-2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Copyright © 1999-2008 Flasher.ru. All rights reserved.