2011年12月24日

LINQがわからない

この記事はAdvent Calendar 2011のC#の24日目……のおまけ編だよ。

Advent Calendarの他の人の記事でも解説はいろいろ出てきているけど、LINQがわからないんだよね。
と言うわけで、何がわからないのかを書いてみるよ。

わからないって言うのは、使いどころって言うか、どういうときに使うのかって言うか、そんな感じ。
わたしの直感全開なので意味不明になると思うけど、いつものことなので気にしない。

とにかく使えばいいじゃんって話なのかもだけど、
よくわからないでとりあえずよさそうだから使うって言うのはどうかと思うの。
最初はそれでも、ちゃんと理解した方が良いよね。

で、LINQって調べてると、SQLっぽいのがいっぱい出てくるんだよね。
SQLってDBとかになれてる人が見るとわかりやすいのかもしれないけど、
クライアントのアプリ作ってるとDBってあまり使わない気がするの。
だから、クエリ構文?で解説されてもよくわからない……。

この記事を書くのに、メソッド構文?を中心に書いてあるneue ccさんの記事から
いくつかサイト巡ってたら、この辺にパイプライン型とかの図があってわかりやすかった。

で、
「LINQってデータコレクションを、好きなパイプラインを使ってフィルターしてくれるってことかなー」
って思うところまで来たんだけど、それで良いのかがわからない(・x・

……これを書いてる間に少しわかってきた気がするから、少し使ってみようかな?
posted by すふぃあ at 00:45| Comment(0) | TrackBack(0) | 雁字

Windows PhoneでVNC Viewerつくってみたよ

☆前書き☆

この記事はAdvent Calendar 2011のC#の24日目だよ。

去年のAdvent Calendarとかみんな凄いの書いてるから、
わたしなんか書いて良いのかな〜って思ったりもしたんだけど、
相談したら書いて良いんじゃない?って言われたので書くことにしたの。

他の人に比べて内容も読みやすさもレベルを下げてお届け!
読みにくいって思ったら、この日の記事はなかったことにして次に期待すると良いとおもいまーす。
あ、C#のコアな話を期待している人、そんな内容はないからね!

と、前書きはこのくらいにしてすすむね。
この1ヶ月くらいで作ったWindows Phoneアプリあたりの話をだらだら書くよ。

☆作ったWindows Phoneアプリの紹介☆

C#の勉強ついでにいろいろアプリ作ってみてるんだけど、
Windows Phoneを手に入れたので、せっかくだから何かつくろーって。
で、Androidで作った「ラティ」ってアプリのWindows Phone版を作ることにしたの。
VNCとかRDPとかの、いわゆるリモートデスクトップって言うののクライアントアプリだよ。

なんか、最初に作るならHello Worldでしょ!って言うのが普通なのかもしれないけど、
見た目さみしいし、やっぱりきれいで動くのがいいじゃん?

Android版はVNCベースじゃなかったから、今回は、VNCにちゃんとつながるようにしよう!
というわけでWindows Phone版の「ラティ」はTightVNCのServerとかにつながるようになってるよ。
有料のカテゴリ?になってるけど、トライアル版でも機能差は無いので普通に無料で使えるよ。

☆RFBプロトコル編☆

VNCって言うのはRFBプロトコルで通信するので、それを実装したライブラリとかがないと、だよね。
ってことで探したんだけど……、使えそうなのがないっ(・x・

というわけでRFBプロトコルの仕様書日本語)を読むところから始めることに。
リモートデスクトップのプロトコルって読み解くの大変なんじゃないのかなぁ。
な〜んて最初は思って読んでみたんだけど、これが意外に凄い簡単なの。
FTPのプロトコル日本語)よりも簡単簡単。たぶん。

最初はなんか文字列の送受信するだけで、あとは、
位置+サイズ+画像のデータをひたすら受け取るだけだよ。ほら簡単。

いろいろ手抜き感はあるけど、実装したライブラリがあるので後でリンク張るね。
ここでは簡単に使い方を紹介するよ。

基本的なプロトコルの実装は、RFBStreamって言うのがあるから、それを使えばおっけ。
でもほら、接続から一連のパスワード確認とかは、まとめてやった方が楽じゃない?
というわけでRFBClientってクラスもあるよ。
でもでも、それでももっと簡単に使いたいって人のために、EmprssiaRFBClientって言うのも用意してみた〜。
今回はこれの紹介ってことで。

えーっと、ラティから抜粋したコードをブログ用に書き換えてるので動作保証はないでーす。
あ、もちろん、書き換えて無くても動作保証はないけど。

コーディングスタイルがあり得ない!って言うのはスルーするけど、
LINQとかRxとかAsyncはぜ〜んぜん使えてないのだ。
せっかくAsync CTP入れたのにね!(謎)

this.RFBClient = new EmpressiaRFBClient();
int[] encodings = new int[] { EncodingType.tight, EncodingType.ZRLE, EncodingType.zlib, EncodingType.zlibhex, EncodingType.CoRRE, EncodingType.RRE, EncodingType.Raw, EncodingType.Hextile, EncodingType.Cursor };

// 1.セットアップでいろいろ準備。
this.RFBClient.setup(
// 1−1.使う通信方式(エンコーディング)の設定。
encodings,
// 1−2.カーソルをクライアントで描画する。
(PixelFormat, x, y, width, height, pixelBytes, maskBytes) => {
}
// 1−3.EncodingType.CopyRectを使用する場合はもう一個引数増える。
);
this.RFBClient.ConnectFailed += (sender, e) => {
if(e.IsCanceled) {
return;
}
string message = null;
if(e.SecurityResult != null) {
if(e.SecurityResult.FailedReason != null) {
message = e.SecurityResult.FailedReason;
}
}
if(message == null) {
if(e.UnexpectedException != null) {
message = e.UnexpectedException.Message;
} else {
message = "なんか接続に失敗したみたい。ごめんなさい。理由はよくわかんない。";
}
}
this.RaiseDisconnected(message);
};
this.RFBClient.SendFailed += (ex) => {
this.RaiseDisconnected(ex.Message);
};
this.RFBClient.ReceiveFailed += (ex) => {
this.RaiseDisconnected(ex.Message);
};
this.RFBClient.FrameBufferInitialized += (PixelFormat, width, height) => {
// 2.画面情報の初期化。
AutoResetEvent Lock = new AutoResetEvent(false);
this.Dispatcher.BeginInvoke((EmpressiaRFBClient.FrameBufferInitializedHandler)delegate {
// 2−1.Windows PhoneだとARGB32が楽。違う場合は要求を送信するよ。
PixelFormat ARGB32 = new PixelFormat() {
BitsPerPixel = 32,
Depth = 24,
BigEndianFlag = 0,
TrueColourFlag = 1,
RedMax = 255,
GreenMax = 255,
BlueMax = 255,
RedShift = 16,
GreenShift = 8,
BlueShift = 0,
Padding1 = 0,
Padding2 = 0,
Padding3 = 0,
};
if(PixelFormat.Equals(ARGB32) == false) {
this.RFBClient.sendSetPixelFormat(ARGB32);
}
this.Image = new WriteableBitmap(this.RFBClient.FrameBufferWidth, this.RFBClient.FrameBufferHeight);
Lock.Set();
}, PixelFormat, width, height);
Lock.WaitOne();
};
this.RFBClient.MessageReceivingStarted += () => {
// 3.初回だけリクエストのタイミングを決める。2回目以降は勝手に呼ばれる。
this.RFBClient.sendFramebufferUpdateRequest(true, 0, 0, this.RFBClient.FrameBufferWidth, this.RFBClient.FrameBufferHeight);
};
this.RFBClient.ImageReceived += (s, rects) => {
lock(this.ImageEventLock) {
this.ImageLock.Reset();
this.Dispatcher.BeginInvoke((EmpressiaRFBClient.ImageReceivedHandler)delegate {
foreach(RFBRectangle rect in rects) {
// 4.透明なのを塗りつぶすよ。
for(int i = 3; i < rect.PixelBytes.Length; i += 4) {
rect.PixelBytes[i] = 0xFF;
}
for(int lineIndex = 0; lineIndex < rect.Height; ++lineIndex) {
Buffer.BlockCopy(rect.PixelBytes, lineIndex * rect.Stride, this.Image.Pixels, (rect.Y + lineIndex) * this.Image.PixelWidth * 4 + rect.X * 4, rect.Stride);
}
}
this.Image.Invalidate();
this.ImageLock.Set();
}, s, rects);
this.ImageLock.WaitOne();
}
};

this.RFBClient.connectAsync(Host, Port, Password);

重要そうなところは1〜4の番号を振ってコメント入れておいたっ。
1−2と1−3:
特殊な画像処理が必要なところ(クライアントの描画環境によるからRFBの範囲ではどうしようもない)。
2−1:
Windows PhoneのWriteableBitmapがARGB32(BGRA32?)だから楽するための処理ね。
わたしの作ったライブラリの一部がそれ前提なところが残ってる気もするし。
3:
コメント書いてて、これライブラリとしてダメじゃないカナーとか思った!
思ったけど今はこうなってるからいいよね(゚ー゚)(。_。)(゚-゚)(。_。)ウンウン
4:
RFBプロトコルは、透明度扱わないんだけど、
WriteableBitmapのARGB32だとアルファチャンネルってことになっちゃうから、
全部透過なしに上書きしてる。

あとは、xaml側と調整すれば画面が出るはず〜。
キー送信とか、マウスの操作は、
sendKeyEventとsendPointerEventっていうメソッドがあるから画面の操作と連携させればおっけ〜。
KeyEventは結構大変だけどねっ。マウス操作くらいならすぐすぐ。

是非試してみてね(  ̄▽ ̄)ノ

☆SSHプロトコル編☆

RFBプロトコルってパスワード部分をのぞけば暗号化されないから、
SSHでポートフォワードとかやりたいよね。
というか、Empressia Tunnelなんて作ってたから、
簡単にできるでしょ〜って思って、手を出してみたの。
まぁ、つまり大変でしたって話なんだけど……。

C#でSSHと言えば、SharpSSHとかが有名……だよね、
うん、わたしが知ってるくらいだから有名なの。
その、SharpSSH使おうと思ったんだけど、
これってJavaのJSchっていうライブラリの移植版みたいなんだよね。
元が結構古くて.NEtFramework1.1ベースみたい。

ってことで、ArrayListとかHashtableとかがWindows Phoneだと動かない。
Threadとかのメソッドも減って消えてるメソッドがあるからそのままじゃ使えないし。
BigIntegerもMono?のを使ってるみたいでこれがunsafeコードを持ってるんだよね。
結局、いろんなところ書き換えちゃった。

ほんとはそのまま動くようにするだけで良いんだろうけど、
元がJavaだからか、プロパティとかイベントとかがほとんど使われてなかったから、
めんどくさくて適当に書き換えちゃったところも。

RFBと同じでライブラリは最後にまとめて張るね。
まぁ、ポートフォワード付近しかタメしてなかったりするから、いろいろなところでエラーとか出るかも(笑)

あ、おまけでEmpressiaSSHなんてライブラリも作ったよ。
このライブラリを使うと、SECSH(ssh.com)形式の秘密鍵ファイルが使えるようになるの。
あと、ポートフォワードが簡単に使えるクラスEmpressiaSSHTunnelClientも用意してあるのでお試しアレ。
RFBみたいに使い方を紹介するよ。
もちろん動かなくても知らない!さすがわたし!無責任!

EmpressiaSSHTunnelClient SSHTunnelClient = new EmpressiaSSHTunnelClient();
userInfo.FingerprintConfirmationRequired += (string host, string type, string fingerprint) => {
return true;
};
userInfo.ChangedFingerprintConfirmationRequired += (string host, string type, string fingerprint) => {
return true;
};
SSHTunnelClient.Connected += delegate {
// 接続したよ。
};
SSHTunnelClient.Bound += delegate {
// ポートフォワードが開始されたよ。
};
SSHTunnelClient.ConnectionFailed += delegate {
// 接続に失敗したよ。
};
SSHTunnelClient.Disconnected += delegate {
// 切断されたよ。
};
SSHTunnelClient.Unbound += delegate {
// ポートフォワードが終わったよ。
};
EmpressiaUserInfo userInfo = new EmpressiaUserInfo("sshpassword");
SSHTunnelClient.connectAsync(new TransferProfile() {
TunnelHost = "example.com",
TunnelPort = 22,
TunnelUser = "sshuser",
TunnelPassword = "sshpassword",
LocalHost = "127.0.0.1",
LocalPort = 5900,
RemoteHost = "192.168.0.2",
RemotePort = 5900,
}, userInfo, null);
なんか、パスワード2回指定してるけど気にしない!

でもさ、結局、Windows PhoneってSocketのAcceptできないんだよね。
というわけでローカルポートにバインドできなくて今回はあきらめたっ_(__)ノ彡☆

あ、あと、SilverlightとWindows Phoneだと、SshShellのコンソールリダイレクトが使えないはず。
Console.OpenStandardInput()とConsole.OpenStandardOutput()をどうすればいいのかがわからなくて……。

☆基本ライブラリ編☆

SSHとかRFBをWindows Phoneで作る時に思ったんだけど、
Windows Phoneって結構標準のクラスライブラリが削られてて面倒なんだよね。
暗号系はBouncy Castleあたりがあれば良いんだけど、ネットワーク関連がどうしようもなくて……。
ってことで、NetworkStreamとか作ってみてるよ。
パフォーマンスは微妙だと思うけど、だいたい同じ感じで使えるはず……。

あと、リングバッファなByteQueueとか、
それをストリームで扱うEndlessStreamなんかもあるので良ければドーゾ。

EmpressiaLibrary.dllにまとめて入れてあるので興味があれば〜。
ライブラリはまたまた最後にまとめて張っておくね。

使い方は、別に特殊なのはないので省略ね。
……みんなはこういうのどうしてるんだろう……?(・_・?)ハテ

☆その他ライブラリ編☆

RFBやってると、ZlibなStreamを延々読み続けないといけないんだよね。
ただ1個のストリーム読むだけなら良いんだけど、
飛び飛びにあるピクセルデータ部分だけを連続したZlibなStreamとして扱わないとダメって感じ。
標準クラスライブラリのDeflateStreamを使ってる分には問題ないんだけど、
DotNetZipのDeflateStreamだと、これがうまく動かないっ。
というわけでこれも書き換えてみたよ。
まぁ、使う機会はほとんどないと思うけど、後で張っておくね!

Bouncy CastleもWindows Phoneで動くように書き換えたのでこれも張っておくよ。

☆ライブラリまとめ☆

ず〜っとライブラリの話書いてきたけど、下に関連してる図を載せておくね。
EmpressiaLibraryDependencyGraph_20111224.png
であとは、ライブラリ達でーす。

えっと、Silverlight版は、プロジェクトファイル用意するだけなんだけど、
わたしが使う予定がないので用意してなかったり!

動かないじゃんっていうのがあれば、再現できるサンプルとかあればがんばるよ!たぶん(・x・

☆余談☆

ところで、Vita用のSDKが来ないんだけど……。
って書こうと思ったら、昨日(23日)の15時頃に連絡があったよ。
やっと、開発環境周りの日本語訳ができたのかな〜。
というわけでPS Suite SDKダウンロードしてみた。
まだ何も作ってないけど、なんか作りにくそうだった……(・x・

タグ:Windows Phone
posted by すふぃあ at 00:34| Comment(0) | TrackBack(0) | 雁字

2011年12月08日

Windows Phone 7で暗号化

えっと、なんか、WP7の暗号化っていろいろ足りなかったりするよね。

たぶん、Phone7.FxとかBouncy Castleとかいろいろあるから、
何でも使えば良いんだと想うんだけど、

#wp7dev_jpで困っている人がいるみたいだったので、
とりあえず、Bouncy CastleをWP7で動くようにビルドしたのをおいてみたよ('-^*/

もちろん、ライセンスは、元の方を見て使ってね。
http://www.bouncycastle.org/
一応ビルドしたのはここね(゜▽、゜
http://www.empressia.jp/dll/BouncyCastle.Empressia.WindowsPhone.dll

こういうのはダメなんだよ!ってことはないとおもってるけど、
そういう情報があったら教えてね。速攻消すから。
あと、WP7で使っておかしくなっても、元の方に文句言わないでね。
タグ:Windows Phone
posted by すふぃあ at 23:09| Comment(0) | TrackBack(0) | 雁字

2011年10月30日

Windows PhoneのISEToolのGUIアプリ

Windows Phone OS 7.1 あたりで出てきたISEToolがCUIなので、
GUIで操作できるアプリを作ってみたよ。一通り必要な機能は入れたつもり。
この辺からダウンロードできるよ

リモートの表示がちょっと遅いんだよねぇ。階層が深ければ深いほど。
必要なときに読み込むようにしてあげた方が良いのかなぁ。
タグ:Windows Phone
posted by すふぃあ at 15:13| Comment(0) | TrackBack(0) | 雁字

2011年09月03日

MMDX(SlimDX版)のモデルロードを高速化

何となくぼーっと、MMDXを触ってみているよ。


Lat式ミクVer2.3を歩かせてみてるんだけど、ロード時間が長いので、ライブラリの速度アップをしてみました。


ここのリンクからダウンロードできるよ。


わたしのPC上でだけど、Lat式ミクVer2.3のロード時間が12秒→3秒くらいになた(゜▽、゜快適
タグ:MMD MMDX
posted by すふぃあ at 01:08| Comment(0) | TrackBack(0) | 雁字

2011年07月18日

WeldからJSFのViewScopedが使えるようになったみたい

Weld(CDI)とMojarra(JSF)の連携がGlassFish v3.1あたりで強化されているみたいなので確認してみたよ。



GlassFish v3のころは、連携が十分じゃなかったんだよね。

具体的には、@ManagedBeanに対して、@Injectが動かなかったの。

でも今は動くようになってる。




比較していくと、普通にWeld(CDI)の場合はこんな感じ。

テキストエディタで書いてるから間違ってたらごめんなさい。



@javax.inject.Named

@javax.enterprise.context.RequestScoped

public class HogeComponent {

  // CDIとしてDIされる。

  @javax.inject.Inject

  PiyoComponent piyo;

}


これでCDI管理の元で、Injectされる。

で、今までMojarra(JSF)で同じことやろうとすると、こんな感じ。


@javax.faces.bean.ManagedBean

@javax.faces.bean.ViewScoped

public class HogeComponent {

  // JSFとしてDIされる。

  @javax.faces.bean.ManagedProperty

  PiyoComponent piyo;

}

@Injectが使えなかったってこと。


ManagedBeanだと、CDI管理下に入らないから、

CDIがInjectするための@Injectが動かなかったんだと思う。


Weldの良いところは、なんでも@Injectで入れちゃうぞ、っていうことだから、

『ManagedBeanの方使わなければいいじゃん。』っていう話でもあったんだけど、

そうすると、ViewScopedが使えなくなるという……。



下のようなのは動かないってこと。



@javax.inject.Named

@javax.faces.bean.ViewScoped

public class HogeComponent {

  // GlassFish v3では動かない。

  @javax.inject.Inject

  PiyoComponent piyo;

}

このために、Weldで動くViewScopedを自作するというのをやってたんだけど、

GlassFish v3.1に載ってるWeldさんならそんな必要もなくなったみたい。

結局、下のでCDI管理下に入るようになったのかな。



@javax.faces.bean.ManagedBean

@javax.faces.bean.ViewScoped

public class HogeComponent {

  // GlassFish v3.1では動く。

  @javax.inject.Inject

  PiyoComponent piyo;

}

これで、Injectがちゃんとされる。JSF全体がCDI管理下に入った感じかな。

もうオリジナルなViewScopedはいらないね('-^*/


タグ:Weld CDI ViewScoped
posted by すふぃあ at 10:36| Comment(0) | TrackBack(0) | 雁字

2011年05月13日

AndroidのATOKでエラー やっとスタックトレース捕まえたよ

別にデバッグしたかった訳じゃないんだけど、Android版ATOKがなかなか更新がないので張ってみる。

激しく色々リークしてそうな……(゜▽、゜

今日バージョン上がったみたいだけど直ってないとおもうんだよねー。

裏の見えないところで色々リークしてそうだねー。



ERROR/Database(2392): Leak found

ERROR/Database(2392): java.lang.IllegalStateException: /data/data/com.justsystems.atokmobile.trial.sifications.db SQLiteDatabase created and never closed

ERROR/Database(2392): at android.database.sqlite.SQLiteDatabase.(SQLiteDatabase.java:1695)


ERROR/Database(2392): at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java

ERROR/Database(2392): at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatab

ERROR/Database(2392): at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatab

ERROR/Database(2392): at android.app.ApplicationContext.openOrCreateDatabase(ApplicationContext.

ERROR/Database(2392): at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java

ERROR/Database(2392): at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpen

ERROR/Database(2392): at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpen

ERROR/Database(2392): at com.justsystems.atokmobile.trial.common.c.a(Unknown Source)

ERROR/Database(2392): at com.justsystems.atokmobile.trial.service.AtokInputMethodService.onStart)

ERROR/Database(2392): at android.inputmethodservice.InputMethodService.doStartInput(InputMethodS

ERROR/Database(2392): at android.inputmethodservice.InputMethodService$InputMethodImpl.startInpu.java:354)

ERROR/Database(2392): at android.inputmethodservice.IInputMethodWrapper.executeMessage(IInputMet

ERROR/Database(2392): at com.android.internal.os.HandlerCaller$MyHandler.handleMessage(HandlerCa

ERROR/Database(2392): at android.os.Handler.dispatchMessage(Handler.java:99)

ERROR/Database(2392): at android.os.Looper.loop(Looper.java:123)

ERROR/Database(2392): at android.app.ActivityThread.main(ActivityThread.java:4370)

ERROR/Database(2392): at java.lang.reflect.Method.invokeNative(Native Method)

ERROR/Database(2392): at java.lang.reflect.Method.invoke(Method.java:521)

ERROR/Database(2392): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.j

ERROR/Database(2392): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)

ERROR/Database(2392): at dalvik.system.NativeStart.main(Native Method)
タグ:android
posted by すふぃあ at 21:04| Comment(1) | TrackBack(0) | 雁字

2011年05月02日

もしわたしがAndroidのFragmentを使ったら


さて、だいぶ更新あいちゃったけど、

Fragment APIを一通り使ってみたので、書いてみようと思うの。

いつものように、普通のその辺のチュートリアル記事とかじゃおもしろくないので、

わざとそれとは違うことを書くですよ。




まず、よく見るのは、Fragment使うと、UIがとっても便利!みたいな話だよね。

これは、たしかにタブレットなAndroidで重要で、そのためにFragmentが作られたみたいだし間違ってはいない……気がする。

でも……、見た目ばかり先行しちゃって、重要なことが本当に理解はされていないと思うんだよね。

つまりね、一番重要なのは、「ライフサイクル動作までの単位で再利用を可能にしたこと」だと思うの。




Dialogを例にしてみるよ。

今まで(Fragment APIが出るまで)は、Dialogは拡張できたけど、そのライフサイクル依存な動作は、Activityに書くしかなかったよね。

えっと、onResumeで決まった動作をするDialogとか作りたくても、その部分だけは、Activityに記述するしかなかったの。

同じような処理をいろんなアクティビティでやりたければ、Activityごとに全部書かないといけなかったってこと。

これはとっても再利用しにくいよね。




で、Fragmentがあるとどうなるかっていうと。

Fragmentにもライフサイクル機能があるから、onResumeでのその決まった動作は、ActivityじゃなくてFragmentの方にかける。

ってことは、Activityにはそのコードがなくなる。つまり、Activityごとに書いてた処理が一つのFragmentに寄せられるってわけ。

ライフサイクルのプラグインって感じね。まぁ、実際コード見ると、ActivityのonResumeで、FragmentのonResumeが呼ばれているわけだけど(笑)

これで、必要なコードは一カ所にまとめられて再利用しやすくなるの。




あ、そうそう、注意点があるよ。

あくまでもこれは、Activityに寄せられてたライフサイクルの記述をFragmentと言う単位に切り出せるようになっただけ。

よくListViewがListFragmentになるように見られることがあるみたいだけど(、まぁ、それは間違っていないんだけど)、

実際には、Activityに書かれてたコードがFragmentに寄るだけで、UIをカスタマイズしたらそのコードはFragmentとは別に用意することになる。

「Activity→Fragment→View」ってなるかな。クラスはFragmentの分増えるってこと。

間違えないようにしないとね。




もう一個重要なのは、上に書いたことから、ViewがないFragmentも作れるってこと。

ライフサイクルに沿ったバックグラウンド処理とかが、Acitivityから切り離したと言う意味で再利用可能な形で作れるってことだよ。

むしろ今は、こっちの方が重要な気がする(笑)




何でかっていうと、Fragment、なんかアニメーションがおかしいんだよね。

普通に設計ミス?みたいな感じがしてるけど(笑)

一応、「Android Issue 15623」あたりでググれば出てくると思うよ♪




適当にやってきた感じをまとめると以下のような感じかなー。あくまで個人的な感覚だからね〜(゜▽、゜

1.ダイアログ表示は積極的にDialogFragmentを使うようにする。

2.ListViewはライフサイクル制御が必要なときだけFragmentにすればok無駄にFragmentにする必要はない。

3.ライフサイクルに依存したバックグラウンド処理はFragment使うといい感じ。

4.アニメーションしたいなら、Issue 15623あたりに注意する。


タグ:android
posted by すふぃあ at 14:17| Comment(0) | TrackBack(0) | 雁字

2011年04月02日

AndroidでDialog〜DialogFragmentの使い方〜

〜前置き〜

前にAndroidのDialogの使い方についての記事書いたけど、
いくつかコメントもらったりしたので、新しい情報で書いてみようかな。
ちなみに、Fragmentについては、互換パッケージを使った場合だよ。

まず、Androidの表示の仕方の基本パターンだけど3つかな。

1.Activity#onCreateDialog(int)をオーバーライドして、Activity#showDialog(int)を呼び出す。
2.Activity#onCreateDialog(int, Bundle)をオーバーライドして、Activity#showDialog(int, Bundle)を使用する。
3.DialogFragmentを継承して、FragmentActivityに表示する。

ちょっと凝ったことをしたいなら、迷わず3かな。
それぞれの特徴を、個人的な視点で書いてみるね。

1の場合:

Android1.6(API Level4)で使える。
前の記事の通り、動的なパラメーター表示関連に激しく弱い。

2の場合:

Android2.2(API Level8)から使える。
弱点は、API Levelが高すぎること。

3の場合:

互換ライブラリがあれば、Android1.6から使える。
利点は、どこでもアクティビティのライフサイクルに載せられること。
弱点は、なんか無駄にくせがあること。あとドキュメントがさっぱりなこと。

ってことで、今なら、3が便利っぽいので3でやる場合の基本とノウハウ(?っていうのかな)を書いてみる。
いつも通り基本的なのは軽く流しちゃうけどっ。

〜定義編〜

DialogFragmentは抽象クラスじゃないけど、継承して使うの。
基本は、onCreateDialogをオーバーライドすればいいかな。
onCreateViewなんかもあるけどその辺は別にどうでもいいや(マテ)。

〜使用編〜

DialogFragmentのshowメソッドを使いましょう。
おわり。

簡単だよね!(゚ー゚)(。_。)(゚-゚)(。_。)ウンウン
……というのが一般的な説明な気がする。

Fragmentじゃない時のコードからの移行も簡単だよみたいになっているけど、表面上はって感じかな。
実際にアプリ作ってる側からすると、きっつぃ。
以下は、その辺の紹介だよ。

〜動的なパラメータ〜

Bundleを渡せそうなメソッドにsetArgumentがあるから、これ使えば良さそう。Javadocでもそんな感じだし。
ただ、onPrepareDialogみたいなのがないの!onCreateDialogしかないの!
Activityの時のキャッシュみたいな機能はなくなったのかな。それっぽい解説が全くないんだよね。
一応、動作としては毎回呼ばれるみたいだけど、onCreateDialogの中でgetArgumentするってことでいいのかな。
移行用ドキュメントちゃんと作ってほしいなぁ。それともわたしが読み飛ばしちゃってるのかしら。
むー(・x・

〜キャンセルリスナー〜

onCreateDialogあたりで、作ったダイアログにリスナーを登録する。
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
  @Override public void onCancel(DialogInterface dialog) {
    // do something
  }
});

こんな感じかな。動かしてみると……、はい、普通に呼ばれないね。
移行するとこんなのでいきなり躓くし。
なんか、DialogFragment#onCancelの方をオーバーライドしないとダメっぽい。

〜複数回のdismiss〜

ちょっと複雑なProgressDialogなんかを作る場合に起こりそう、っていうか起こったんだけど、
複数回DialogFragment#dismissを呼ぶと落ちる。

サンプルコードはこんなかんじ!
this.df.dismiss();
this.df.dismiss(); // 落ちる。
落ち方はこんなかんじ
Caused by: java.lang.NullPointerException
  at android.support.v4.app.DialogFragment.dismissInternal(DialogFragment.java:163)
  at android.support.v4.app.DialogFragment.dismiss(DialogFragment.java:149)

う〜みゅ、そのままだね!あ、いや、別に連続して書いてはいないけどね。
複数スレッドからダイアログを閉じたいだけなんだけど……。
Dialogの時は起きないのに。まったく……(゜▽、゜
ストリームとかだって複数回closeとか出来るようにするでしょう。普通……。
というわけで?以下のようにして解決。

this.df.onDismiss(this.df.getDialog());
this.df.onDismiss(this.df.getDialog()); // 落ちない。

まぁ、詳細は、DialogFragmentのソースコードでも見てください。二つのメソッドの実装とコメントを見れば一発かな。
実装依存なコーディングだからあまり良くないんだろうだけど、互換ライブラリだし、まぁ、いいかなって。
ていうか、dismiss呼ぶので落ちるのは個人的にイヤなんだんだけど……。
onDismissの実装見る限り、わざとやってるように見えるんだけど、どうしてなのかなぁ……。

全体的にFragment作るのに忙しくて互換性がぽいぽいっとされた感じ。
ま、いつものGoogleさんっぽいけど、これからもこういう感じなんだろうね。
だいじょうぶなのかな〜いろんな意味で(笑)

タグ:android
posted by すふぃあ at 19:47| Comment(0) | TrackBack(0) | 雁字

2011年02月20日

Androidのダイアログ表示でメモリリーク?

なんか、Androidでのダイアログ表示の仕方って、
いろんなサイト見ていると、AlertDialog.Builder#show()呼び出しているがすごく多い。
「Android ダイアログ 表示」とかで検索するとそれはもういっぱい引っかかる。

たしかに、それで表示は出来るんだけどさ。
正しくは動かないと思う。裏で。

showってメソッド、普通は、voidかbooleanだと思うの。
でも、Andoridだと、Dialogなインスタンスが戻ってくるの。
なんか疑問に思ったりしないかなぁ?

開発ガイドのダイアログ作成部分には、
AlertDialog#showなんてメソッドは一切記載がなかったりするんだけどね。
開発ガイド読んでないのかな。

まぁ、別に読んでないのはわたしも一緒だからいいんだけど、
やばいコードは余り広めない方がいいと思うんだよね。

え?ダイアログちゃんと表示されるじゃん、って人は、
開発環境とかでログを表示しながら、実際にダイアログを表示して、縦横切り替えをしてみるといいと思うの。
「android.view.WindowLeaked」って表示されるんじゃないかな〜。
いろいろ試して起きなければ、きっと、正しく作られてるから大丈夫だよ!

Dialogは、Activityの一部として扱われるから、Activityのライフサイクルにのせてあげないといけないの。
のせないなら、自前でちゃんと管理しないとダメってことね。

ライフサイクルにのせる方法は、ActivityのonCreateDialog(int)で生成してreturnで返してあげるしかないみたい。
Dialog#setOwnerActivityを使ってもダメだったから、今のところそれしか方法無いのかなーってわたしは思ってる。

ここで、showの返値がDialogになってる理由がちょっとわかる。
そう、AlertDialog.Builderでshowすると、返値がDialogじゃないとライフサイクルに載せられないってことね。

ちなみに、new AlertDialog.Builder(this)みたいにしてActivityセットしてるよ?って言う人は、
もう一度API見てください。引数がContextになってるはず。
なので、そこはActivityである必要はなく、ライフサイクルにものらない(のってもいい気はするけど)。

なので、自前で、管理しきる自身のない人は、onCreateDialog(int)でダイアログをreturnしてあげるといいと思う〜。

あ、そうそう、さっきの縦横切り替えで大丈夫じゃん。って思った人。
あと、縦横切り替えでダメなら、AndroidManifest.xmlのAcitivityの属性に、
「android:configChanges="orientation|keyboardHidden"」書けばいいじゃんって思った人。
RootActivity以外でDialog表示して、Homeキーとかおして別の重いアプリとか起動してみるといいんじゃないかなー。
きっと、裏でActivityが終了して同じエラーが出るよ(試してないけどね!)。

自信がなければ、Androidのダイアログは、onCreateDialog(int)で作りましょう。と言う話でした(・x・それだけっ
タグ:android
posted by すふぃあ at 13:25| Comment(4) | TrackBack(0) | 雁字