今日は Android Advent Calendar 2011 参加のエントリです。Advent Calendar って何という方は こちら をどうぞ。
多くの方が Android 開発に eclipse を使用していると思いますが、eclipse の機能を使いこなして快適な開発・効率のよい開発をしているでしょうか。今日は、わたしが普段使っている開発環境で行っている eclipse の設定を紹介したいと思います。まぁどっちでもいい好みの問題といえるような設定から、是非皆さんに使って欲しいお勧め機能までいろいろ紹介します。
今回のエントリでは eclipse の設定画面がたくさん出てきますが、どこにある設定であるかを示すのに [ aaa > bbb > ccc ] という表記をします。一番左が設定画面(Preferences) の左にでている項目を示しています。右はネストした項目だったり右側にでている項目だったりその時々によって異なりますがいちいち説明しません。感じ取ってください。また、設定の項目は英語版での表記です。普段日本語化していないので日本語表記が分かりません。普段日本語化している方はごめんなさい。これも感じ取ってください。
まずは軽めのものから。
[General] の中にある Show heap status チェックボックスです。

このチェックボックスをチェックすると、右下の方に現在のヒープの大きさと使用しているメモリの量が表示されます。また、ゴミ箱アイコンをクリックするとeclipse を実行しているJVM で強制的に GC を走らせることができます。

[General > Editors > Text Editors] にある Show line numbers チェックボックスです。

このチェックボックスをチェックすると、ソースコードの左側に常に行番号が表示されるようになります。コレをチェックしなくても下の方に行番号と列番号が表示されているのでカーソル位置についてはわかるのですがわたしは表示するほうが好きです。ノートパソコンで開発する際など、少しでも画面を有効に使いたい場合は off のほうがいいかもしれません。

[General > Editors > Text Editors] にある Show whitespace characters チェックボックスです。

このチェックボックスをチェックすると、テキスト中の空白、TAB、改行などが可視化されます。具体的には、半角空白が ・ に、 TAB が ≫ などとして表示されます。また、CR/CRLF/LF といった改行の違いも見た目でわかるようになります。半角スペースのつもりがTAB でインデントしてしまったり、行末に余計な空行が入っていてもすぐにわかるのでお薦めです。

[General > Workspace] にある文字コードの選択のラジオボックスです。

当然ソースコードはUTF-8 で記述すると思うので、設定を UTF-8 にします。全てのワークスペースで UTF-8 しか使わないという人(大抵の人はそうだと思います)は、clipse の実行ファイルの所にある eclipse.ini (MacOS X の場合は、 Eclipse.app を右クリックして「パッケージの内容を表示」してから Contents/MacOS/eclipse.ini) を開いて、 -vmargs と書かれた行の下に
-Dfile.encoding=UTF-8
を加えると、eclipse のデフォルトが UTF-8 になります。
[Java > Appearance > Type Filters] で、コード補完時に候補にしたくないクラスを指定します。
私は以下のクラスを指定しています。
android.R java.awt.*
android.R を指定することで、 R.string などを補完する際は、アプリケーションが生成する R クラスとして補完されるようにしています。うっかり android.R として保管されてムキッって言ってしまう @lychee さんにぜひお勧めな設定です。また、 java.awt.* を指定することで、 List を補完した際に java.awt.List が候補の先頭に出てきてちげーよと思うことがなくなります。
他にも状況に応じて適宜加えると効率アップに貢献します。
[Java > Code Style] で変数のプリフィックスを設定ます。
Android のコードはメンバ変数やstatic変数に接頭辞をつけるルールなので、これを eclipse に教えておきます。こうしておくと、getter/setter の生成時などに、変数の接頭辞を無視してメソッド名を生成してくれます。Fields の prefix list に m, Static Fields の Prefix list に s をそれぞれ記述します。

[Java > Code Templates] で、eclipse が自動生成するコードをカスタマイズできます。わたしが行っているのは主に以下の変更です。
ファイルの先頭に挿入されるコメントです。コピーライト表記を以下のような感じでいれています。今年が何年かを ${year} 変数から指定することで2012年も安心です。
/*
* Copyright ${year} 自分の名前<じぶんのメールアドレス>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
クラスやインタフェースの前に挿入されるコメントです。個人で作る場合は @author の記述は邪魔なことが多いので消して以下のようにしています。
/**
*
* ${tags}
*/
親クラスのメソッドをオーバーライドする際のコメントです。デフォルトでは (non-Javadoc) としてオーバーライドするメソッドが記述されますがeclipse を使っているなら簡単にオーバーライドされるメソッドに飛べるのでコメント自体を削除しています。
クラスを自動生成するさ際に挿入されるコードです。デフォルトでは何も書かれていませんが、わたしは以下のコードを記述しています。
@SuppressWarnings("unused")
private static final String TAG = ${type_name}.class.getSimpleName();
private final ${type_name} self = this;
コレにより、各クラスに自動的に TAG と self が定義されるようになります。不要な場合も多いですが、その場合は自動生成後に削除します。必要になって書くよりも不要なときに消すほうが楽なのでこうしています。また、Android のコーディング規約的にはメンバ変数は m で始めるべきですが、 this と同じように使いたいのであえて付けていません。 self が定義してあると、Activity の中の無名インナークラスで Context を渡さないといけない際に HogeActivity.this と書かずに self でスマスことができます。この方法は @vvakame さんのコードで見かけてわたしも真似するようになった記憶があります。
[Java > Code Style > Formatter] で、オートフォーマットをする際の設定を行います。
フォーマッタ設定は各自の好みや AOSP の設定を使うなどすればいいと思いますが、オートフォーマット除外の tag を有効にしておくのをおすすめします。
Formatter の Edit ボタンを押し、 On/Off tags タブを選択します。そこに表示される Enable On/Off tags にチェックをつけます。デフォルトのタグとしては @formatter:on と @formatte'Formatter'r:off が設定されていると思います。

この設定を有効にすることで、ソースコード中にオートフォーマットを行わない行を作ることができます。これでいつでも気兼ねなくオートフォーマットできます。
// @formatter:off 手動で頑張って整形したコード(配列の初期化を適当な数で折り返したい場合とか) // @formatter:on
[Java > Editor > Save Actions] で、ファイルを保存する際に自動で実行する処理を指定します。
↑でオートフォーマット除外をしていれば常にオートフォーマットしても問題ないので Save Actions として実行することをおすすめします。
[Java > Editor > Templates] でコードや Javadoc に挿入するテンプレートを定義できます。私は以下のテンプレート定義を追加しています。
Log.d(TAG,""); を生成するテンプレートです。コード中で logd<Ctrl-Space>(補完発動) すると、Logcat にデバッグログを出力するコードが一瞬で書けます。
Log.e(TAG,""); を生成するテンプレートです。コード中で loge<Ctrl-Space>(補完発動) すると、Logcat にエラーログを出力するコードが一瞬で書けます。
Log.w(TAG,""); を生成するテンプレートです。コード中で logw<Ctrl-Space>(補完発動) すると、Logcat に警告ログを出力するコードが一瞬で書けます。
Log.i(TAG,""); を生成するテンプレートです。コード中で logi<Ctrl-Space>(補完発動) すると、Logcat に情報ログを出力するコードが一瞬で書けます。
Log.dで、実行しているメソッドのトレースログを出力するコードを生成するテンプレートです。コード中で tracelog<Ctrl-Space>(補完発動) します。
自分の eclipse をみながら普段どんな設定をしているかを書いてみましたが、このエントリの内容でみなさんの Android 開発が少しでも楽になればと思います。
RC-S620/S は、シリアル接続でコントロールできる NFC Reader/Writer モジュールです。arduino 向けライブラリが FeliCa Developers' Blog で公開されているので、ADK からもわりと簡単に使用することができます。
このライブラリはとても便利なのですが、使用するうえで一つ困ることがあります。それはこのライブラリが RC-S620/S との通信にシリアルポートを使用してしまうため、Arduino IDE の シリアルモニターが使えなくなってしまうことです。そこで、ライブラリが使用するシリアルポートを変更可能にするパッチを作成しました。
このパッチを適用すると、TX1/RX1 を使用するようになります。使用するポートを変更したい場合は、 RCS620S.h の SERIAL_RCS620S マクロの定義を変更してください。
また、 setup() などで RC-S620/S との通信に使用するシリアルポートを有効にする必要があります。以下のコードを追加してポートを有効にしてください。シリアルモニターを使用する場合は、 Serial.begin(115200); も残しておく必要があります。
SERIAL_RCS620S.begin(115200);
arduino-RCS620S.zip に適用する場合は、ディレクトリ構造が異なるので patch -p3 とするなど、適宜調整してください。
diff --git a/firmware/RCS620S/RCS620S.h b/firmware/RCS620S/RCS620S.h
index 9792859..f2a17c0 100644
--- a/firmware/RCS620S/RCS620S.h
+++ b/firmware/RCS620S/RCS620S.h
@@ -16,6 +16,15 @@
#define RCS620S_MAX_CARD_RESPONSE_LEN 254
#define RCS620S_MAX_RW_RESPONSE_LEN 265
+
+/*
+ for default Serial port, use Serial
+ for TX1/RX1, use Serial1
+ for TX2/RX2, use Serial2
+ for TX3/RX3, use Serial3
+*/
+#define SERIAL_RCS620S Serial1
+
/* --------------------------------
* Class Declaration
* -------------------------------- */
diff --git a/firmware/RCS620S/RCS620S.cpp b/firmware/RCS620S/RCS620S.cpp
index fe9eb01..bf0f776 100644
--- a/firmware/RCS620S/RCS620S.cpp
+++ b/firmware/RCS620S/RCS620S.cpp
@@ -309,7 +309,7 @@ void RCS620S::writeSerial(
const uint8_t* data,
uint16_t len)
{
- Serial.write(data, len);
+ SERIAL_RCS620S.write(data, len);
}
int RCS620S::readSerial(
@@ -324,8 +324,8 @@ int RCS620S::readSerial(
return 0;
}
- if (Serial.available() > 0) {
- data[nread] = Serial.read();
+ if (SERIAL_RCS620S.available() > 0) {
+ data[nread] = SERIAL_RCS620S.read();
nread++;
}
}
@@ -335,7 +335,7 @@ int RCS620S::readSerial(
void RCS620S::flushSerial(void)
{
- Serial.flush();
+ SERIAL_RCS620S.flush();
}
int RCS620S::checkTimeout(unsigned long t0)
2011年10月25日11:30 AM, Android SDK テックリードの Xavier Ducrohet の投稿。
Android 4.0 の SDK と新しい開発ツール群をrevision 14として先週リリースしました。新しいツール群はビルドパフォーマンスを改善する沢山の変更を含んでいます。これらの変更の中に、ライブラリプロジェクトの扱われ方の変更が含まれています。これはライブラリサポートとコードの再利用性を改善するための第一歩です。ライブラリプロジェクトの扱いに関する変更が既存のプロジェクトに対して影響しないよう考慮していますが、新ツールへ移行する際に問題が発生する場合もあります。ライブラリプロジェクトに対する変更と移行時の問題の解決方法については以下を読んでください。
以前は、ライブラリプロジェクトのリソースとソースコードはメインプロジェクトのリソースとソースコードをコンパイルする際の追加フォルダとして扱われていました。大抵の場合はこの方法でうまく行きますが、2つの問題がありました。
r14では、コンパイルされたコードによるライブラリへ移行することでこの両方の問題を一度に解決することにしました。この方法は、Eclipse における柔軟性のなさを改善すると共に、ライブラリを単一の Jar ファイルとして配布することを可能にします。
リリースノートで見たかもしれませんが、この方式への移行は幾つかの場合で既存のプロジェクトに影響を与えます。しかし修正は難しくありません。
一つ目の影響は、ライブラリプロジェクトに含まれるリソースのIDが final ではなくなったことによるものです。この変更により、Javaコンパイラはライブラリに含まれるIDの値をインライン展開できなくなります。これは、 ID の値を switch 文の case ラベルとして使用できないことを意味します。 このようなコードが存在する場合、Eclipse が提供するリファクタリング機能を用いて、 switch 文を if/else に変換することができます(here 参照)。

二つ目は、プロジェクトによっては新しい方式に正しく移行されない場合があることです。 dex のビルドステップでのクラス重複などのエラーが発生し、プロジェクトのコンパイルに失敗します。 ADT14 はこれまでのプロジェクトを新しい方式へ移行させますが、既存の方式が抱える問題により正しく移行できないこともあります。移行が正しく行われないと、これまでの方式と新しい方式によってプロジェクトがライブラリを2回参照してしまい、ライブラリ側のクラスが2回パッケージングされてしまいます。このような場合は、Package Explorer(パッケージエクスプローラー) で <ライブラリ名>_src という名前の余分なソースフォルダがないか確認してください。右のスクリーンショットこのような場合の例を示しています。
エラーを修正するには、以下の手順で余分なソースフォルダを取り除いてください。
このライブラリプロジェクトに対する変更により、コンポーネントの再利用に対するより良いサポートを提供します。コンポーネントの作成、利用、管理をより簡単に行えるよう引き続き改善を行なっています。私達のゴールは開発者の方々がすべてのフォームファクターに対して素晴らしいユーザーエクスペリエンスを持ったアプリの作成をお手伝いすることです。
ライブラリプロジェクトは組織内部でしか使用していないのでバイナリでの配布よりも今までのソースコードベースの方式が良いという開発者の方もいます。ソースコードベースの方式も新方式と平行してサポートできるようにする方法も検討中です。
最後に、私達が r14 で把握しているいくつかの既知の問題(とそのワークアラウンド)を次のサイトに記述しています。 http://tools.android.com/knownissues
これらの問題を修正するアップデートの公開に向けて作業を続けています。できるだけ早くリリースできることを期待しています。
UI の作成で LinearLayout を使用する際、「とりあえず中の View の attribure に android:layout_weight="1" と書いとけばなんとなくうまくいく」なんてことを言われたことはありませんか? 以下は、weight を指定することで、LinearLayout の中では何が起きるのかについて調べたことのメモです。
今回は、横方向(LinearLayout の orientation が horizontal) の場合で記述します。縦方向についても全く同様なので、縦の場合は width と height を入れ替えて読んでください。
まず、View に指定する weight (android:layout_weight) はどういう意味でしょうか。 この場合の weight は「重要性」や、「影響力」という意味です。つまり、 weight のイメージとしては、値が大きいほど画面内で大きなスペースを占有するということです。
ところが weight についてしっかり理解せずに使うと、本来の意味とは全く逆で値が大きいほど占有するスペースが小さくなる場合があります。なぜこのようになるかについてはあとで説明をするので、まずは以下の例を見てください。
まずはレイアウトの XML です。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" android:text="weight:1" android:background="@android:color/black" android:textColor="@android:color/white" /> <TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="2" android:text="weight:2" android:background="@android:color/white" android:textColor="@android:color/black" /> <TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="3" android:text="weight:3" android:background="@android:color/black" android:textColor="@android:color/white" /> </LinearLayout>
TextView を横に3つ並べています。weight の値は順に 1, 2, 3 となっています。それぞれの View の範囲が分かりやすいように、TextView の背景は 黒、白、黒にしました。このレイアウトを表示すると以下のようになります。

なぜか最初の TextView が画面の 2/3 を占め、残りが2つめの TextView、3つ目は見当たりません。このようになるのは、weight の使われ方に原因があります。
weight が横方向で使用される際の意味は以下のとおりです。
LinearLayout に属するそれぞれの View について、それぞれの幅の合計とLinearLayout自体の幅との差分(余白)を各 View に割り振る際の比率
7/4追記: @yanzm さんの Android Layout Cookbook によると、上記差分からさらに各 View の margin を引いたものが weight に従って分配されるとのこと(margin と padding の違いに注意)。さすが yanzm 本...
View の幅は android_layout_width の指定に従って計算します。つまり、wrap_content であれば中身の幅、match_parent(またはfill_parent) であれば親の LinearLayout の幅になります。
では、先程の例がなぜあのような見た目になってしまうのかを説明します。
まずweight 適用以前の各 View の幅ですが、全て fill_parent なので 親の LinearLayoutの幅(== 画面の幅)になります。画面の幅 を W dip とすると、W dip の TextView 3つ分が並ぶことになるので 合計の幅は 3W dip です。 LinearLayout の幅は画面の幅と同じ W dip なので、差分を取ると -2W dip という負の値になります。
もうわかったかもしれませんが、 fill_parent と weight を組み合わせると、差分(余白)が負の値になるのが一見奇妙な挙動になる原因です。この -2W dip を各 View の weight に従い分配すると以下のようになります。今回の例では weight の合計値は 6 (1 + 2 + 3) です。
まず 最初の TextView は weight が 1 なので、-2W dip のうち、1/6 を受け取ります。つまり最終的は幅は W + (-2W * 1/6) dip == 2/3 * W dip です。画面の 2/3 を占有するということです。
2つ目の TextView は、 weight が 2 なので、-2W dip のうち、2/6 を受け取ります。つまり最終的は幅は W + (-2W * 2/6) dip == 1/3 * W dip です。画面の 1/3 を占有するということです。
3つ目の TextView は、 weight が 3 なので、-2W dip のうち、3/6 を受け取ります。つまり最終的は幅は W + (-2W * 3/6) dip == 0 * W dip です。幅が0なので表示されません。
これが weight を指定した際に直感と違うみためになる理由です。
では、単に View の幅を 1:2:3 にしたいしたい時はどうすればいいかというと、LinerLayout の幅全てを余白として扱い weight に従って各 View に分配するのが簡単なやり方です。そのためには各 View で android:layout_width="0dip" と指定します。さきほどの layout XML の android:layout_width を "0dip" に変えたものが以下の図です。

このように、weight に比例した幅になっています。 今回 wrap_content の例は説明しませんでしたが、それぞれの幅を決めてから残った部分を weight に比例させて配分するという点は変わりません。
weight の意味を正しく理解して、思い通りのレイアウトを作成してください。
注: このエントリは、Androidのソースコードを読んで理解した内容なので間違っている可能性もあります。お気づきの点があれば @zaki50 までお知らせください。
To Be Written.
@95kugo さん、@itog さんと呑んでいる時に、画面サイズの判別(small, normal, large, xlarge)ってアプリからできるっけ?という話になったので、やり方のメモです。このやり方は iosched という Google I/0 参加者用のスケジュール管理アプリでみつけました。余談ですが、iosched という名前は kernel の中で入出力を管理しているプログラムとしか思えないのですが狙ってるのでしょうか...
以下のように、android.content.res パッケージに属しているConfiguration クラスを使用して端末の画面サイズを判定可能です。
(context.getResources().getConfiguration().screenLayout
& Configuration.SCREENLAYOUT_SIZE_MASK)
== Configuration.SCREENLAYOUT_SIZE_XLARGE
このコードが true を返せば xlarge です。画面サイズ毎に処理を分岐したい場合は == の前の値を switch 文で分岐させればOK。
画面サイズの判定のために、Configuration クラスには以下の定数が定義されています。
Configuration クラスに screenLayout が定義されていないので、スクリーンサイズの判定はできません。 API Level 3 の端末に対応する必要がある場合は、 API バージョンをチェックした上で small 決め打ちでよいと思います。
追記: @marchuq さんに教えてもらったのですが、こんな 1.5 端末もあるのですね... 少なくとも 1.5 だから small というのは正確ではないようです。 Build クラスの値から振り分けるなど、いくつかの方法を組み合わせる必要がありそうです。
Configuration クラスのメンバ変数である screenLayout や、判定のための定数の大部分は API Level 4 で定義されていますが、唯一 SCREENLAYOUT_SIZE_XLARGE だけは定義されていません。
API Level 8 以下で xlarge の判別を行いたい場合は、独自に xlarge のための定数(値は 4)を定義するか、default.properties で API Level 9 以上を指定して SCREENLAYOUT_SIZE_XLARGE が定義されている android.jar を使用する必要があります。後者の場合は、API Level 9 の情報を使用することになりますが、 Java の仕様上定数はコンパイル時にインライン展開されるので API Level が 9未満の端末でも未定義エラーになることはありません。
SCREENLAYOUT_SIZE_XLARGE を含め、全て使用することができます。