2013年9月10日火曜日

【Android】カスタムビューのカスタムオプションの値が取れない場合

まずは小生の整理のためにも軽くまとめ.

Androidでもカスタムビューを作ることができる.
Viewや,TextView,LinearLayoutを継承すればいい.
たとえばRelativeLayoutを継承し,
その中に画像とテキストとチェックボックスを含め
単一のビューにする,などといったことができる.


作成したビューはレイアウトxmlに配置することができ,
グラフィカルレイアウトの画面でどのように配置されたかを
プレビューすることもできる.
配置には普段は
<TextView />や<LinearLayout >...</LinearLayout>
とするところを,
例えばパッケージ「com.example.test」のカスタムビュー「CustomView」の場合
<com.example.test.CustomView />や
<com.example.test.CustomView>...</com.example.test.CustomView>
のようにして使う.

また,独自のオプションを作成することができる.
オプションというのはレイアウトファイルでよく使う
android:layout_width
みたいなやつで,
先の例でいうと,
チェックボックスを表示・非表示にする checkvisibility(仮) とか,
画像をグレースケール化する imagegray(仮) とか
自分の用途に応じていろいろなオプションを考えられる.

このオプションは
res/values/attrs.xml
内に記述する.
オプションは記述しただけではまだレイアウトファイルに使用できず,
xmlns:custom="http://schemas.android.com/apk/res/com.example.test"
(customという文字列は別になんでもいい)
といった記述をレイアウトファイルのルートレイアウト内にしなければいけない.
同じタグ内に
xmlns:android="http://schemas.android.com/apk/res/android"
というものがあるはずである.
SDKのオプションについて同じことをやってくれている.

そうすることで,
<com.example.test.CustomView
custom:checkvisibility="visible"
custom:imagegray="false" />
といった感じでオプションが使用できる.

オプションの値はカスタムビュークラス内で
TypedArrayのオブジェクトを使うことで得ることができる.

かなり端折ったがここから本題.


この一連の過程を行ったときに,
エラーも出ていないのに
eclipseのグラフィカルレイアウトでオプションの値が反映されない場合がある.
そういった場合の対処法としてはeclipseを再起動する.これ.
ちなみにプロジェクトのクリーンを行っても解決されない.
eclipseを再起動すること.

この現象が起こるキーはres/layout/attrs.xmlの編集である.
オプションを追加したり,削除したりでattrs.xmlを編集したなら,
eclipseを再起動することでグラフィカルレイアウトに反映することができる.

カスタムビューを作るにあたって,
SDKの各Viewがそうであるように,
コンストラクタ,onMeasure,onLayoutからの流れで完結するような
作りにしたほうが望ましい.
つまりレイアウトに配置したあとでソースコード側(Java側)から必要なお作法が無い
こういった作りが望ましいと思う.
これはSDKのViewのソースコードが本当に参考になる.
/frameworks/base/core/java/android/widget
下のクラスがそれである.

【Windows8.1】MSDNやTechNetサブスクリプション向けに公開されました

先日,Windows8.1のRTMは一部のHWパートナーのみ対象に公開を行い,
それ以外のMSDNやTechNetパートナーは一般消費者と同日の公開になってしまった.
という記事を投下したが,
9/9にそれが撤回されたようだ.

http://blogs.windows.com/windows/b/bloggingwindows/archive/2013/08/27/readying-windows-8-1-for-release.aspx
Based on the feedback from you and our partners, we’re pleased to announce that we will be making available our current Windows 8.1 and Windows 8.1 Pro RTM builds (as well as Windows Server 2012 R2 RTM builds) to the developer and IT professional communities via MSDN and TechNet subscriptions. 
発表する時点でフルボッコ炎上が当然見込まれるのに
実際にされると撤回する意志の弱さなら元からそういった決断をしなければいい.
心象が悪くなるだけである.
まぁ我々開発者からすれば結果オーライ,
Windows8.1での事前テストが行えるわけである.
(と入っても小生は現在Androidしかやってないので環境破壊のリスクを犯してまでは入れたくない)

良く言えばちゃんと客の話を聞き対応できる会社なんだなと
悪く言えばもうちょっと考えて決断してくれと
そんな印象である.

Preview版のときみたいにアップデータをくれたら嬉しいのだが.

ところで,小生のMSDNサブスクリプションのキー一覧を見ると,
Windows8,Windows8.1(Preview),Windows8.1がそれぞれ別ライセンスキーを与えられている.
Windows8→Windows8.1は無償アップデートされるので
Windows8.1を量産できる模様.
すごい.

2013年9月6日金曜日

【Java】ReaderとかInputStreamとか。

なんとなくで使ってたけど
その真意はつまづいてみないと分からない
という話.

HTTP接続したクライアントから送られてくる専用コマンドを
処理していくサーバーなのだが,
その流れてくるデータストリームの扱いに難儀した.
当初はGETコマンドの実装から始めていたので,
改行も取れるBufferedReaderでストリームを処理していた.
ちゃんと文字列でデータをくれるし,ヘッダの処理も楽.

つまづいたのが,POST,特にバイナリを受信する時だった.
画像バイナリを受信して,ファイルに書き出してみると
ところどころデータが化けている.
理由はBufferedReaderで得たchar配列をbyte配列に
キャストするときに起こっていた.

Javaのcharって2バイトなのな.
(signed)charって1バイトだろ.
#typedef unsigned charがbyteだろ.
とか思ってたけど言語によって違うんだな.

なるほど,BufferedReaderではバイナリを処理するのは厳しい
ということで,InputStreamで処理させよう.
でも他のコマンドの実装ができてるからヘッダはBufferedReaderで.

とかやってると,今度は化けることはなくなったものの,
バイナリの先頭部分がごっそりなくなっている.
BufferedReaderでバイト数指定してreadした直後に
InputStreamでreadしてるのに!
データストリームから取りこぼし?

これはBufferedReaderの動作原理を知っていれば
あたりまえだろ
というような動作である.
BufferedReaderのBufferedというのは
readメソッドでチマチマ1バイトずつ処理しようが,
先にバッファー領域にごそっとストリームを格納する.

ファイルアクセスで考えるとイメージしやすいか.
ファイルの読み込みを行うときに
1バイトずつ処理するのとして,
1バイト読み込み→1バイト処理→1バイト読み込み→1バイト処理→…
とやると1バイトずつファイルアクセスが発生して
とてつもなく遅くなる.
そのため,BufferedReaderではバッファ領域に
ファイルを(デフォルト値で8KB程度?)読み込んで
それをreadメソッドで読むという流れになっている.
こうすることで使用感はInputStreamなどと同じなのに
ファイルアクセス回数を減らしている.

つまり,ヘッダだけ読み込もうとBufferedReaderに
データストリームを任せた瞬間に
BufferedReaderのバッファ領域にはヘッダと一緒に
バイナリファイルの先頭部分も格納されていた.
InputStreamがデータストリームを読みに行こうとした時には
バイナリの途中からになっていた,ということである.
バイナリの先頭部分はBufferedReaderの破棄と共に
闇に消えたのである.

つまりは,Reader系で作ったのがそもそもの間違いであり,
複数のストリームクラスを併用しようとしたのも間違いだった.

結局,実装済部分も含めて
BufferedInputStreamだけで処理するように作りなおした.