新しく使えるようになった13個のSupport Annotations


Google I/Oの[What’s New in Android Development Tools](https://www.youtube.com/watch?v=f7ihSQ44WO0&feature=youtu.be&t=24m7s)(動画の24:07くらいから)で紹介されたsupport-annotations 22.2から使えるようになった新しい13のアノテーションについてメモ。

## 環境

今回、お試しした環境は以下のとおり。
Android Mをターゲットにしていますがそれ以前のバージョンでも使えるのではないかと思います。

- Mac OS X: 10.10.3
- Android Studio: 1.3 Preview 2
- Gradle plugin: 1.3.0-beta2
- Build tools: 23.0.0 rc2
- Target SDK: MNC

## 使い方

biuld.gradleのdependenciesに以下を追加するだけです。

```gradle
compile 'com.android.support:support-annotations:22.2.0'
```

## @WorkerThread, @UiThread, @MainThread, @BinderThread

この4つのアノテーションはメソッドの実行スレッドを明示することができます。
例えば、

```java
    @WorkerThread
    private void myWorkerMethod(TextView textView) {
        textView.setText("Worker Thread!");
    }
```

このように@WorkerThreadでアノテーションしたメソッド内でUI操作を書くと「UIスレッドで呼んでね！」と怒ってくれます。
![@WorkerThread](https://qiita-image-store.s3.amazonaws.com/0/53706/4e020996-680d-7d00-5f50-693c748632d1.png "myworker.png")


逆に次のようにUIスレッドで動作させることを明示しているメソッドをAsyncTaskの中などで呼ぼうとした時にも怒ってくれます。

```java
    @UiThread
    private void myUiMethod(TextView textView) {
        textView.setText("UI Thread!");
    }

    public AsyncTask testTask() {
        return new AsyncTask() {
            @Override
            protected Object doInBackground(Object[] params) {
                myWorkerMethod(mTextView);
                myUiMethod(mTextView);
                return null;
            }
        };
    }
```

![@UiThread](https://qiita-image-store.s3.amazonaws.com/0/53706/24c71460-3b06-025c-323b-05598e9ca114.png "myUI.png")

### @UiThreadと@MainThreadの違い

ドキュメントによると、極めて稀なケースではあるがアプリが別ウインドウを実行するためにメインスレッドとは別のUIスレッドを作ることがあるらしい。
なので、普通に使っている分には@UiThreadと@MainThreadの違いを気にする必要は無さそう。

### Tips

例としてメソッドにアノテーションを付与してみましたが、Viewの拡張クラスのようにクラス全体がUIスレッドで動作することが要求される場面ではクラスにアノテーションを付けることも可能とのこと。

##  @Size

メソッドの引数にサイズの最小値、最大値を指定したり、

```java
    private void log(@Size(min = 1, max = 23) String tag) {
        Log.d(tag, "Logging!");
    }

    private void sizeTest() {
        log("This is too long text for tag");
        log("Appropriate tag");
        log("");
    }
```

![MaxMin](https://qiita-image-store.s3.amazonaws.com/0/53706/985cb3c4-5760-dab0-d132-2ff0976a4b42.png "log.png")

配列のサイズを指定したり、

```java
    public void setViewPosition(@Size(2) int[] position) {}

    private void sizeTest2() {
        int[] position = new int[3];
        setViewPosition(position);
    }
```

![ArraySize](https://qiita-image-store.s3.amazonaws.com/0/53706/24f6ec4e-8153-208f-d75a-58366da53aae.png "arraysize.png")

配列のサイズを2の倍数に指定したり(x,y座標の組み合わせを受け取りたいときとか)、

```java
    public void setViewPosition2(@Size(multiple = 2) int[] positions) {}

    public void sizeTest3() {
        int[] positions = new int[5];
        setViewPosition2(positions);
    }
```

というように引数のサイズを指定することが出来ます。
...が **不具合？** なのか自分の環境では配列サイズの条件にマッチする引数を渡してもエラーになる...


![Error](https://qiita-image-store.s3.amazonaws.com/0/53706/84242b9e-96a5-0952-0dde-86f62b739761.png "error.png")

**追記**
本日配信されたAndroid Studio 1.3 Preview 3で配列サイズの条件を満たしていてもエラーになる不具合が解消されていました。
![AS1.3](https://qiita-image-store.s3.amazonaws.com/0/53706/f4370eb2-d1fe-416d-714f-a9c61aae29d0.png)

## @IntRange, @FloatRange

メソッド引数に渡される値の許容範囲を指定できます。

```java
    private void setViewAlpha(@FloatRange(from = 0.0, to = 1.0) float alpha) {}
    
    private void testRange() {
        setViewAlpha(0.5f);
        setViewAlpha(100f);
    }
```

![range.png](https://qiita-image-store.s3.amazonaws.com/0/53706/44693c18-1ccd-2660-33b4-3f42931330d1.png "range.png")

## @ColorInt

色の情報を渡すとき、リソースIDなのか色のInt値なのか区別を付けるためのアノテーションです。
@ColorIntを付けた引数にリソースIDを渡すとエラーになります。

```java
    private void setViewColor(@ColorInt int color) {}

    private void testColorInt() {
        setViewColor(Color.BLUE);
        setViewColor(android.R.color.black);
    }
```

![ColorInt](https://qiita-image-store.s3.amazonaws.com/0/53706/751dd010-33e2-675f-cfce-b907b818c019.png "colorint.png")

## @CallSuper

継承先のクラスでメソッドをオーバライドした際に、superを呼ぶ必要が有ることを明示できます。

```java

public class BaseClass {
    @CallSuper
    public void baseMethod() {
        Log.d("TEST", "You need call super!");
    }
}

public class ExtendedClass extends BaseClass {
    @Override
    public void baseMethod() {
        Log.d("TEST", "Do I have to call super?");
    }
}
```

![CallSuper](https://qiita-image-store.s3.amazonaws.com/0/53706/b9bd3218-d297-96c7-8c10-d676f7c648fa.png "callsuper.png")


## @CheckResult

このアノテーションを付けたメソッドの返り値を使用していないと怒られるようになります。
また、他のメソッドを使うようにサジェストすることもできます。

```java
    @CheckResult(suggest = "#validate(int)")
    private boolean isValid() {
        return true;
    }

    private boolean validate(int id) {
        {
            // do validate something
        }
        return true;
    }

    private void testCheckResult() {
        isValid();
    }
```

![CheckResult](https://qiita-image-store.s3.amazonaws.com/0/53706/8bf552fe-58a1-f319-a723-29c6ca6e0efd.png "checkresult.png")

## @RequiresPermission

パーミッションが必要なメソッドを明示できます。
指定の仕方も「どれか」「ぜんぶ」など色々な指定の仕方ができるようです。

```java
    @RequiresPermission(anyOf = {
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.ACCESS_FINE_LOCATION})
    private void getLocation() {}

    @RequiresPermission(allOf = {
            Manifest.permission.READ_CALENDAR,
            Manifest.permission.WRITE_CALENDAR})
    private void updateCalendar() {}
    
    private void testPermission() {
        getLocation();
        updateCalendar();
    }
```

![Permission](https://qiita-image-store.s3.amazonaws.com/0/53706/6018b281-5e51-33c3-794f-21c49bad50a9.png "permission.png")

また、エラーになっている箇所で"⌥+Enter"すると、AndroidManifestへのパーミッション追加やパーミッションのチェック処理を追加することができます。

![PermissionAnim](http://i.gyazo.com/dc2446b3ccec0ab718e55a4827dd5cfa.gif)

## @VisibleForTesting

~~テスト用にクラス、メソッド、フィールドの可視範囲を広げることができます。~~

とドキュメントには書いているんですが、privateなフィールドやメソッドにこのアノテーションをつけてもテストからはアクセス出来なかったです。
使い方を間違っているのか不具合なのか...うまく使える方、使い方教えてください。

**追記**
コメント欄で@fkmさんに指摘頂きました。完全に自分のドキュメント読み間違えです。

> This annotation lets you declare that a class, method or field is more visible than necessary, in order to be able to access it from tests.

とあるので「テストのためにクラス、メソッド、フィールドが必要以上の可視性を持っていることを明示できる」が正しいです。

## @Keep

アプリの最小化時(Proguardのことかな？)に保持すべきメソッドやクラスにアノテーションを付けることができます。
**でもまだ使えません！**

## おわり

うまく使えば入力値やメソッドの使い方をある程度制限することができるので、特に複数人で開発するようなときは期待しない使い方をされることを抑えてバグの混入を減らすのに役立つかもしれません。

## 参考

Google I/Oのセッション動画: [Google I/O 2015 - What's New in Android Development Tools - YouTube](https://www.youtube.com/watch?t=1471&v=f7ihSQ44WO0)
ドキュメント: [Support Annotations - Android Tools Project Site](http://tools.android.com/tech-docs/support-annotations)