448
465

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Androidコードディング規約

Last updated at Posted at 2014-11-02

##App(Application)##

###1.命名規則###

####アプリケーション名####

  • 普通の英語名(スペースを含んでも構わない)
  • UpperCamelCase

####プロジェクト名####

  • UpperCamelCase

##Src(Sorce)##

###1.命名規則###

####パッケージ名####

  • すべて小文字
  • スペースは削除して、アンダースコア(_)に変更する。
  • srcの中のパッケージ名:
    • メインパッケージ:<リバースドメイン名>.<アプリケーション名>
    • メインパッケージ以外:<メインパッケージ>.[controller|model|view...]
  • 詳細な構成については、2のフォルダパッケージ構成に記す。

####ファイル・クラス名####

  • UpperCamelCase
  • 名詞
  • Activity、Fragment、AdapterなどはComponent名を末尾に付ける

####メソッド名####

  • lowerCamelCase
  • 動詞で始める。ただし、Booleanを返すメソッドはisで始める。
  • プロパティへのアクセスメソッドについて
    • Booleanを返すもの : is
    • それ以外を返すもの : get
    • Setter : set

####プロパティ名・変数名####

  • lowerCamelCase
  • アンダースコア(_)やドル記号($)で初めてはいけない
  • publicではなく、staticでもないプロパティ名は、mで始める
  • staticなプロパティ名は、sで始める
  • メソッド中のprivateな変数には、mを付けない

####定数名(public static final)####

  • 大文字とアンダースコア(_)のみを用いる。
    ex:public static final double FIELD_WIDTH = 500.0;
  • 用途に応じて、以下のように接頭辞を変える。String型の識別子の値は、lowerCamelCaseに変換したものを使用する。
用途 接頭辞
Intentのaction ACTION_
Permission PERMISSION_
BundleやIntentのフィールド名 EXTRA_(型名)_
なお、これらの定数の値は、パッケージ名で始める。
public static final String ACTION_GPS_STATUS_CHANGED = "com.example.sample.ACTION_GPS_STATUS_CHANGED";
public static final String EXTRA_GPS_LOCATION = "com.example.sample.EXTRA_GPS_LOCATION";

####SQLite####

  • テーブル名とカラム名:小文字とアンダースコア(_)
  • テーブル名:<モデルオブジェクト・クラス名>s
  • IDカラム名:BasicColumns._ID
    データベース名:<アプリケーション名>.db

###2.フォルダパッケージ構成###

  • controller(直接的にViewを持たない処理)

    • provider(通信処理を管理)
    • util(その他の処理)
  • model(POJOやenumを管理)

    • pojo(画面名かDBの構成によって更に子フォルダを作成する)
    • enumerate(enumを管理)
    • system(アプリ自体の情報を保持するクラスを管理する ex:AppConfig.java,Constants.java)
  • view(layoutファイルと関連付けられるもの・viewcontrollerを管理)

    • activity(Activityを管理)
    • adapter(Adapterを管理)
    • fragment(Fragmentを管理)
    • widget(カスタムViewを管理)

###3.Javaコーディング規則###
コーディング規則はGoogleのJavaのコーディング規則に準拠するものとする。

Google Java Style

主な内容と構成

###4.その他Javaコーディング規約と変更###

####型変換について####
型の変換については、基本的にvalueOfメソッドを用いて行うようにし、それで対応できない場合には別のメソッドを利用するようにする。

変換する対象の型名.valueOf(T)

####例外処理について####
#####例外を無視してはいけない#####

悪い例:

void setServerPort(String value) {
    try {
        serverPort = Integer.parseInt(value);
    } catch (NumberFormatException e) { }
}

このように例外を無視していると、いつか誰かがつまずき、コードにある地雷を踏んでしまいます。コードにあるすべての Exception は処理しなければなりません。どのように処理するかは、場合により異なります。

例外の処理の仕方:

  • メソッドの呼び出し元に例外を投げます。
void setServerPort(String value) throws NumberFormatException {
    serverPort = Integer.parseInt(value);
}
  • 適度に抽象化した新しい例外を投げます。
void setServerPort(String value) throws ConfigurationException {
    try {
        serverPort = Integer.parseInt(value);
    } catch (NumberFormatException e) {
        throw new ConfigurationException("Port " + value + " is not valid.");
    }
}
  • catch {} ブロックのなかで行儀よくエラーに対処して、適切な値を代入しておきます。
/** Set port. If value is not a valid number, 80 is substituted. */
void setServerPort(String value) {
    try {
        serverPort = Integer.parseInt(value);
    } catch (NumberFormatException e) {
        serverPort = 80;  // default port for server 
    }
}
  • Exception をキャッチして、新しい RuntimeException を投げます。しかし、これは危険です。この手段をとるのは、そのエラーが発生したときにはクラッシュさせるのがふさわしいといった積極的な理由がある場合のみにしてください。
/** Set port. If value is not a valid number, die. */
void setServerPort(String value) {
    try {
        serverPort = Integer.parseInt(value);
    } catch (NumberFormatException e) {
        throw new RuntimeException("port " + value " is invalid, ", e);
    }
}

元の例外が RuntimeException のコンストラクタの引数に渡されていることに注意してください。もしJava 1.3でもコンパイルする必要があるなら、元の例外を省略する必要があります。

  • 最後の手段: 自信をもって例外を無視するのが本当に適切だと言えるのであれば、例外を無視しても構いません。ただし、なぜそうするのか、きちんとした理由をコメントに入れておく必要があります。
/** If value is not a valid number, original port number is used. */
void setServerPort(String value) {
    try {
        serverPort = Integer.parseInt(value);
    } catch (NumberFormatException e) {
        // Method is documented to just ignore invalid user input.
        // serverPort will just be unchanged.
    }
}

#####汎用的例外の使用について#####

悪い例:

try {
    someComplicatedIOFunction();        // may throw IOException 
    someComplicatedParsingFunction();   // may throw ParsingException 
    someComplicatedSecurityFunction();  // may throw SecurityException 
    // phew, made it all the way 
} catch (Exception e) {               // I'll just catch all exceptions 
    handleError();                      // with one generic handler!
}

ほとんどの場合、汎用の Exception や Throwable をキャッチするのは適切ではありません。また、できるだけ Throwable を使わない方が望ましいです。

汎用の Exception をキャッチする代わりに、次のような手段をとることができます。

  • try の後、例外ごとに別の catch ブロックでキャッチする。これは不恰好に見えるかもしれませんが、すべての Exception をキャッチするよりましです。catch ブロックでは、同じコードを繰り返しすぎないよう注意してください。
  • 複数の try ブロックを使って、きめ細かくエラー処理するようリファクタリングする。パースから IO を分離して、それぞれ個別にエラー処理するようにしてください。
  • 例外を投げ直す。どうしてもこのレベルで例外をキャッチする必要がない多くの場合には、単にそのメソッドに例外を投げさせてください。

####ファイナライザについて####

ファイナライザとは、ここでは、オブジェクトがガベージコレクトされるときに実行されるコードのことを指す。

ファイナライザを使はないようにする。うまく例外処理することで、ファイナライザでやりたいことは大抵可能なため、どうしてもファイナライザが必要であれば、close() メソッド(のようなもの)を定義して、そのメソッドをいつ呼び出す必要があるのか、ドキュメントに明記する。

####インポートについて####

コードをインポートする際には、必ず ワイルドカードを使用しないスタイルを使用する。
ただし、Java標準ライブラリ(java.util., java.io. など)とユニットテストコード(junit.framework.*)についてはその限りではない。

また、順序については以下のとおりに行う。

  1. Android 関係のインポート
  2. サードパーティ製ライブラリ (com, junit, net, org)のインポート
  3. java および javax 関連のインポート

各グループ内では、アルファベット順にインポートします。
大文字は小文字よりも前にあるものと見なします。(例えば Z は a よりも前にある)。
大きなグループ分け (android, com, junit, net, org, java, javax) の間には空行を入れておくべきです。

####コメント/Javadocについて####

Javadocに入れるべき項目と順番

  1. コピーライト文
  2. package 文
  3. import 文
  4. クラスやインタフェースの宣言
  5. クラスやインタフェースの説明

そして、各ブロックの間は1行空けておく。

Example.java
/*
 * Copyright (C) 2010 The Android Open Source Project 
 *
 * 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.
 */

また、クラスと複雑なパブリックメソッドにはすべて、少なくともそのクラスやメソッドが何をするものか説明する一文を Javadoc コメントとして入れなければなりません。

####メソッドについて####

メソッドはできるだけ小さく、ポイントを絞ったものにする。
目安として、40行を超えるようであれば、プログラムの構造に影響を与えることなく分割できないか検討する。

####インデントについて####

ブロックのインデントにはスペース4つを使用する。タブは使用しない。
関数呼び出しと引数を含んだ行の折り返しは、スペース8つでインデントを行う

####[Java 1.5 アノテーションについて]####

アノテーションは同じ言語要素にある他の修飾子よりも前に置く。
アノテーションが複数ある場合、パラメータ付きのアノテーションの場合には、アルファベット順に1行ずつ並べる。
Java 1.5 で定義された3つのアノテーションについて、Android 標準のプラクティスは以下のようになります。

その要素の利用がもはや推奨されない時には、@Deprecated アノテーションを必ず付けなければならない。@Deprecated アノテーションを使うときには、@deprecated Javadoc タグも付けなければなりません。
そして、その代わりに使う実装について説明しておく。@Deprecated メソッドはまだ動作がサポートされていることも意味していることを忘れない。
もし @deprecated Javadoc タグが付いた古いコードがあれば、@Deprecated アノテーションを追加しておく。

メソッドがスーパークラスにある宣言や実装をオーバーライドしているときには、@Override アノテーションを必ず付けなければならない。

@SuppressWarnings アノテーションは、どうしても警告を取り除けない事情がある場合にのみ使用する。警告を「取り除けない」と判断したときには、@SuppressWarnings アノテーションを付けなければならない。すべての警告がコードにある実際の問題を反映するようにしておくためです。
@SuppressWarnings アノテーションが必要になったときには、その直前に TODO コメントを入れて、その警告を「取り除けない」事情について説明しておかなくてはいけません。こうすることで、やっかいなインタフェースをもつ問題のあるクラスだということがわかります。

###5.TODOについて###

コード中の TODO コメントは、一時的なものや、短期的な解決策、その場しのぎで完全ではないところなどに使用する。
TODO にはすべて大文字の TODO にコロンを続けたものにする。
また、Gitのissueなどに絡んだTODOである場合は、issue の ID をつけ、解決を他者に依頼する場合は @ マークの後に相手のユーザー名を記述するようにし、文末に中括弧で囲み記述する([...])。

例:

// TODO: Remove this code after the UrlTable2 has been checked in.

// TODO: Fix this error[Issue:30 @shun]

###6.Activity・Fragmentのインスタンス生成について###
Activity、FragmentなどのKeyPairの型情報が落ちたパラメーター情報を渡す可能性のあるインスタンス生成はcreateInstanceメソッドなどを用い、作成する側に型情報を教えるようにする。

###7.ログの出力について###

ログ記録は必要不可欠ですが、適度に簡潔にしておかないとパフォーマンスに悪影響を与え、役に立たなくなります。
ログ記録ファシリティにはレベルが5つあり、各レベルをいつどのように使うべきかは以下の通りです。

  • ERROR: このレベルは何か致命的なことが発生したときに使うべきです。
    つまり、ユーザにとって目に見えて重大で、データの削除やアプリケーションのアンインストール、データパーティションの削除、電話全体の再起動(あるいは、もっともっと悪いこと)といったことを明確にしないと復旧不能な問題が発生したときです。このレベルは必ずログに記録しておいてください。 通常、ERROR レベルでログ記録するような問題は、統計収集サーバに報告するのが望ましいです。
  • WARNING: このレベルは深刻な予期せぬことが発生したときに使うべきです。
    つまり、ユーザにとって目に見えて重大ですが、特定のアクションを実行すればデータを失うことなく復旧可能な問題が発生したときです。このアクションには、しばらく待つだけやアプリを再起動することから、アプリケーションの新しいバージョンを再ダウンロードしたり、デバイスをリブートすることまで、いろいろあります。このレベルは必ずログに記録しておいてください。 WARNING レベルでログ記録するような問題も、統計収集サーバへの報告を検討するのが望ましいです。
  • INFORMATIVE: このレベルは多くの人にとって関心のあることが発生したとき、それを通知するために使うべきです。
    つまり、広範囲な影響があるかもしれませんが、必ずしもエラーではないような状況です。これは、そのドメインにおいて最も信頼できると思われるモジュールによってのみログ記録されるべきです。(信頼できないコンポーネントによって、ログが二重に記録されるのを防ぐため)。このレベルは必ずログに記録しておいてください。
  • DEBUG: このレベルはデバイスに何が発生しているのか、想定外の動作を調査、デバッグするための情報を記録するときに使うべきです。
    あなたのコンポーネントに何が起こっているのか、必要十分な情報だけをログに記録すべきです。もしデバッグログがログの大部分を占めるようならば、それらは VERBOSE レベルで記録すべきです。DEBUG レベルはリリースビルドでも記録されるため、if (LOCAL_LOG) ブロックや if (LOCAL_LOGD) ブロックで囲んでおく必要があります。この LOCAL_LOG[D] はクラスやサブコンポーネントで定義され、こうしたログをすべて無効にできるようになっています。 したがって、if (LOCAL_LOG) ブロックにはアクティブな論理を入れてはいけません。ログに必要な文字列構築も if (LOCAL_LOG) ブロックのなかに入れておく必要があります。もし if (LOCAL_LOG) ブロックの外側で文字列構築しようとしているなら、ログ記録の呼び出しをメソッド呼び出しにリファクタリングしてはいけません。依然として if (localLOGV) を使っているコードもあります。これもまだ使えるのですが、名前付けは Android の標準に従っていません。
  • VERBOSE: 以上のレベルのいずれにも当てはまらないログはすべて、VERBOSE レベルを使うべきです。
    このレベルはデバッグビルドでのみログが記録されるよう、if (LOCAL_LOGV) ブロック(あるいは同等のもの)で囲んでおくべきです。こうすることで、デフォルトではコンパイルされなくなります。ログに必要な文字列構築は、リリースビルドに入らないよう、if (LOCAL_LOGV) ブロックのなかに入れておく必要があります。

重要な点として、DEBUGとVERBOSEは、リリースビルドではログが出力されないようif(LOCAL_LOGD)で囲むようにする。
また、ログの出力においてタグは以下のようにクラスのシンプルネームを使用する。


Log.d(getClass().getSimpleName(), "Sample log");

##Res(Resource)##

###1.命名規則###

####リソース名とID####

  • 小文字とアンダースコア()のみを用いる。 ※idをCamelCaseとしている例もあるが、drawableのファイル名にならいa-z0-9.のいずれかでなくてはいけないので、それに合わせる。
  • リソース名は、アルファベット順にソートされて表示されるので、関連するものが固まって表示されるように命名する。
    • activityやfragment、item、ic、img、bgなどの接頭辞を必ず付ける。
    • 例えば、グローバルなdrawableはbackground、horizontal_progress_bar、seek_bar_thumbなど、「何」
      を先頭に付ける。アイコンなどは、ic_で始める。
    • 一画面でしか使用されないローカルなdrawableは、その「場所」を先頭に付ける。例:「img_フラグメント名_用途名」
    • 文字列を画像にして使用する場合は、「string_フラグメント名_文字列の一部」と命名する

###2.Layoutのコーディング###

レイアウトは基本的に、階層が深くならないように配慮して書く。また、2箇所以上で共通して使用する設定に関しては、Styleとしてまとめ、そこを参照するようにする。

####RelativeLayoutについて####
RelativeLayout を使用して記述する場合は、基準となる View から先に記述していき、先に ID をつけるようにする。

####パディングについて####
パッディングは、対象の要素の階層よりも一つ下の要素に対して余白を設けたい場合に使用する。
また、padding は使用せずに、padding-left、padding-top、padding-right、padding-bottom を使用し個別に指定するようにする。

####マージンについて####
マージンは、対象の要素と同一の階層の要素に対して余白を設けたい場合に使用する。
また、要素1と要素2がxmlで上から並んでいる場合。要素2にマージンを指定し、余白を作るようにする。

####Width と Height について####
fill_parent は使用しないようにし、match_parent を使用する。
また、後ほどコードから値を変更する可能性がある場合は wrap_content を指定しておく。dp によって絶対値指定する場合は dimen の値を参照するようにする。

###3.Resource###

####Color####

色は、最低限以下の3つを用意する。

  • primary(メインの色 : 7割)
  • accent(サブの色 : 2割)
  • primary_text(テキストの色 : 1割)

また、上記の色で明るい色を作る場合は、{色名}_light、暗い色を作る場合は、{色名}_dark を作成する。透明度を指定をした色を作る場合は、{色名}alpha という形で用意するようにする。
他に、単一のクラス等で使用する色については、クラス名
{使用部分} という形で命名する。

####Dimens####

#####dp値について#####
dp値には原則として、奇数ではない48の因数、またはその組み合わせの値を使用する。padding、margin など向きのある値には vertical と horizontal の2つを用意する。
また、最初に以下のような値を用意しておき、これらの組み合わせで記述ができるものについては、こちらを使用するようにする。

dimens.xml
<!-- Common -->
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="element_spacing_large">12dp</dimen>
<dimen name="element_spacing_normal">8dp</dimen>
<dimen name="element_spacing_small">4dp</dimen>
<dimen name="view_height_large">64dp</dimen>
<dimen name="view_height_normal">48dp</dimen>
<dimen name="view_height_small">36dp</dimen>
<dimen name="view_height_tiny">24dp</dimen>

#####sp値について#####
テキストサイズは、すべてsp値で記述するようにする。また、テキストサイズにはあらかじめ以下のような値を用意しておく。上のサイズ別のものは、TextViewで主にappearanceにて使用するもので、下のものについてはButtonやTitleなどの各パーツ内でデフォルトで使用するものにするようにする。

dimens.xml
<!-- Text Size -->
<dimen name="text_size_ssmall">11sp</dimen>
<dimen name="text_size_small">12sp</dimen>
<dimen name="text_size_medium">14sp</dimen>
<dimen name="text_size_large">18sp</dimen>
<dimen name="text_size_xlarge">20sp</dimen>

<dimen name="text_size_body">@dimen/text_size_small</dimen>
<dimen name="text_size_title">@dimen/text_size_large</dimen>
<dimen name="text_size_subtitle">@dimen/text_size_medium</dimen>
<dimen name="text_size_menu">@dimen/text_size_medium</dimen>
<dimen name="text_size_caption">@dimen/text_size_small</dimen>
<dimen name="text_size_button">@dimen/text_size_large</dimen>

#####dimens.xmlについて#####
各画面やShapeファイル、クラスごとに用意する値についてはレイアウトファイルごとに のようにコメントをつけ、どのリソースで使用するものなのかを明確にするようにする。

####Strings####

アプリケーション内でユーザーが閲覧する文字列については、すべてstrings.xml に記述する。
また、文字列の一部を変更して使用するものについては、%1$dなどで置き換えられるようにして記述し、なるべくコード内での文字列操作は行わないようにする。

AndroidManifest に記述する値については、build.gradleに記述するようにする。
APIキーなどの値に関しては、AppConfig.java にstaticな値として記述するようにする。

#####strings.xmlについて#####
各画面やShapeファイル、クラスごとに用意する値についてはレイアウトファイルごとに のようにコメントをつけ、どのリソースで使用するものなのかを明確にするようにする。

###3.Styleのコーディング###

スタイルの管理は、主に以下の3つのファイルで行う。

  • theme.xml (テーマの参照をまとめておくファイル)
  • styles.xml (ButtonやEditTextなどのコンポーネントのスタイルをまとめておくファイル)
  • styles_text.xml (文字のスタイルをまとめておくファイル)

theme.xml内のアイテムは最低限以下の要素を用意するようにする。

theme.xml
<item name="colorPrimary">@color/primary</item>
<item name="colorPrimaryDark">@color/primary_dark</item>
<item name="colorAccent">@color/accent</item>

##その他・参考##

Android Open Source Project
日本語訳

448
465
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
448
465

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?