Archive for 9月, 2009
AIRでLocalConnectionを使ってデータを受け取る場合には、
var con:LocalConnection = new LocalConnection();
con.send("接続名", "メソッド名", 引数...);
のようにすればいいのはわかるが、ここで”接続名”ではまってしまった。
一体、”接続名”は何になるのか・・・・・
いろいろ調べていたら、ここに書いてありました。
以下、抜粋
-----------
Adobe AIR の application セキュリティサンドボックスで実行されているコンテンツ(AIR アプリケーションと共にインストールされたコンテンツ)では、スーパードメインの代わりに、ストリング app# に続いて AIR アプリケーションのアプリケーション ID(アプリケーション記述子ファイルで定義)が使用されます。例えば、アプリケーションの connectionName は、アプリケーション ID が com.example.air.MyApp の場合、connectionName は"app#com.example.air.MyApp:connectionName" に解決されます。
----------
つまり、アプリケーションIDをFooにした場合には、app#Foo:connectionNameになるというのです。
これで、上の”接続名”としてもうまくいきませんでした。
そこで、AIRとして実際に実行してdomainの値を見てみるととこれが違うのです。
app#Foo.7D80D064F882A8B9EAC3293F93623397AC88D9C0.1
ってな感じで、表示されるではありませんか?
で、実際これをつかって
app#Foo.7D80D064F882A8B9EAC3293F93623397AC88D9C0.1:connectionName
にしてみたら、うまくできました。
どうやら、これはpublish idのようです。
(publish id がわからない方は、この名称で調べてみてください。)
でも、さらにもう一つ問題が・・・・
これ、AIRとしてインストールすればこのIDが表示されるのですが、Flex BuilderでデバッグしているときにはこのIDが設定されないので、
結局デバッグができない・・・・
と思って調べてみたら、ちゃんと設定場所があるのですね。
アプリを右クリックして、プロパティから「実行/デバッグの設定」で、アプリの「編集」ボタンを押すと、
「パブリッシャーID」
として、登録する場処理がありました。
これを設定すれば、Flex Builderでのデバッグでも、きちんとできました。
いやー、結構はまりました。
flexのValidatorを使っているときに、ふと疑問におもったので調べることにした。
というのも、チェックしたい値があるオブジェクトと、エラーを出力したいオブジェクトが異なるときに一体どうすればいいのだ?はたまた、Validatorはもうちょっと使いやすくならないだろうか?
と思ったのがきっかけだ。そもそも、Validatorの例などをぶらぶらとみて使っているだけなので、
もっと応用がきくような気がするのだ。
という事で、Validatorを使うときには
<mx:Validator id="v1" required="true" source="f1" property="text" />
<mx:TextInput id="f1" />
<mx:Button click="{v1.validate()}" />
なんて感じにつかうようにサンプルが書いてある。
さて、このValidatorは実際には値のチェック以外に何をしているのだろうか?
では、Validatorのソースを見ていくことにしよう。
まず、肝となる部分が、
Validator内部の処理の
addEventListener(ValidationResultEvent.VALID,IValidatorListener(actualListener).validationResultHandler); addEventListener(ValidationResultEvent.INVALID,IValidatorListener(actualListener).validationResultHandler);
という処理だ。
このIValidatorListenerというインターフェースだが、このインターフェースはUIComponentは実装されているのだ。
したがって、ValidatorがValidationResultEvent.VALIDもしくは、ValidationResultEvent.INVALIDを発行して、それを(通常)UIComponentが受け取り、エラー処理をしているのだ。
もうひとつ、上のコード指定されているactualListenerとは一体Validatorタグの中でどこを指しているのだろうか?
これは、実はlistenerもしくはその指定がなければsourceを指すのだ。
ここまでくれば、上の疑問「チェックしたい値があるオブジェクトと、エラーを出力したいオブジェクトが異なるときに一体どうすればいいのだ?」という質問では、listenerにエラーを出力したいオブジェクトを指定すればよいという事がわかるだろう。
この質問はマニュアルをよく読めば答えは書いてあるのだが、どうしてそのようなルールができているのかがわからないと今一つ頭に入ってこないものだが、このように内部をある程度理解した後にマニュアルを読めばすんなりと頭に入ってくる。
では、UIComponentはエラーイベントを受け取り、何をしているのだろうか?
これは、追うのは簡単だ。すでに、イベント処理の登録でどこが動くか分かっている。
validationResultHandler()
の中身を見てみればよい。
細かい処理をいろいろとやっていはいるが、重要なところは、
if (msg && errorString != msg)
{
errorString = msg;
dispatchEvent(new FlexEvent(FlexEvent.INVALID));
}
のところだろう。
つまり、errorStringにエラーメッセージを設定しているのだ。
これでValidatorの大体の流れがつかめた。
まあ、簡単に言ってしまえば、Validatorは、
1)エラーメッセージを表示したいUIComponentのvalidationResultHandler()メソッドをイベント処理として登録する。
2)チェック処理をするとValidationResultEventイベントを投げる。
とこれだけだ。
AIRアプリからSocketにて通信しようとするときに、接続できない場合での一般的な例外がどのようなエラーとなるのかが、
よくわからないのでちょっと調べてみた。
ケース1)サーバが見つからないとき、もしくはそのサーバに接続できないとき
- 接続ができないとわかった段階で「IOErrorEvent」のイベントが発行される。
- Socket.timeoutたったあと「SecurityErrorEvent」のイベントが発行される。
ケース2)ポートが開いていないとき(サービスが上がっていないとき)
ケース1と同様
- 接続ができないとわかった段階で「IOErrorEvent」のイベントが発行される。
- Socket.timeoutたったあと「SecurityErrorEvent」のイベントが発行される。
ケース3)ポートがFirewall(iptablesで受け付けない)で拒否をされているとき。
- Socket.timeoutたったあと「SecurityErrorEvent」のイベントが発行される。
- 接続ができないとわかった段階で「IOErrorEvent」のイベントが発行される。
ここで、イベントの順番が今までと違ってきました
ケース4)ポート番号がおかしいとき、「90000」とか・・・
- 「SecurityError」の例外が投げられる。
- Socket.timeoutたったあと「SecurityErrorEvent」のイベントが発行される。
しかし、接続できなかったときには、どっちのイベントで捕まえればいいのかなと思っていましたが、
「SecurityErrorEvent」、「IOErrorEvent」も両方発行されるのですね。
ケース4のように命令としておかしくても、「SecurityErrorEvent」のイベントが発行されるようなので、
エラーはたいてい「SecurityErrorEvent」で処理をしておけば大丈夫ってことでしょう。
Socket.timeoutできちんと処理をあきらめたいということであれば、
なおさら、「SecurityErrorEvent」で処理をしたほうがいいということかな。
ViewStackを使っていて、子コンポーネントでの表示切替時でちょっと気にしなければいけない点があったので記録。
ViewStackなどは子コンポーネント同時に表示するわけではないのでちょっと気にしなければならないのが、creationPolicyプロパティ。
これは、子のインスタンスルールなのだが、通常、何も指定していないときには、子ビューがインスタンス化されていない可能性があるということです。
これは遅延インスタンスという機能があり、実際に必要になる(見る必要がある)までインスタンスを遅らせるというものです。
ここで、ちょっと注意なのが「子ビュー」のインスタンスということで、そのクラスのインスタンスではありません。
ですので、普通の部品のようにMXML内の要素に、自分自身のcreationCompleteなどの処理でアクセスしようとしてもエラーになってしまうというわけです。
したがって、creationCompleteで処理をするには、「子ビュー」の要素にcreationCompleteのプロパティを設定すれば、
想定したようになるというわけです。
たとえば、
<mx:ViewStack>
<foo:View>
</mx:ViewStack>
<foo:View creationComplete="init()">
<mx:Canvas id="cs" />
</foo>
しかし、init()処理の中ではcsにはアクセスできません。これは、遅延インスタンス機能によりまだ、インスタンス化されていないからです。
したがって、
<foo:View >
<mx:Canvas id="cs" creationComplete="init()" />
</foo:View>
にすればいいというわけです。
まあ、creationPolicyをもっと良く知れば、これ以外にもそのアプリケーションならではのもっといい方法が見つかるとは思います。
以前、日付をphpのdate関数のように扱いたいということでプログラムを書いたがちょっとバグがあったので、
それを修正したのと、エスケープを使えるようにしました。
バグの部分は、引数がt(つまり、指定した月の日数)をなおしました。
また、PHPのdate関数を参考に、ISO 8601とRFC2822形式も対応しました。
基本的な使い方は変わっていないので割愛します。
まあ、ソースを見てもらえればわかるとも 思いますので・・・・

