2013年1月30日水曜日

外部のライブラリをどうするか

gitで管理していたAndroidプロジェクトがありました。

Project1
├.git
├src
├res
└libs

こんな感じです。ディレクトリ全部を書き出したわけじゃないです。こんな感じだと思ってください。

このプロジェクトでは外部のAndroidライブラリを利用することになりました。jarではなく、eclipseのプロジェクトの状態でソース形式で配布されているやつです。

workspace
├Project1
│├ git .
│├src
│├res
│└libs
└Library1
 ├src
 ├res
 └libs

こんな感じにしました。ここのLibrary1もプロジェクトなので、こうするのが自然かなぁ、と思ってこんな感じにしました。
ただ、これだとgitの管理下にLibrary1がないんです…。
Project1だけgitで管理しても、Library1も揃わないとビルド出来ません。かと言って、自分が修正するでもないプロジェクトを別のリポジトリに登録するのも変な感じだし…と、困っていました。

知人に聞いてみたら、Library1を他のプロジェクトでも繰り返し使うならリポジトリとして登録して、submoduleにするのが良いのではないか、という意見をもらいました。
(submoduleって何だろう?という状態です…)
あとはProject1のどこかにLibrary1を含めてしまうか、Library1をjar化してProject1の中に含めるか等の案をもらいました。

まずは一番すっきりしそうなLibrary1のjar化を試してみることにしました。ダメでした…。
少し調べただけですが、リソースを含むライブラリプロジェクトはjarには出来なさそうですね(出来るなら配布元もjarにしてそうですしね)。

続いて、プロジェクトの中にプロジェクトを入れてしまうことにしました。submoduleがよくわかってませんし。
これは簡単ですね。

workspace
└Project1
 ├ git .
 ├src
 ├res
 └libs
  └Library1
   ├src
   ├res
   └libs

こうするだけです。
これならgit管理下に入ります。プロジェクトの中にプロジェクトがあるというのは変かな?と思っていましたが、やってみるとそこまで違和感はなかったです。
ただ、Library1が外部のSDKですので、公開リポジトリに置くのはマズそうな気はします…。今回は非公開のプロジェクトだったので、とりあえずこのまま進めることにしました。

こういう場合の定番の方法を知りたいですね。

2013年1月20日日曜日

正しい容量を認識しなくなったSDカード

本来4GBのはずが、なぜか70.5MBととして認識されるようになってしまったSDHCカードがありました。

そんなときはこちら。SDフォーマッターというものがありました。
https://www.sdcard.org/jp/downloads/formatter_3/

起動して、SDカードを挿して、「フォーマット」ボタンを押すだけ。
その後は正しく4GB(相当)として認識されました。
Windows/Macどちらもあるようです。便利ですね。

2013年1月11日金曜日

ThreadPoolExecutorってこんなやつかも

昨日、帰ったらThreadPoolExecutorの動きを確認するサンプルコードを書くつもりだったのですが、仕事の中で満足するくらい確認できてしまって、結局家ではやりませんでした。

自分の理解したThreadPoolExecutorはAndroidのものです。たぶん、一般的なJavaでも同じだと思いますが。さらに、Android2.xまでのAsyncTask内で使われているような使い方をした場合の動作です。

http://developer.android.com/reference/java/util/concurrent/ThreadPoolExecutor.html

ThreadPoolExecutorというのは、大きく2つため込むものがあるようです。
1つは名前が表す通り「スレッド」、もう1つは「実行前のタスク」です。タスクっていうのはRunnableですね。
コンストラクタで指定するいくつかの値がありますが、corePoolSize、maximumPoolSizeはスレッド数に関するものです。keepAliveTime、unitはcorePoolSizeを超えたスレッドの生存期間を表しているようです(ここはあまり調べませんでした)。workQueueは実行前のタスクがためられるキューです。キューのインスタンスを渡すので、ここの長さも使用する側で決めることができます。

ちなみにAndroid2.xまでのAsyncTaskでは以下のように設定されていました。

corePoolSize … 5
maximumPoolSize …128
keepAliveTime、unit … 1秒
BlockingQueue<runnable> workQueue … 長さが10固定のキュー

このときexecute()を行うとどのようになるか。

(1) Executorが保持するスレッドがcorePoolSize以下のとき

スレッドを作って実行します。poolSizeが+1されます。
getPoolSize()は内部のスレッド数を返します。
getActiveCount()は動作中のスレッド数を返します。
ここは問題ありませんね。

(2) Executorが保持するスレッドがcorePoolSizeを超えているとき

workQueueの状態で動作が変わります。

(2-a) キューにタスクを格納可能なとき

キューに詰めて終わりです。キューに詰められたタスクは、実行中のスレッドが空けば取り出されて処理されます。

(2-b) キューにタスクを格納できないとき(キューが一杯のとき)

キューからタスクを1つ取り出して、新しくスレッドを作って実行します。新しいタスクはキューに詰められます。
ただし、スレッド数がmaximumPoolSizeを超えるようだと、例外が発生して終わりです。
ここでスレッドが作られるため、getPoolSize()を呼ぶとcorePoolSizeを超えた数が返されます。スレッド数は最大でmaximumPoolSizeまで増えますが、keepAliveTime、unitで指定した時間を超えて何もしないスレッドは破棄されていきます。

書いてみると単純ですね…。
すっごく苦労したんですが。


今回、不具合でタスクが完了しない(無限ループに陥ってた)ものがあり、スレッドに居座り続けるという事態が発生していました。しかも、何度も呼ばれる処理だったために、徐々にスレッド数を消費していきます。
その不良スレッドがcorePoolSizeを超えて、なおかつキューに空きがある場合、新しく呼ばれた処理はキューに詰められるだけで何もしません。恐ろしいですね。そんな不具合でした。

大変でしたが、コードをたくさん読めて満足しました。

2013年1月10日木曜日

タイムアウトについて

通信関連のプログラミングをしているとタイムアウトという言葉が出てきます。プログラムで設定できるタイムアウトは大抵2種類あります。コネクトタイムアウトとソケットタイムアウトです。

今まで漠然と「コネクトタイムアウトは接続までに待てる時間」、「ソケットタイムアウトはデータが流れなかった時に待てる時間」くらいの理解でした。

今日は「それってつまりどういうことなんだ?」と思い、検索してみました。そのものずばりの情報が見つかった訳ではないのですが、次のページから、自分なりに解釈しました。

TCP/IP エラー処理 connect 編 http://x68000.q-e-d.net/~68user/net/tcp-connect-1.html
TCP/IP - TCP( 3ウェイハンドシェイク ) http://www.infraexpert.com/study/tcpip9.html

・コネクトタイムアウトは、SYN=1で送信して、SYN=1、ACK=1を待っている時間。
・ソケットタイムアウトは、SYN=0、ACK=1で送信して、SYN=0、ACK=1を待っている時間。

…ということなのではないかと。
(自分なりの解釈と書きましたが、正確には知人の指摘を受けた上での理解です)
これも間違ってたらどうしよう…?

ThreadPoolExecutorって何だ

昨日はThreadPoolExecutorの動きに悩まされていました。
もう少し細かく書くと、Android 2.xまでのAsyncTaskの内部的な動きがよくわからなかったのです。
AsyncTaskの内部ではThreadPoolExecutorが使われていました。
それに絡んでいる(ような気がする)不具合が発生していて、内部の動きがわかれば解決に向かうかも、という期待からThreadPoolExecutorについて調べていました。

インターネットを検索すると、いくつかThreadPoolExecutorに関する記事は見つかるのですが、自分の理解力がアレなのかイマイチ理解出来ません。
プールやらタスクやらキューやら出てきて、どこにどうスレッドがたまるのか想像出来ないのです。
ネット上でThreadPoolExecutorのソースを見つけたので読んでみて、ようやく「こういう動きかな?」というところまでわかってきました。

昨日帰宅してから確認するためのコードを書いてるみようとしたのですが、睡魔に勝てず寝てしまいました(帰れたの1時なんですもの)。
また、今日帰ったら試してみたいと思います。

2013年1月8日火曜日

JUnit実践入門

JUnitを使ったテストができないと、この先まずかろうと思い、「JUnit実践入門」という本を買ってきました。

まずはライブラリのダウンロードをしなければ話にならないのですが、何故かダウンロードページまで行き着きません。この本には「公式サイトからダウンロードしてください」くらいしか書かれていないので、特別な手順は必要なさそうでした。しかし、ダウンロードページと思われるリンクをクリックしても、全然ページが表示されないのです。 初日は「ライブラリがダウンロードできない」というパソコン初心者真っ青の理由で何もせずに終わりました…。 翌日(今朝なんですけどね)ブラウザを変えて試してみたら、すんなりダウンロード出来ました。なんてこった。 これから少しずつ勉強していきます。

2013年1月7日月曜日

新年の抱負。

今年がんばりたいこと。
・情報を受信するばかりではなく、発信できるよう努力する
・アプリを使ってお金を稼ぐ

がんばります。