PDA

Просмотр полной версии : загрузка нескольких файлов в процентах


inozemcev
03.10.2011, 18:09
Увидел у 'зеленых носков' их загрузчик (http://www.greensock.com/loadermax/)и меня заинтересовало следующее : каким образом они определяют в процентах статус загрузки сразу нескольких файлов?
Получается что они получают полную информацию о количестве байт всех файлов еще до того, как они будут загружены. Каким образом они это могли бы реализовать?

Bgg
03.10.2011, 18:17
Получают от сервера размеры файлов?

in4core
03.10.2011, 18:29
Все довольно просто. Смотри :
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;

И таким образом получить общее кол во байт до загрузки файлов?

in4core
03.10.2011, 18:33
Конечно нельзя )) Поток открывается на событии 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) + "%");

Или я все-таки не так понял задачу?

in4core
03.10.2011, 20:28
так то да, но врядли носки используют кучу лоадеров вместо одного :)

-De-
03.10.2011, 20:30
Cheburashka, проблема в том, что пока Loader не начал что-то грузить (не получил первый ответ от сервера), то contentLoaderInfo.bytesTotal у него 0. Например, если вдруг браузер может качать только в один поток, т.е. по очереди эти три лоадера будут грузить, то проценты у тебя три раза добегут до 100)

mikhailk
03.10.2011, 20:59
Не надо грузить параллельно.
У пользователей с плохим коннектом будут проблемы.

Я лично поступаю очень просто. Допустим, надо загрузить 5 библиотечных файлов от 400 до 800 кб каждый. Ставим их в очередь и последовательно грузим. При этом всю линейку прогресс-бара делим на количество загружаемых файлов, а внутри каждой сублинейки показываем прогресс загрузки соответствующего файла.

Работает очень симпатично.

stweet
03.10.2011, 23:30
Мне кажется зная количество загружаемых файлов не сложно будит построить такую загрузку.
создав общую переменную и к ней прибавлять то что показывает 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 - это вроде внутри одного процесса загрузки (одного лоадера)

stweet
04.10.2011, 11:43
Ну, если внимательно посмотреть то я использую рекурсивный метод. Т.е. там где стоит "//..." подразумевается часть кода которая и добавляет/удаляет лиснеры и т.п., асам процесс идёт по очерёдно, друг за другом. Если не понятно объяснил не поленюсь накидать полный пример.

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 у файлов.

stweet
04.10.2011, 14:35
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 - ке к пути каждой картинке добавлен её вес, после чего это дело суммируется и вычитается в процессе.

in4core
04.10.2011, 14:59
function in function .... ужасть

stweet
04.10.2011, 15:04
function in function .... ужасть

согласен, но во многом спасает и экономит, к тому же этот пример написания я довольно часто встречал в книге К.Мука "300 рецептов". Вот как то и приелось. Редко, но метко =)

in4core
04.10.2011, 15:10
мук так делает? не знал не знал...