一応、原因が分かったのでご報告。
URLLoaderにEventListenerを追加するには、addEventListenerを使います。
このAPIを見ると
public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
イベントリスナーが不要になった場合は、removeEventListener() を呼び出して、イベントリスナーを削除します。削除しない場合、メモリの問題が発生する可能性があります。ガベージコレクターは参照を有するオブジェクトを削除しないため、登録されているイベントリスナーに関係したオブジェクトはメモリから自動的に除去されません。
と書いてあります。そうか...メモリリーク怖いしなぁーと思い、第三引数のWeakReferenceをtrueに指定して使っていました。
WeakReference...Javaでもおなじみの弱参照ってやつですね。
ということで、このWeakReferenceをつかったAIRアプリとしてこんな感じものもを作ってみました。
WindowLoadTest.mxml
<?xml version="1.0" encoding="UTF-8"?>
<mx:WindowedApplication title="WindowLoadTest" windowComplete="onWindowCompleted()" alpha="0.7" layout="absolute" xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script source="WindowLoadTest.as"/>
</mx:WindowedApplication>
WindowLoadTest.as
import flash.net.*;
import flash.events.*;
protected function onWindowCompleted():void {
start();
}
public function start():void {
var loader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest();
request.method = "GET";
request.url = "http://www.google.com/";
loader.addEventListener(Event.COMPLETE, onCompleted, false, 0 , true);
loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler, false, 0 , true);
trace("loader load:" + request.method + ";" +request.url);
loader.load(request);
}
private function onCompleted(event:Event):void {
trace("onCompleted:" + event);
}
private function httpStatusHandler(event:HTTPStatusEvent):void {
trace("httpStatus: " + event.status);
}
これだと、無事に動きます。Traceで出力されたログは以下。
loader load:GET;http://www.google.com/
httpStatus: 200
onCompleted:[Event type="complete" bubbles=false cancelable=false eventPhase=2]
次に start()メソッドを別のクラスに移動して動かしてみます。
startのロジックをLoadTest.asに移動します。
LoadTest.as
package {
import flash.net.*;
import flash.events.*;
public class LoadTest {
public function start():void {
var loader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest();
request.method = "GET";
request.url = "http://www.google.com/";
loader.addEventListener(Event.COMPLETE, onCompleted, false, 0 , true);
loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler, false, 0 , true);
trace("loader load:" + request.method + ";" +request.url);
loader.load(request);
}
private function onCompleted(event:Event):void {
trace("onCompleted:" + event);
}
private function httpStatusHandler(event:HTTPStatusEvent):void {
trace("httpStatus: " + event.status);
}
}
}
WindowLoadTest.asは以下に変更
protected function onWindowCompleted():void {
new LoadTest().start();
}
これを実行すると以下のTraceログになります。
loader load:GET;http://www.google.com/
追加したはずのEvent.COMPLETEのイベントが飛んでこないみたいでログに出てきません(涙)
ここで、LoadTest.asでWeakReferenceで追加しているコード
loader.addEventListener(Event.COMPLETE, onCompleted, false, 0 , true);
を強参照に戻す、つまり
loader.addEventListener(Event.COMPLETE, onCompleted)
にすると、Event.COMPLETEのイベントが飛んでくるようになります。
...ということで、どうやらURLLoaderに弱参照のみのListenerを追加するとイベントが完了する前にGCが行なわれて,GC対象になってしまう...ような感じです。
それならばっ!ということで、LoadTestのクラスを、MXMLのクラス変数で保持するようにしたら?という所を試してみました。
コード的には以下のように修正です。
WindowLoadTest.as
private var loadTest:LoadTest;
protected function onWindowCompleted():void {
loadTest = new LoadTest();
loadTest.start();
}
そうすると、結果は
loader load:GET;http://www.google.com/
httpStatus: 200
onCompleted:[Event type="complete" bubbles=false cancelable=false eventPhase=2]
となり、無事にCOMPLETEDイベントも返ってきました!
どういう状態のものがGC対象になるのか、ならないのか...ちゃんと理解しながらコード書かないとハマるなぁ...
今回の件は解決できたからいいとしても、はっきりと理解できていないので、不安です。。