【Android】もっと先へ「加速」したくはないか、少年 〜File Template編〜


## 前置き

Android Studio使い立てのAndroid Studioユーザー対象です。

たとえばなんですが、ContentProviderって毎回ほぼほぼ同じ事書いてませんか？
僕は書いてます。驚くほど毎回同じです。
多少の型、テーブル名とswitch文の中身が違うくらいです。

あげく、月一で書く訳でもないので毎回忘れてる訳です。

毎回のように前に書いたコードを見ながらほぼほぼ同じコードを書く訳です。
Javadocも合わせると150行強くらい書く訳です。
こんなに生産性があるように見える非生産的な時間はないです。
まさにサボり屋にはもってこいです。いかに生産性があるように見せかけるか。甘美な響きです。

ですが世間にはサボっても自分の首が絞まるだけの方も居ると思います。私もその類いです。

Android Studioを使えば(正確に言うとIntelliJ)この生産的に見せかけて非生産的な作業を限りなくゼロ時間へ持っていけます。

ゼロ時間は少し違いますね。盛りました。多少の型、テーブル名とswitch文の中身くらいは書きます。
長引かせて既知の方いたらごめんなさい。

File Templateを使います。

## File Templateとは

その名の通り、FileのTemplateです。
習うより慣れろです。
早速作ってみましょう。

## File Templateの作り方

Android StudioのPreferenceを開いて、「File and Code Templates」を選択します。

<img src="https://qiita-image-store.s3.amazonaws.com/0/47114/d58f021b-6b9b-3aac-5d32-25920a938fbd.png" width="700"/>

緑色の「＋」を押すとTemplatesの中にUnnamedというのができてNameの中にカーソルが行くので適当な名前を付けます。

<img src="https://qiita-image-store.s3.amazonaws.com/0/47114/61821b3c-be8d-2d39-da80-94328f11b04c.png" width="700" />

あとは右上の真っ白なところにテンプレートを差し込めば完了です。

## 例
僕はContentProviderというテンプレートを作って下記をぶっ込んでます。
空行、コメント合わせて171行分です。
(じつはこれ使ってもコメントアウトしているせいでエラーがでるんですが、そこは自力でそのときのアプリ用に直します。参考のためにコメントアウトしています。)


```
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
#parse("File Header.java")

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.provider.BaseColumns;
import android.text.TextUtils;

public class ${NAME} extends ContentProvider {

    /** Authority */
    public static final String AUTHORITY = "$AUTHORITY";

 //   /** sync calendar テーブルID */
 //   private static final int SYNC_CALENDARS = 1;
 //   /** sync calendar テーブル個別ID */
 //   private static final int SYNC_CALENDAR_ITEM = 2;
    /** Uriマッチャー */
    private static UriMatcher sUriMatcher;
    static {
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
 //       sUriMatcher.addURI(AUTHORITY, SyncCalendarColumns.PATH, SYNC_CALENDARS);
 //       sUriMatcher.addURI(AUTHORITY, SyncCalendarColumns.PATH+ "/#", SYNC_CALENDAR_ITEM);
    }
    /** DBヘルパー */
    private $DBHelper mDBHelper;

    @Override
    public boolean onCreate() {
        mDBHelper = new EventAlarmDatabaseHelper(getContext());
        return true;
    }

    /**
     * query実行
     * @param uri クエリURI
     * @param projection フィールド
     * @param selection where句条件
     * @param selectionArgs where句にいれる変数
     * @param sortOrder ソート条件
     * @return query結果
     */
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
        switch (sUriMatcher.match(uri)) {
            // case SYNC_CALENDARS:
            // case SYNC_CALENDAR_ITEM:
            //     queryBuilder.setTables(SyncCalendarColumns.TABLE);
            //     break;
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
        SQLiteDatabase db = mDBHelper.getReadableDatabase();
        Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder);
        return cursor;
    }

    /**
     * コンテントタイプ取得
     * @param uri Uri
     * @return コンテントタイプ
     */
    @Override
    public String getType(Uri uri) {
        switch(sUriMatcher.match(uri)) {
            // case SYNC_CALENDARS:
            //     return SyncCalendarColumns.CONTENT_TYPE;
            // case SYNC_CALENDAR_ITEM:
            //     return SyncCalendarColumns.CONTENT_ITEM_TYPE;
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
    }

    /**
     * insert実行
     * @param uri URI
     * @param values 値
     * @return 結果URI
     */
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        String insertTable;
        Uri contentUri;
        switch (sUriMatcher.match(uri)) {
            // case SYNC_CALENDARS:
            //     insertTable = SyncCalendarColumns.TABLE;
            //     contentUri = SyncCalendarColumns.CONTENT_URI;
            // break;
            // case SYNC_CALENDAR_ITEM:
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
        SQLiteDatabase db = mDBHelper.getWritableDatabase();
        long rowId = db.insert(insertTable, null, values);
        if (rowId > 0) {
            Uri returnUri = ContentUris.withAppendedId(contentUri, rowId);
            getContext().getContentResolver().notifyChange(returnUri, null);
            return returnUri;
        } else {
            throw new IllegalArgumentException("Failed to insert row into " + uri);
        }
    }

    /**
     * delete実行
     * @param uri URI
     * @param selection where句条件
     * @param selectionArgs where句にいれる変数
     * @return deleteしたレコード数
     */
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        SQLiteDatabase db = mDBHelper.getWritableDatabase();
        String customSelection;
        int count;
        switch (sUriMatcher.match(uri)) {
            // case SYNC_CALENDARS:
            //     count = db.delete(SyncCalendarColumns.TABLE, selection, selectionArgs);
            //     break;
            // case SYNC_CALENDAR_ITEM:
            //     customSelection = SyncCalendarColumns._ID + "=" + uri.getPathSegments().get(1) + (!TextUtils.isEmpty(selection) ? "AND (" + selection + ")" : "");
            //     count = db.delete(SyncCalendarColumns.TABLE, customSelection, selectionArgs);
            //     break;
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }

    /**
     * update実行
     * @param uri URI
     * @param values 値
     * @param selection where句条件
     * @param selectionArgs where句にいれる変数
     * @return updateしたレコード数
     */
    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        SQLiteDatabase db = mDBHelper.getWritableDatabase();
        int count;
        String customSelection = selection;
        String id = uri.getPathSegments().get(1);
        if (customSelection == null) {
            customSelection = "";
        }

        String updateTable;
        switch (sUriMatcher.match(uri)) {
            // case SYNC_CALENDARS:
            // case SYNC_CALENDAR_ITEM:
            //     updateTable = SyncCalendarColumns.TABLE;
            //     break;
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }

        count = db.update(updateTable,
                values,
                BaseColumns._ID + "=" + id + (!TextUtils.isDigitsOnly(customSelection) ? " AND (" + customSelection + ")" : ""),
                selectionArgs);
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }
}
```

## File Templateを使ってみる

いつも通り New -> Java ClassとするとClass名を入力するポップアップが出ると思うんですがそこで「Class」を展開してみると、、
現れました！「Content Provider」！！

<img src="https://qiita-image-store.s3.amazonaws.com/0/47114/a794328e-ffb3-424c-1265-50e34da225f0.png" width="400" />

選択してみると、、、
「AUTHORITY」と「DBHelper」を入力せよポップアップが出てきました！
これは例にある $AUTHORITY と $DBHelper です。
何か自分で入力したいときはこの方法が使えます。

<img src="https://qiita-image-store.s3.amazonaws.com/0/47114/fc59855f-078f-4cf6-4806-9e31afba14fa.png" width="300" />

あとは「OK」を押すだけです！
これでテンプレートが作成できます！

簡単ですね！

## まとめ

１ファイルレベルで毎回同じような事を書いている場合は速攻File Templateを登録しましょう！
早い上、前のコードを探す必要もなくなります。
デザインパターンとかはもってこいですね。
どんどん登録して加速世界の高みをめざしましょう！

## バーストリンカーなら合わせて読みたい
・[【Android】もっと先へ「加速」したくはないか、少年 〜Project Template編〜](http://qiita.com/kgmyshin/items/9c803a21451e603531f0)