2013年12月17日火曜日

【Android】BundleにでかいStringをあげたら死んだ

Activityをまたいである程度の大きさのリストを共有したい.
そこで,一番手っ取り早そうな方法を使った.
具体的には

====ActivityA
ArrayList<Hoge> bigList;
String json = Json.encode(bigList);
Intent intent = new Intent (this, ActivityB.class);
intent.putExtra ("BIGLIST", json);
startActivityForResult (intent, 666);

つまりActivityAクラスで大きなリストをJSON文字列化して
それをインテントに乗せてActivityBクラスへ渡し,
ActivityBクラス内でJSONからリストに戻していた.
このリストが(1件のデータはさほどの大きさではないが)500件ほどになると
以下のようなエラーを吐いて爆死した.

12-17 17:41:54.349: E/JavaBinder(282): !!! FAILED BINDER TRANSACTION !!!
12-17 17:41:54.349: W/ActivityManager(282): Exception when starting activity jp.mau.dummy/.activity.ActivityB
12-17 17:41:54.349: W/ActivityManager(282): android.os.TransactionTooLargeException
12-17 17:41:54.349: W/ActivityManager(282): at android.os.BinderProxy.transact(Native Method)
12-17 17:41:54.349: W/ActivityManager(282): at android.app.ApplicationThreadProxy.scheduleLaunchActivity(ApplicationThreadNative.java:705)
12-17 17:41:54.349: W/ActivityManager(282): at com.android.server.am.ActivityStack.realStartActivityLocked(ActivityStack.java:702)
12-17 17:41:54.349: W/ActivityManager(282): at com.android.server.am.ActivityStack.startSpecificActivityLocked(ActivityStack.java:811)
12-17 17:41:54.349: W/ActivityManager(282): at com.android.server.am.ActivityStack.resumeTopActivityLocked(ActivityStack.java:1759)
12-17 17:41:54.349: W/ActivityManager(282): at com.android.server.am.ActivityStack.resumeTopActivityLocked(ActivityStack.java:1393)
12-17 17:41:54.349: W/ActivityManager(282): at com.android.server.am.ActivityStack.completePauseLocked(ActivityStack.java:1141)
12-17 17:41:54.349: W/ActivityManager(282): at com.android.server.am.ActivityStack.activityPaused(ActivityStack.java:1039)
12-17 17:41:54.349: W/ActivityManager(282): at com.android.server.am.ActivityManagerService.activityPaused(ActivityManagerService.java:4309)
12-17 17:41:54.349: W/ActivityManager(282): at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:381)
12-17 17:41:54.349: W/ActivityManager(282): at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:1616)
12-17 17:41:54.349: W/ActivityManager(282): at android.os.Binder.execTransact(Binder.java:367)
12-17 17:41:54.349: W/ActivityManager(282): at dalvik.system.NativeStart.run(Native Method)

この現象自体は前々から把握しており,
そろそろ対策するかと何度も再現検証して初めて出たログである.
リストを大きくすると死ぬから原因自体は容易に想像できるが,
このTransactionTooLargeExceptionという例外クラス名を見れたのは大きい.

対策はまだしていないが,以下のような方法が考えられる.

1.リストが絶対に100件程度で収まる場合
無対策でそのままJson化して受け手側で展開すればOK.
しかし受け手側で展開したリストと送り手が持っていたリストは別物であり
メモリ上に重複しているということを覚えておく必要がある.
巨大なデータを2つも持ちたくはないし,
受け手側でした変更を送り手側に反映するためには
受け手側で再度JSON化して送り手側に返す必要がある.

2.リストがまぁそれなりの大きさで済んでくれる場合
メモリ上にリストを全部展開しても生き残れる程度に確実に収まる場合は
調べたところではSerializableを継承したクラスにリストを配置し,
それを受け渡すことで回避できるらしい.
ただ,やってることは1.とさほど変わらず,
Stringというプリミティブオブジェクトを渡すのか,
Serializeされたストリームを渡すのかの違いで
受け手側で展開して多重化されるのは変わらないらしい.

3.リストが青天井の場合
ArrayListなんてつかわずにおとなしくDB化しよう.
インテントもDBのURL渡すだけでいい.
ArrayAdapterとか使ってたら改造が大変だけど,
やる実は大きいと思う.
DBは使わなくなったら棄てるようにしよう.


…と今日考えたこと.
まだ(改造がめんどくさくて)実装していないがこれからDB化していく.
はぁ…

【Android】にこちゃんねる ニコニコ風2ちゃんブラウザ

小生の拙作,にこちゃんねる というAndroidアプリを公開した
いや,少し前にしていたので紹介させていただきたく.


にこちゃんねる -ニコニコ風2ちゃんねるブラウザ-
2013年12月2日 Ver.1 公開

にこちゃんねる は簡単にいうと
ニコニコ動画のようにレスがスクロール表示される2ちゃんブラウザ
です.


他のアプリの上にスクロール表示できるので,
ゲームをしながらレスを流し読みしたり
ツイッターアプリを表示したままレスの確認をしたりできます.

ワンセグやフルセグ対応機種であれば
テレビを見ながら実況板を表示することで
実況民の感想を即座に見ることができます.

スレは4スレまで一度に巡回できます.
それぞれ背景色で分けているので
レスがどのスレについたものか判別できます.
巡回中スレッドの横にアイコンが表示されますが,それと同じ背景色でスクロールします.

自由に板を登録できるテレビリモコン配置のショートカットもあります.
初期配置ではご覧のとおりの設定になっております.
べっ…別に実況専用ではないんだからね!


さあ,これはべんり!楽しい!今すぐダウンロード!
にこちゃんねる -ニコニコ風2ちゃんねるブラウザ-

2013年11月6日水曜日

【Android】ビューの背景や文字をタッチした時だけ変更する(on Java)

こんなの簡単やろーと思っていたら
案外ハマってしまったのでポスト.

しかも調べてもレイアウトをxmlで記述する方法ばかりで
Javaで記述する方法は出てこない.

TextViewなどのViewで
背景と文字をタッチしている時だけ変更する…

xmlからだと
android:text_color
android:backgruond
で処理できるのだが,
ソースから実現しようとするといろいろとこんがらがった.

色はリソースファイルで持たせている.
これはxml.
selectorを使った色をjavaでどう受けるのかというのがポイント.
まずはリソースファイル.

文字色
/res/color/general_color_text_menu.xml

背景色
/res/color/general_color_bg_menu.xml

文字色と背景色とで記述方法が違うのに注意
文字色は<item>タグだけで記述するが,
背景色は<color>タグを<item>タグでラップする必要がある.

なお,今回はandroid:colorの値もリソースファイルを指定しているが,
値指定("#000000"みたいなの)でも問題ない.

で,じつは悩んだわりには難しくなかった.
受けるjavaは以下のように記述すればいい.

背景色をgetDrawable()で受けて,
文字色をgetColorStateList()で受けている.

文字色と背景色とでxmlの記述方法が違うのは
そこらへんの違いなのかもしれない.

2013年10月18日金曜日

【Windows8.1】Preview版から正式版へ

昨日10/17 20:00に公開された
Windows8.1正式版.
20:00まで張って速攻インストールを試していたのに
アクセスできずに結局昨日は離脱.
今日もアクセス状況がよろしいとは言い難い.
明日になれば落ち着くとは思うが.


さて,Preview版から正式版へアップデートする方法であるが,


その前に予め書いておくと,このステップを経ても
インストールしたアプリが一切消去される
ストアー経由だから~と消えないつもりでいたら全滅した.
デスクトップのアプリのことである.
Firefoxが消えるのでブックマークを退避させる,だとか
Skypeが消えるのでチャットログDBを退避させる,だとか
(小生はメールクライアント入れてないから知らんが)メールも消えるかもしれない.
今インストールしているアプリを把握しておく必要もある.
ドキュメントが消えるわけではないので,
インストールしないタイプの実行ファイルは安全.
eclipseは後者のため助かった.
…が,何が起きてもいいように重要なファイルや設定情報は
外付けストレージなどに退避させてから更新を行うことを推奨する.今回は割と本気で.
ストアアプリのことかと思ったら大間違い.デスクトップアプリも全滅した.
この後,ウチのVAIO E14PもPreview版→正式版にアップデートしたところ,
メーカー製ドライバも全て消えた.
そらそうだ.
輝度調整やキーボードバックライトはもちろん,
VAIO UPDATEも動かん,これじゃVAIOの意味が無い
ということで,必要なデータだけ外付けHDDに撤退させて
購入時の状態にレストアしたよ…
リカバリディスク作ってなかったけど
購入後すぐにHDD換装してたからその当時のが残ってた.
メーカー製PCにPreview版入れた人は覚悟すべしってことだな.


Windows8から8.1Previewへストア経由でアップデートした場合は
今回もストア経由で正式版へアップデートできるようだが,
ストアにWindows8.1正式版のアイコンが出てこない(と思う).
http://apps.microsoft.com#wsl=WindowsUpgrade
へアクセスしろとWindows Blogには書いてあるが,
ここのリダイレクト?がとてつもなく調子が悪いので
ms-windows-store:WindowsUpgrade
をブラウザのURL欄に入力してEnterでストアが開く.


起動するプログラムを選択しろと言われたら
既定で選択されているであろうTWINUIというものを選択すればいい.


開いたストア画面で【ダウンロード】を選択すると
ダウンロードが開始されるのだが,
画面としてはストアのホーム画面へ遷移するだけで
どこにも作業進捗が表示されない.

進捗が表示されないが,ちゃんとダウンロードをしているので
そのまま放置しててよい.

これ本当にどこにも表示されないんだな.
Windows Updateとかいろいろ確認したんだが.

強いて言えば,タスクマネージャーでネットワークを使用しているサービスを見ると
一匹ネットワークをガリガリ使っているサービスホストがいて,
そいつの中にWindows Updateとか書いてあるやつがいるからこいつかもしれない.


放置していると再起動を促されるので
再起動すると,Windowsの初期設定を行うことになる.


初期設定が完了して驚いたのは
先にも書いたのだが,スタートメニューがやけにガランとしている.

ストアアプリだけではなく,デスクトップアプリも全滅.
インストールしないタイプの実行ファイルだけ配布したアプリは無事.
ドキュメントも無事.
これでAndroidのプロジェクトが吹き飛んだら3日は寝込んだはず.


一方で,ISOからWindows8.1をインストールした場合は
一旦以前の環境に戻す必用があるようだ.
コレはめんどくさい.(やらなくてよかった…)
http://windows.microsoft.com/ja-jp/windows-8/update-from-preview

2013年10月1日火曜日

【jQuery】ブロックサイズに合わせて画像をフィット表示

jQueryも勉強.
はるーか昔にJavascriptで画面遷移なしに表示の更新…
などはやっていたのだが,サクっと忘れており
Ajaxを勉強するためにJavascriptも勉強.
jQuery?はナニソレ状態からスタート.
(響き的にDBを扱う何かかと思ってた…)

今回やるのは
エリア内に画像を表示させるが,
縦横比を崩さずにできるだけ大きく表示する.
ということ.

CSSだけだとどうしても縦横比が崩れるか画面いっぱい表示されないか
という結果になったが,
ブロックのサイズが取得でき,
ウインドウサイズ更新のたびに操作をできる
Javascriptって便利だな.

今回,
画像を配置するブロックをid="area"
画像自身をid="item"
とする.

これを描画時とウインドウサイズ更新時に呼び出す.

何も考えずにCやJavaなどと同じような文法で掛けるのって素敵.

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だけで処理するように作りなおした.

2013年8月28日水曜日

【C】URLデコードする(UTF-8)

独自鯖を作ってる最中,
クライアントからのpostリクエストボディに「\r\n」も「\0」も何も終端記号が含まれず
feof()とかで終了条件設定しててもむだで
そのままだとfgetc()なりfgets()なりのところで固まってしまうため
Content-Lengthの分だけ監視する必要があった
…のにもまず驚かされたが,
マルチバイト文字がURLエンコード(パーセントエンコード)されることを忘れていて
デコーダを実装するのに軽く絶望していた.

が,こんな簡単に実装できるとは.

まずはUTF-8のおさらい.
Wikipedia[UTF-8]の表を見る.
ん,そういえばこれどこかでやったな…
と,思ったが,残念ながら以前やったのはUTF-16toUTF-8だった.
しかし,土台部分や考えは流用できそうだ.

%XX%XX%XX%XX…と続くエンコード文字列のまず先頭を取得する.
先頭の%XXこいつのXX部分を見て,Wikipediaの表と対応させて
それが0x80未満なら1byte.
0xC2-0xDFなら2bytes.
0xE0-0xEFであれば3bytes…
まぁ4bytes以上の文字は置いといてそんな感じか.
1byteということは%XXこれが1文字.
2bytesということは%XX%XXこれで1文字,
3bytesも同様に%XX%XX%XXこれで1文字.
UTF-8というのは1文字のバイト長が1byte~6bytesという可変長で表現される.

URLエンコードではそのバイト列をバイトずつ区切って,
頭に%をつけてASCII文字のみで送れるようにしたものである.
また,半角スペースが「+」に変換される.

URLデコードではその逆をやる.
まず「+」を全て半角スペースに置き換える.
次に1つ目の%を探して次の2文字を取得する.
こいつの値を見て,その文字が何バイト続くかを判定,
そのバイト分取得したら文字に直す.

…と言葉で書くよりプログラムで書いたほうがわかりやすいな.
今回のプログラムではURLデコードを行うurlDecode関数と,
文字列を置換するreplace関数がある(「+」を半角スペースに直すため用いる).


【Windows8.1】MSDNでもWin8.1RTM配布は10/18

あまりにも反対が多すぎたためか9/9に撤回されました.
9/10現在MSDNパートナーにWindows8.1 RTM公開がされています.

Windows8.1及び8.1RTのリリースがHWパートナーに対し行われた.
従来,MSDNやTechNetでの配布も2週間以内には行われていた.


Windows 8
RTM: 2012-08-01, MSDN/TechNet Availability: 2012-08-15, GA: 2012-10-26

Windows 7
RTM: 2009-07-22, MSDN/TechNet Availability: 2009-08-06, GA: 2009-10-22

Windows Vista
RTM: 2006-11-08, MSDN/TechNet Availability: 2006-11-17, GA: 2007-01-30


ということはもう数週間以内にはMSDNやTechNetではRTMが入手可能に…
と思いたかったのだが,
今回はどうもそうはいかないようである.

ソースはWindows Blog.
http://blogs.windows.com/windows/b/bloggingwindows/archive/2013/08/27/readying-windows-8-1-for-release.aspx

While our partners are preparing these exciting new devices
we will continue to work closely with them as we put
the finishing touches on Windows 8.1 to ensure a quality
experience at general availability on October 18th.
This is the date when Windows 8.1 will be broadly available for
commercial customers with or without volume licensing agreements,
our broad partner ecosystem, subscribers to MSDN and TechNet,
as well as consumers.

暴訳すると,HWパートナーにはWindows8.1は配った.
サブスクライバは一般消費者と同じ10/18な!
といったところか.

コレに対し,其のWindows Blogでのコメント.

controlz controlz 145 Posts
August 27, 2013
I'm disappointed that it won't be available on TechNet until October - it may not be perfectly stable yet, but the RTM build is surely more stable and complete than the preview build (9431) or the recently leaked 9471 build.
「10月まで手に入らないのは失望したわ.Preview版とか最近リークされた9471ビルド版みたいにRTMも不完全なんじゃね」

segobi segobi 0 Posts
August 27, 2013
Congratulations for releasing it to Technet and MSDN so late. You are losing your partners.
「サブスクライバへの悪対応おめでとう!パートナー失うわ」

…以下,サブスクライバへの先行リリースがなくなったことに対する
皮肉と失望の渦巻くコメント欄であった.

そりゃあシステム屋としては8.1リリースと共に新OSを勧めることが難しくなるし,
SW屋やPCメーカー以外のHW屋も即対応を謳うことができなくなる.
そうするとユーザーの導入も伸びづらくなる.

まぁサービスパックと考えるとこれまでが大げさな対応だったのかもしれない.
Vista→7以上にSP感がするし.
これはWindows8SP1だ…Windows8SP1…SP1…


わざわざWindows離れを加速させてる気がしなくもない.

2013年8月27日火曜日

【未検証】モバイルブラウザの不都合な動作

未検証シリーズ.検証するつもりもない.
ここ数日,クロスブラウザと闘い続けているのだが,
(デスクトップブラウザが正しいとすれば)想定外の動作をしてくれることがある.

iOS SafariでiframeのVisibilityがおかしい
<iframe ~~~~ style="visibility:hidden"></iframe>
といった形でiframeにhiddenを設定し,
JavascriptからvisibilityをvisibleにしたりhiddenにしたりするようなHTML.
突然iframeが表示されることがあり,
また,iframeは表示したらhiddenにしても非表示にならない.
なお,デスクトップブラウザやAndroidブラウザではちゃんと非表示になる.
iframeを使うのがそもそもの間違いなんだろうが,
Google Mapsの埋め込みはiframeを使うんだよな.
opacityで非表示にしたりz-indexでレイアウトの後ろにしたり
そういったことで対応できるのかもしれない.
モバイルブラウザ的には埋め込みの表示/非表示ではなく,
Google Mapsのサイトへのリンクが正解なのではと思い,リンクを貼ることにした.

Android 標準ブラウザの画像に対するmax-heightの挙動
<img ~~~ style="max-height:100%" />
といった形で画像をブラウザサイズに抑制する場合,
ページロード時に表示されるアドレスバーの領域を除いて100%と計算される.
まずはまぁこれはいい.
アドレスバーは描画領域に含まれないんだからちゃんと描画している部分が100%だから正しい.
しかし,この状態で画面を引き上げ,アドレスバーをスクロールアウトさせると,
ブロックはスクロール後のより広くなった領域を100%と考えているのに,
imgは描画がおかしくなる.
具体的には描画領域の高さが変更されたのは確認したが,
画像の高さを反映させずに幅だけ変更させる.
つまり,画像が横に伸びるのだ.
スクロールさせて表示するような作りのページならいいが,
1枚絵を表示させるだけのページだと,できれば絵を画面内に収めたい.
だからmax-height指定して画面内に収めたのにアドレスバーが変な挙動を誘発させる.
これは今のところお手上げ.

2013年8月26日月曜日

【Windows8.1 RP】RT版のIEは横スクロールを避けるように作られている

Modern UI(旧称:Metro Style)のIEは横スクロールを避けるように作られている.
可能な限り.

今回のエントリは画像がメイン.
(領域の)大きい画像が続くので拡大しないと分かりづらいかも.

Webサーバを作っていて,クロスブラウザのレイアウトを目指すため
いろいろなブラウザで動作を確認していたのだが,
Modern UI版IEの挙動が面白かったのでメモ.

Modern UIといえばWindows8で導入された
フルスクリーンアプリのプラットフォームである.

他のモバイルプラットフォームでは同時起動アプリは1つのものが多いが,
Modern UIでは左右どちらかに細長い画面でアプリを配置して,
狭い領域と広い領域の2つまで同時にアプリを表示させることができる.
これをスナップというのだが,
Windows8ではそのスナップする狭い領域のアプリの幅は固定されていた.
Windows8.1(Preview)ではそのスナップが進化し,
アプリの幅をユーザがある程度自由に動かすことができるようになった.
これは過去のエントリでも書いている.

そこで,フルスクリーン状態のIE,スナップ状態のIEと
いろいろなサイズで独自Webサーバの挙動を見てみて,
レイアウト崩れが起きないか確認していた.

今回テストで用意したHTMLファイルの内容は以下のとおりである.


青の領域は本来のディスプレイの半分の領域で,
今回使用しているディスプレイが1920x1200なので,960x1200の領域である.
赤の領域はナゾの領域(後述)で1024x1295の領域である.
緑の領域は何でもいいから大きいの,ということで,
4k2kの3840x2160の領域である.

まずはフルスクリーン状態(幅1920)で表示するとこんな感じ.
青領域下部の枠線がぴったり表示されているのが分かる.
フルスクリーン状態


次に,その状態からだんだんと幅を狭くしていこう.
幅1397
幅1397


幅1308
幅1308


…と綺麗に幅のみが縮小しているのが分かる.
幅を削ったのだから幅が減るのは当然で,
この挙動がWebUIとして想定される挙動である.

先ほどの状態から更に幅を減らすと,
幅を自由に決められず,
自動的にディスプレイの半分のサイズになる領域になる.

アプリとアプリの間にスペーサーがあるのでディスプレイの丁度半分の幅ではないが,
幅949
ディスプレイの半分の幅


さて,ここで高さが変わってしまった.
(アプリの高さが青線よりも高くなった…というか縮小された)
後述すると書いたナゾの領域の幅・高さになったのである.
この赤領域の数値はナゾであって,
HTMLで指定した値はピクセル調整して丁度になった値なのである.

そこから更に幅を狭めていくと,
より縮小が進んで
幅811
幅811


幅569ではとうとう4k2kサイズの高さに並び,
幅569


最終的には
幅320(これ以上は縮小できない)
最小幅


こんな状態になった.
特筆すべきなのは縮小率は固定で,
半分の状態の赤枠の幅が表示されたまま縮小されていく.

つまり,Modern UI版IEでは
スナップ幅がディスプレイの半分以下になると
その幅のまま表示が縮小される.
幅が固定なので,変な作りにしない限り
横にスクロールすることはほぼないだろう.
ただし,幅を狭くしていくと表示倍率が下がっていくため,
文字が豆粒になっていくのである.
読めない…

2013年8月23日金曜日

【Android】View.INVISIBLEとView.GONEの違い

さきほどのエントリでView.INVISIBLEとView.GONEについて触れたが,
この2つ,一言で表せば
「VIEWを消す」
で同じなのだが,
厳密には大きく違う.

INVISIBLEに関しては,
触れないし(Clickイベント等が発行されない),見えないけど,確かにそこにいる
オカルティックな存在.

GONEは
アイツはもう消した!
というだからお前は誰なんだよという存在.

分かりづらいかと思うので,サンプルアプリを作ってキャプチャしてみた.

1つめの例
LinearLayoutの中に
RとGとBのTextViewがある状態.
RとBはそれぞれ50dipの幅を持っており,
Gはlayout_weight指定してその残りを占めるようにしている.
ボタンはBの処遇を決めるボタンである.

B:Visible



B:Invisible



B:Gone

これで分かるのが,
Bが消えたときにInvisible/GoneとでGの挙動が違う.
Invisibleの場合は見えなくなったけど配置としてそこにBがあるという判定で
Gは振舞っているが,
Goneの場合は配置からBが消された状態で
GがBのあった場所も占めるようになっている.

これでどう実践的になるかというと,
例えば画面上部にタイトル,進むボタン,戻るボタンがあるようなUIを考える.
さきほどの例と同じようなUIなのだが.
そんななかである条件で進むボタンや戻るボタンを非表示にしたい.
といったときに,Goneを指定してしまうとタイトルがセンターからずれる.
Goneを指定してセンターからずれた状態
タイトルはセンターを死守して欲しい場合はInvisibleを使うべきである.
Invisibleならセンターのままでいてくれる


2つめの例
先程はLinearLayoutだったが,今回はRelativeLayout.
RelativeLayoutでレイアウト依存される側のViewが消えた場合にどうなるか.
今回はGをRelativeLayoutのCenterに配置し,
Gの左にRを,Gの右にBを配置.
ボタンによってGの処遇を決定する.

G:Visible



G:Invisible



G:Gone


Invisibleはレイアウトが崩れなかったが,
GoneにするとGの配置に依存していたBやRが行き場をなくして
親であるRelativeLayoutの左上に配置された.

これは注意すべきである.

こう見ると,InvisibleもGoneも一言でいえば確かに
「Viewを消す」
なのだが,圧倒的に使い方を考えなければいけないことが分かる.


ちなみにこの他に「消す」ことのできるメソッドとして
・setAlpha ※API LV.11~
・setAnimation(AlphaAnimation)
があるが,これらは共に半透過を扱うものであるため,
完全に消しても実物はそこに存在し,
レイアウトに影響を及ぼさず,
触れる(クリックイベント等が発生する)
見えないだけである.


【Android】Spinnerは配置しないとイベント発行しない

表題でSpinnerと書いたが,あらゆるViewがそうかもしれない.
Spinner(いわゆるドロップダウンリスト)では
OnItemSelectedListenerを使って,選択即反映をさせることが多い.
リストのアイテムが選択されたときに発行されるイベントである.
そのイベントだが,Spinner自体をActivityに配置しないと発行されない.

配置しないとそもそもドロップダウンリストが表示できない…
というわけではないから悩むことになった.
具体的には


別に用意したTextViewをクリックするとリストだけ表示する場合.
Spinnerは画面に配置せずに,
TextViewがクリックされたときにperformClickメソッドでSpinnerを叩く.
(このperformClickメソッドはViewからの継承のため,他のViewでも使えるはず.)
すると,リストは表示される.
リストが多いとスクロールもできるし,
タップすれば選択色が光ってリストも消える.
まるでちゃんと動作しているようにみえる.

しかし,OnItemSelectedイベントは飛んでこない.

ここで,Spinnerを画面に配置してやる必要があった.
これは配置サイズが0dipでもいいし,
Visibility:INVISIBLEでもいい.

ただし,配置してないのと同様の扱いになるVisibility:GONEではやはり
イベントが発生しない.

width/heightともに0dipに設定した上でVisibility:INVISIBLEに指定した
Spinnerをレイアウト最下部に配置することにした.

余談だが,Spinnerは画面に配置されると同時に
position:0選択のイベントが発行されるらしく,
何らかの処理を設定していたらそれに注意が必要である.
選択してActivityを移動とかの処理を入れていると
配置と同時にActivity移動なんてことになりかねない.

2013年8月21日水曜日

【Server】Content-Lengthをきちんと指定しないとインライン画像が表示されない

今回はHTTPサーバのハナシ.
HTTPサーバなんてApache使えばいいから基本知らなくていいことなんだろうけど
特殊鯖を作るとなるとそういうわけにもいかない.

IMGタグなんかでウェブサイト内に表示する画像,
つまりインライン画像が表示されないことがある.
ことがある…というのも,ブラウザ環境に左右されるのである.

Firefox23,Android2.1 標準ブラウザ,iOS6 Safari
ではちゃんと表示されるのに
Chrome28/29,Android4.0 Chrome
では表示されない.
おかしいな,MIMETYPEもちゃんと指定しているし…
と調べまわった結果,
インラインではサムネイルを表示させるのに,
Content-Lengthは元画像のサイズを送っていたことが判明.
(90*90のサムネイルなのに4MBとかいうContent-Lengthを送っていた)
つまり鯖のミスだったのである.
Chromeはそこんところ厳格らしい.

Content-Lengthはこのサイズだろ?
俺がもらったのと違うぜ,壊れてんじゃね?
ひょっとしたらウイルスとかなんかなんじゃね?
ってことなのかもしれない.

Content-LengthをきちんとChromeに送ってやったら
インラインで表示された,めでたしめでたし.

2013年8月7日水曜日

【Android】Serviceを設定したら終わらせよう

AndroidのWidgetを作る場合には
クリックイベントを処理したり,
はたまた時計を作ろうとAlarmManagerをセットしたり
Activityを作るのと違ってServiceを多用することになると思う.


こんな感じでサービスを登録するが,
サービスはアプリ(Activity/Widget)を終了させても終わってくれない.
再起動するか,
ユーザが手動で【設定>アプリ>実行中】から停止するかしない限り
サービスが残りっぱなしになる.

時計ウィジェットを作ろうとAlarmManagerを再帰呼び出しさせた日には
サービスを手動で終了させても次のアラーム時にサービスが勝手に復帰する.
こうなったらアプリをアンインストールするか
再起動するかしないと消えない.

なので,アプリを終了するときにサービスを停止させよう.
ウィジェットならばウィジェットがHOME配置から消されたら終了させよう.

ウィジェットの場合,HOME配置から消されるとonDeletedイベントが発生する.
なので,onDeletedをオーバーライドして,
上記の例に倣うと


サービスを登録したときと同じ方法でIntentを宣言し,
stopServiceを呼び出す.
これでサービスの停止が完了である.

なお,サービス登録時にIntentを作成しているからといって
Intentをクラスフィールドにして停止のときもそのまま再利用~
などと考えてもIntentの中身はnullになっているため,不可能である.
クラスフィールドにしてもいいが,
再度Intentのコンストラクタを呼ばないといけない.

開始と停止とで(作り方は同じだとしても)違うオブジェクトを作って
それで本当に停止できるのかとちょっとオブジェクト指向の考えからいくと
不安になるかもだが,これで停止ができるのである.

次に,時計ウィジェットなどでアラームを設定した場合にも
作成時と同じ方法で
Intent/PendingIntent/AlarmManagerを作成し,
キャンセルしてやることで解除される.
すなわち,


このようにセットしたのなら


このようにキャンセルすることになる.
サービスの停止の前にアラームの解除をする必要がある
IntentのsetActionも解除時に必要.
このsetActionが足りなくても解除に失敗する.

何度「まだいる!」と思わされたことか.

2013年7月31日水曜日

【Android】ViewPagerで現在表示しているViewを取得する

ViewPagerの上にメニューレイアウトがあったりして
そのメニューレイアウトからViewPagerが表示しているコンテンツに操作を行いたいとき…

例を出すと
ViewPagerといえばギャラリーアプリ的なのを想起しやすいため
そのギャラリーアプリで考えると
メニューから拡大縮小,回転,グレースケール化などなどをする場合
なんてものが挙げられるが

ViewPagerの外からViewPager(実際はPagerAdapterだが)が
管理するコンテンツにアクセスしたいことがある.

各ページにメニューを配置しても実装はできるが…
それはさすがにスマートじゃない.


ViewPagerを使う場合はPagerAdapterのサブクラスを作ることが必須だが,
そのPagerAdapterにはsetPrimaryItemというメソッドがある.
読んで字の通り,アイテムを表示するときに呼ばれるメソッドである.
開発者が気にすることではないのだろうが
きっとViewPagerが呼んでいるのだろう.

instantiateItemメソッドなどと違い,
Abstract指定されていないので継承は必須ではないこのメソッド.
これを使えば表示されているViewの取得ができる.

今回はViewPager直下をRelativeLayoutと仮定する.

こんなかんじで作ってgetPrimaryViewを呼び出してやればいい.

もし,RelativeLayoutの更に下のViewがほしいのなら
もう少し手を加える必要がある.
レイアウトに欲しいViewをsetTagして,
呼び出すときにgetTagすればいい.

getChildAtでも子Viewを取得できるが
きちんと管理していればいいが
コード改修を考えると誰が出てくるか不明瞭なので怖くて使えない.
想定外動作を引き起こすことになる上,
下手したらキャスト失敗で死ぬことになるからね.

2013年7月23日火曜日

【Linux】lnでOperation not permitted

Linuxでライブラリを別のところからコピーしようとしたら
シンボリックリンクが蹴られた.

じゃあ手動でシンボリックリンクしてやろうと

# ln -s libjpeg.so.9.0.0 libjpeg.so.9

したら

ln: libjpeg.so.9: Operation not permitted

と言われた.

Operation not permitted?
ユーザ権限が不足してるのかと思い,
suしてみるもダメ,chmod/chownしてみるもダメ.

ふと気がついた.
今コピーしようとしている先は接続しているHDDであるということを.

# mount

を叩く.

/dev/sda1 on /mnt/test type vfat

HDDはVFATでした.
譲り受ける際にフォーマットはNTFSじゃなけりゃなんでもいいって言ってしまってたわ…
VFATなのでシンボリックリンク作れなくて当然.

はずかしい

2013年7月17日水曜日

【Android】ViewPagerについて

ViewPagerとはAndroidの標準ギャラリーのように
左右フリックでコンテンツを切り替えるViewである.

このViewPagerではコンテンツを表示する際に
自動的に前後のポジションのコンテンツを読み込みに行く.
例えばposition:3のコンテンツを表示させる場合,
同時にposition:2,4のコンテンツも取得する.

こんな便利なViewがあるなんて!と思ったのだが,
使い方を誤ると大変なことになりそうだと気づく.

同時に3つまでコンテンツを保持する関係上,
大きな画像を扱う場合はメモリ管理に注意しなければならない.

もしコンテンツがインターネッツ上にある場合やデコードが必要な場合等々,
処理に時間がかかる場合は処理を別スレッドに任せないといけない.

これは当然なのだが,ただ何も考えずに別スレッドにしただけでは
フリック操作をしまくることでスレッドがたまり,
きちんと排他処理をしなければ処理能力不足やソケットの取り合いになり,
排他処理をしても,スレッドがスタックされていく.

必要なスレッドとそうでないもはや古くなってしまったスレッドとの判断が必要.
だが,今表示されているポジションだけでなく,
その前後のポジションも読みに行くという仕様がここではネックになる.


そこで,以下のようなアルゴリズムを考えた.

まず各スレッドにユニークなIDをもたせる.これはスレッドIDでも構わない.
次にそのスレッドでユニークなIDの最新3件(表示ポジションと前後ポジション)を
記憶するためのリストをアクティビティに持たせる.
 →これはLinkedListでも配列でもArrayListでも自分が使いやすいやつでいいが,
  順番というものを意識するため今回は意図的にLinkedListにしている.
スレッドを生成したら即Synchronizedでロックをし,順番待ちしてもらう.

順番がまわってきたら最初にアクティビティが持ってる最新3件のリストに自分が入ってるかどうか確認する.
入っていなければそこで終了.
入っていれば重たい処理を行い,HandlerでUIに反映させる.

なお,ViewPagerはListViewなどと違ってViewが再利用されないので,
重たい処理を行わせた後で表示していいかどうかの判断を行う必要はない(と思う).


以下,上記日本語のコード化
View内のレイアウト配置等,今回不要かつ紛らわしいところは省いている.


本当の本当に終わり

2013年7月1日月曜日

【Windows8.1】PCの起動をカスタマイズ

Windows8以降,システムのセキュアー性を確保するために
セキュアブートといって無署名ドライバを起動させなかったり,
インストールさせなかったりするような仕組みがある.

無署名ドライバのインストール拒否で困るのがAndroid開発である.
GoogleがSDK内に用意してくれた,多くのAndroid端末で動く汎用ドライバ
Android composite adb interface
というものがあるのだが,
これがなんと未署名なのである.
つまり,Windows8以降ではAndroid開発への敷居が少し高くなってしまった.

さて,Windows8からWindows8.1 RPへアップデートした際に
インストール済みの未署名ドライバが一掃されたらしく,
再度インストールしなければならなくなった.
手持ちのAndroidタブレットが見えなくなったのである.

そこで,PCの起動をカスタマイズという起動の仕方がWindows8から追加されており,
未署名ドライバをインストールできる設定でWindowsを起動させることができる.
その状態に持っていく必要がある.


話は変わって,
Windows8では設定が
StoreStyleAppsのPC設定の変更という方法と
従来通りのコントロールパネルという方法とがある.
この2つにわかれていたのが不評だったのか,
PC設定の変更の方にもコントロールパネル要素が入ってきた.
コントロールパネルが消えたわけではない.
相変わらず2立したままなのだが,PC設定の変更が階層化され,複雑になってしまった.

先に述べたPCの起動をカスタマイズするにはPC設定の変更から行う必要があった.
PC設定の変更が大幅に変わってしまったため,どこにいったかわかりづらくなってしまった.
ということを踏まえて,PCの起動をカスタマイズするには,の手順を示す.

右端のチャームから設定チャームを開く

設定コントラクト最下部のPC設定の変更をクリック

するとStoreStyleAppsのPC設定が開くので,
最下部にある保守と管理をクリック

更に最下部の回復を選択し,
右画面の今すぐ再起動するをクリック.

これ以降はWindows8と同様である.

【Windows8.1】デスクトップ画面で起動

Windows8で追加された
Modern UIというスタート画面.

この画面ではStoreStyle Appsといわれる
iPhoneアプリやiOSアプリに近いようなアプリを実行することができる.

MicrosoftとしてはこのStoreStyleのストアを
Windowsという圧倒的なシェアに乗せて広めたかったんだろうが,
現状では今ひとつ評判がよろしくない.

Windows8ではPCの起動時にスタート画面を表示して
デスクトップもStoreStyleアプリの一つ
という風に魅せたかったようだが,
実際はそうではないし,
既存Windowsユーザには浸透しなかった.

それで敬遠されてWindows8が普及しなければ
ストアどころでなく,本末転倒である.

というふうにMicrosoftが思ったかどうかは分からないが,
時期WindowsOSであるWindows8.1には設定で
起動時の画面をデスクトップかスタート画面かを選択できる
設定項目が追加された.
デフォルト設定はスタート画面ではあるが.

そのスタート画面設定が入るということは事前にわかっていたことであるが,
いざ探してみてもなかなか見つからなかったのでここにまとめる.

タスクバー上で右クリックして
プロパティを選択.

ナビゲーションタブを選択し,
サインイン時にスタート画面ではなくデスクトップに移動するにチェックをつける.
これで次回サインイン時以降からデスクトップ画面から起動するはずである.

2013年6月27日木曜日

【Windows8.1】スタート画面も変化が

Windows8で酷評?されたスタート画面.
Microsoftとしてはストアの普及のためにももっと使って欲しいところなのだろう.
変更が加えられていた.

このキャプチャ内にいろいろと入れてみた.

まずは事前に言われていた特徴の一つ,グループ化である.
グループ化とはいうが,従来からまとまって表示されていた先頭にタイトルを付けられるだけ.
このキャプチャでは顔文字( ゚д゚)をタイトルにしている.

次にタイルのサイズ選択肢が増えた.
アプリにもよるが,選択肢の多いアプリで
・大(広いの高さが倍)
・広い(従来の大)
・中(従来の小)
・小(中の1/4)
という4段階になった.
(従来は大と小だけ)
大・中・小に混ざった異色の「広い」
どういう意図があるんだ…

それからデスクトップアプリのタイルサイズも変更できるようになった.
中と小を選択可能になっている.

このキャプチャ左下にある(↓)アイコンは
「すべてのアプリ」の表示である.
以前は右クリックをして表示させていたのが1ステップ減った.

このスタート画面の背景にも微妙に変更が加えられている.
Windows8で選択できたのは
・模様
・色合い
の2項目であった.
Windows8.1では色合いの部分が分解されて
・背景色
・アクセント色
になっている.
背景色と前景色を別々に設定できるようになった.
それから,デスクトップと同じ壁紙を指定することができる.
デスクトップとは別の背景を選ぶことはできない.

模様もいくらか変更が加えられており,
ギターのやつがなくなってもうたで…(/_;)


スタート画面ではないがもう一つ気づいた変更点として
Windows8では画面右下/右上にマウスカーソルを合わせるとチャームというのがでてきた.
検索,共有,スタート,デバイス,設定というメニューのあるアレである.
そのメニューがバーの中心に出てくるので,右下や右上から呼ぶものとしては遠い感じがしたのだろう,
手繰り寄せた感じの変更が加えられている.

右上から呼び出すと各項目も上よりに,
右下から呼び出すと書く項目も下寄りに表示され,
マウスの移動距離が少なくて済むようになっている.

タッチパネルPCのスワイプだと従来通り真ん中なのだろうか?

UIだけでも結構変わってるイメージ.

【Windows8.1】消えたGoogle IME召還

Windows8.1のインストールとともにGoogle日本語入力がIME候補から消えてしまったので召還した.
Google日本語入力を再度インストールしても戻ってこなかったんだ.

まずは画面右下のIMEをクリック
このJってやつ

するとIMEの設定が出てくるので
言語設定をクリック

コンパネの言語に飛ぶ.
日本語のオプションをクリックする.

入力方式の追加を選択する

追加したいIMEを選択して「追加」で完了!

【Windows8.1】スナップが変わってた

Windows8.1ではどうやらアプリのスナップが変わっていたようである.

Windows8では左にスナップするか,右にスナップするかの2パターンのみであり,
スナップに対応していないアプリはアイコンが表示されるだけという悲しい絵面であった.

ありし日のスナップ状態

アプリをちゃんと作っておけばスナップ用の画面も用意することはできる.
といったのはWindows8のストアアプリであった.

それがWindows8.1になると,
左にスナップした状態でもWindowsStoreが使える!
…んん?っつーかスナップ幅広くね?

と思ったらどうやらこのスナップ幅がある程度制限はあるものの可変になったようである.
↑この画面はこれが最小幅の状態.

アプリを半々に表示することができるようになった.
WindowsStoreアプリも微妙に変更されているようだ.

はて,ここで疑問が出てくる.
スナップ用の画面を作った既存アプリはどうなるのかと.

やってみた.
おや,WindowsStoreではできなかった従来のスナップ幅でのスナップができた.

そう.どうやらスナップ画面を用意しているアプリのみ
旧来のスナップ幅で表示することができるように変更されたようなのである.
ではこのスナップ画面を用意したアプリを拡げていくとどうなるか…
これはあかん
どないかならんかったんかと言いたくなる.
いや,もう言ったわ.

スナップ用画面を用意したアプリはある程度まで狭い領域だと黒縁が入った状態になるようだ.
画面の半分近くまで拡げると
ちゃんとした画面になる.

スナップの仕様変更はこんなところか.
旧来は
・左か右かにスナップする
・スナップ画面を用意していなければ残念な絵面
Windows8.1では
・スナップ幅が真ん中で分割したりと可変になった
・スナップ用画面を用意したアプリは旧来のスナップ幅での表示が可能
・スナップ用画面のないアプリは旧来のスナップ幅よりもっと広い領域が最小幅となる
・スナップ用画面のあるアプリは狭い領域だとスナップ用画面+黒縁で表示される

この挙動を見る限り今後はスナップ用画面を用意しないほうがいいかもしれない.