0

さて、ここに1つの奇妙なバグがあります...

私のアプリでは、複数のxmlファイルをロードします。そしてそれらをロードするために、私は常に新しいURLLoaderを作成します。特にない。

最初のファイルは正常に機能し、2番目のファイルも正常に機能します。ただし、3番目のファイルは正常にロードされたと報告されますが、保持されているデータは実際には2番目のファイルのデータです。現在の回避策は、3番目のファイルを2回ロードすることですが、これはどういうわけか機能します...奇妙です。

私はそのようなことがどのように起こり得るのか全く分かりません。もちろん、3つのファイルはすべて、パスが異なる異なるファイルです。

これが関連するクラスです。何か役に立てば幸いです。不明な点がある場合は、お問い合わせください。DownloadJobクラスは、StringオブジェクトとFunctionオブジェクトを保持する単なるヘルパークラスです。後者は、ダウンロードが終了したときに呼び出されます。

    // Actual class stuff
    private var _downloadQueue  :Array = new Array();

    /**
     * Adds a download to the queue. Will be started immediatly.
     * @param   p_url       The URL of the download.
     * @param   p_callback  The function to call when the download is finished. Has to take a DisplayObject/Sound/String as first parameter.
     */
    public function addDownload(p_url:String, p_callback:Function) :void
    {
        var job :DownloadJob = new DownloadJob(p_url, p_callback);
        _downloadQueue.push(job);

        debug.ttrace("added: " + job.url);

        // If it is the only item, start downloading
        if (_downloadQueue.length == 1)
        {
            var job :DownloadJob = DownloadJob(_downloadQueue[0]);
            load(job);
        }
    }

    /**
     * Will call the callback and dispatch an event if all loading is done.
     * @param   p_event The event that is passed when a download was completed.
     */
    private function downloadComplete(p_event:Event) :void 
    {
        var job :DownloadJob = DownloadJob(_downloadQueue[0]);
        var downloaded :Object = p_event.target;
        _downloadQueue.splice(0, 1);

        debug.ttrace("completed: " + job.url);

        // Notify via callback
        if (downloaded is LoaderInfo)
        {
            job.callback(downloaded.content);
        }
        else if (downloaded is Sound)
        {
            job.callback(downloaded);
        }
        else if (downloaded is URLLoader)
        {
            // This one holds the data of the previously loaded xml, somehow
            job.callback(URLLoader(downloaded).data);
        }

        // Continue downloading if anything is left in the queue
        if (_downloadQueue.length > 0)
        {
            var job :DownloadJob = DownloadJob(_downloadQueue[0]);
            load(job);
        }
        else
        {
            dispatchEvent(new Event(EVENT_DOWNLOADS_FINISHED));
        }
    }

    /**
     * Will load the passed job immediatly.
     * @param   p_job   The job to load.
     */
    private function load(p_job:DownloadJob) :void
    {
        // Different loaders needed for data, sound and non-sound
        if (p_job.url.indexOf(".xml") != -1 ||
            p_job.url.indexOf(".txt") != -1)
        {
            var urlloader :URLLoader = new URLLoader();
            urlloader.addEventListener(Event.COMPLETE, downloadComplete);
            urlloader.addEventListener(IOErrorEvent.IO_ERROR, handleError);
            urlloader.load(new URLRequest(p_job.url));
        }
        else if (   p_job.url.indexOf(".mp3") != -1 &&
                    p_job.url.indexOf(".flv") != -1)
        {
            var sound :Sound = new Sound();
            sound.addEventListener(Event.COMPLETE, downloadComplete);
            sound.addEventListener(IOErrorEvent.IO_ERROR, handleError);
            sound.load(new URLRequest(p_job.url));
        }
        else
        {
            var loader :Loader = new Loader();
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, downloadComplete);
            loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, handleError);
            loader.load(new URLRequest(p_job.url));
        }
    }

}
4

1 に答える 1

1

私はあなたのクラスに時間を費やしましたがaddDownload、タイマーからランダムなコマンドをディスパッチしてもエラーを見つけることができませんでした. あなたが投稿したコード内に実際に問題がある場合、おそらく問題はActionScriptの奇妙な変数処理に関係していると推測できます。

それで、私はあなたのクラスを少し再配置する自由を取りました:

  • キューのタイプを に変更しましたVector.<DownloadJob>。これにより、すべての型キャストを取り除くことができます。
  • 現在のダウンロードはフィールド variable に保存されますcurrentJob。とにかく、一度に取り組む仕事は1つだけです。これにより、すべての関数引数が削除されます。
  • ジョブがキューに追加されるのは、そうcurrentJobでない場合null、つまりダウンロードが実際に進行中の場合のみです。待つ必要がなければ、キューに入れる必要はありません。push()これにより、各およびへの呼び出しが 1 つだけ残りますsplice()。物事がいつ追加されたり削除されたりするかに関して、これ以上の不確実性はありません。
  • ハンガリー語表記を削除しました (ActionScript ではこれを行いません)。
  • より大きなメソッドをより小さく、より読みやすいチャンクに分割します(私が考えるのに役立ちます:))。
  • APIメソッドを除いて、すべてのコメントを削除しました(コードはそれ自体で語るべきだと思います)。

以下のコードを以前のクラスと交換してみて、問題がまだ存在するかどうかを確認してください。もしそうなら、おそらくペイロードを処理するコールバック関数に問題があると確信しています。

private static const EVENT_DOWNLOADS_FINISHED : String = "EVENT_DOWNLOADS_FINISHED";
private var currentJob : DownloadJob;
private var downloadQueue : Vector.<DownloadJob> = new Vector.<DownloadJob> ();

/**
 * Adds a download to the queue. Will be started immediatly.
 * @param   url       The URL of the download.
 * @param   callback  The function to call when the download is finished. Has to take a DisplayObject/Sound/String as first parameter.
 */
 public function addDownload ( url : String, callback : Function ) : void {
    var job : DownloadJob = new DownloadJob ( url, callback );
    if (currentJob) downloadQueue.push ( job );
    else {
        currentJob = job;
        load ();
    }
}

private function load () : void {
    if ( jobIsText () ) loadText ();
    else if ( jobIsSound () ) loadSound ();
}

private function jobIsText () : Boolean {
    var url : String = currentJob.url;
    return url.indexOf ( ".xml" ) != -1 || url.indexOf ( ".txt" ) != -1;
}

private function jobIsSound () : Boolean {
    var url : String = currentJob.url;
    return url.indexOf ( ".mp3" ) != -1;
}

private function loadText () : void {
    var urlloader : URLLoader = new URLLoader ();
    urlloader.addEventListener ( Event.COMPLETE, handleComplete );
    urlloader.addEventListener ( IOErrorEvent.IO_ERROR, handleError );
    urlloader.load ( new URLRequest ( currentJob.url ) );
}

private function loadSound () : void {
    var sound : Sound = new Sound ();
    sound.addEventListener ( Event.COMPLETE, handleComplete );
    sound.addEventListener ( IOErrorEvent.IO_ERROR, handleError );
    sound.load ( new URLRequest ( currentJob.url ) );
}

private function handleComplete ( ev : Event ) : void {
    processPayload ( ev.target );

    if (downloadQueue.length > 0) loadNext ();
    else dispatchEvent ( new Event ( EVENT_DOWNLOADS_FINISHED ) );
}

private function handleError ( ev : Event ) : void {
    trace ( "Error while downloading:" + currentJob.url );
}

private function processPayload ( loader : Object ) : void {
    currentJob.callback ( getPayload ( loader ) );
    currentJob = null;
}

private function loadNext () : void {
    currentJob = downloadQueue.splice ( 0, 1 )[0];
    load ();
}

private function getPayload ( loader : Object ) : Object {
    return (loader is LoaderInfo) ? loader.content :     
               (loader is URLLoader) ? URLLoader ( loader ).data :
                   loader;
}
于 2012-02-07T16:17:44.770 に答える