AndroidのSharedPrefencesを取り回しやすくするライブラリを作った

AndroidのSharedPrefencesを取り回しやすくするライブラリをこっそり作ったのでアドベントカレンダーに便乗して紹介しようと思うまる

# Preferhythm

https://github.com/KazaKago/Preferhythm
[![Download](https://api.bintray.com/packages/kazakago/maven/preferhythm/images/download.svg)](https://bintray.com/kazakago/maven/preferhythm/_latestVersion) [![Build Status](https://app.bitrise.io/app/ae4ee3f69a27ccc5/status.svg?token=OUnnoRKMjEkYyhc-CXyPQQ&branch=master)](https://app.bitrise.io/app/ae4ee3f69a27ccc5) [![license](https://img.shields.io/github/license/kazakago/preferhythm.svg)](LICENSE.md)

## What's this?

Androidアプリを開発すると値を端末に保存することがあると思いますが、そんなときはだいたいSharedPreferencesを使いますよね。
ただ、個人的には使いづらいというかtypoとかのヒューマンエラーの温床になりそうだなーとずっと思っていたので、なら作ればいいじゃん精神でSharedPreferencesのラッパーライブラリを作りました。
↓のようなお決まりのコードを書いてる人が多いと思うのでAnnotation Processorによるコード自動生成を使って簡略化させてます。

```kotlin
class MyPreferences(context: Context) {

    private val preferences = context.getSharedPreferences("MyPref", Context.MODE_PRIVATE)
    private val tokenKey = "session_token"

    fun getToken(): String? {
        return preferences.getString(tokenKey, null))
    }

    fun setToken(value: String?) {
        val editor = preferences.edit()
        editor.putString(tokenKey, value)
        editor.apply()
    }

}
```

このライブラリを使うと上記のコードが↓になります。

```kotlin
@PrefClass
class MyPreferences {

    @PrefField
    val token: String?
}

```

これによって保存する値が増やすときにに「コピペ加工したけど変更漏れがないか気になって仕方ない症候群」から開放されるかもしれないｗ

## Requirement

- Android 4.0.3 (API 15) 以上

## Install

利用するモジュールのgradle.buildに以下を追記して下さい。
Kotlinの場合は`apply plugin: 'kotlin-kapt'`をお忘れなく。

### Java

```groovy
dependencies {
    implementation 'com.kazakago.preferhythm:preferhythm:x.x.x'
    annotationProcessor 'com.kazakago.preferhythm:preferhythm-processor:x.x.x'
}
```

### Kotlin

```groovy
apply plugin: 'kotlin-kapt'

dependencies {
    implementation 'com.kazakago.preferhythm:preferhythm:x.x.x'
    kapt 'com.kazakago.preferhythm:preferhythm-processor:x.x.x'
}
```

LatestVersionはこちら→ [![Download](https://api.bintray.com/packages/kazakago/maven/preferhythm/images/download.svg)](https://bintray.com/kazakago/maven/preferhythm/_latestVersion)

## Usage

Preferencesのモデルにしたいクラスに`@PrefClass`アノテーションを付与して、
保存したいフィールド変数に`@PrefField`アノテーションをくっつければモデルの設定は終わりです

```java
@PrefClass // SharedPreferences用のモデルクラスに @PrefClass をつけて下さい
class MyPreferences {

    @PrefField // 保存したい値ごとに @PrefField を付けて下さい
    int intValue = 3; // 値がないときのデフォルト値は3

    @PrefField
    boolean booleanValue; // 値がないときのデフォルト値はboolean型のデフォルトと同様のfalse

    @PrefField
    String stringValue; // 値がないときのデフォルト値はnull

    @NonNull
    @PrefField
    String nonNullStringValue = "foo"; // 値がないときのデフォルト値は"foo"。また @NonNull アノテーションをつけることで生成されるメソッドにも反映させることが可能です

}
```

上記の状態でビルドを行うと「`@PrefClass`をつけたモデルクラス名+Manager」という名前のクラスが自動生成され、
`＠PrefField`をつけたフィールドごとにセッターゲッターが自動的に実装されているのでそのメソッドにセットしてapply()すれば保存されます。これだけ！

```java
public class MainActivity extends Activity {

    // `MyPreferencesManager`が自動生成されます
    private MyPreferencesManager myPreferencesManager = new MyPreferencesManager(this);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        System.out.print(myPreferencesManager.getIntValue()); // 3 (デフォルト値)

        myPreferencesManager.setIntValue(100); // 100をセット
        myPreferencesManager.commit(); // 変更を反映させるときはSharedPreferencesと同様にcommitかapplyを呼んで下さい

        System.out.print(myPreferencesManager.getIntValue()); // セットした100になります
        
        myPreferencesManager.clear(); // MyPreferencesManagerに内包されている値を消去
        myPreferencesManager.commit();

        System.out.print(myPreferencesManager.getIntValue()); // 3 (再びデフォルト値になります)
    }

}
```

リポジトリ内に[Java](https://github.com/KazaKago/Preferhythm/tree/master/samplejava) と [Kotlin](https://github.com/KazaKago/Preferhythm/tree/master/samplekotlin)で動作するサンプルを含んでいるのでそちらもご覧ください

## Important

### Preferences名

デフォルトではSharedPreferences名はクラス名が反映されます
これが不都合な場合はアノテーションパラメータをいじることで自由に変えることも可能です

```java
@PrefClass("YOUR_ORIGINAL_PREFERENCES_NAME")
class YourPreferencesClass {

...

}

```

### キー名

同様にSharedPreferencesへ保存する場合のキー名もデフォルトではフィールド変数名が反映されますが
これもアノテーションパラメータへ任意の文字列を突っ込むことで変更できます

```java
@PrefClass
class YourPreferencesClass {

    @PrefField("YOUR_ORIGINAL_KEY_NAME")
    int yourSaveValue;

}

```

すでに実装済みのSharedPreferecneやキーを引き継いで使いたい場合なんかはこのオプションを使って下さい

## Advanced

### Getter,Setterメソッドのオーバーライド

自動生成された「`@PrefClass`をつけたモデルクラス名+Manager」クラスは継承が可能なのでメソッドをオーバーライドすることで任意の処理を割り込ませることも出来ます

```java
public class CustomMyPreferencesManager extends MyPreferencesManager {

    public CustomMyPreferencesManager(@NonNull Context context) {
        super(context);
    }
    
    @Nullable
    @Override
    public String getStringValue() {
        // 必要に応じてなんやかんやしてください
        // ex) 復号化とか
        return super.getStringValue();
    }

    @NonNull
    @Override
    public MyPreferencesManager setStringValue(@Nullable String value) {
        // 必要に応じてなんやかんやしてください
        // ex) 暗号化とか
        return super.setStringValue(value);
    }

}
```

## Kotlin Support

本ライブラリはKotlinから使われることも想定しておりNullable,NonNull構文を考慮したコードが生成されます。

```kotlin
@PrefClass
class MyPreferences {

    @PrefField
    val intValue: Int = 3 // NonNullかつデフォルト値は3

    @PrefField
    val booleanValue: Boolean = false // NonNullかつデフォルト値はfalse

    @PrefField
    val stringValue: String = "foo" // NonNullかつデフォルト値は`foo`

    @PrefField
    val nullableStringValue: String? = null // Nullableかつデフォルト値はnull

    @PrefField
    val nullableStringWithInitValue: String? = "bar" // Nullableかつデフォルト値は"bar"

}
```

## Supported Type

本ライブラリでサポートしている型は以下の通りです
SharedPreferencesのラッパーライブラリなのでサポートされている型はそれと同じです。詳しくは[公式ドキュメント](https://developer.android.com/training/data-storage/shared-preferences.html)をご覧ください

- Primitive Type
    - int
    - long
    - float
    - boolean
- Object Type
    - Integer
    - Long
    - Float
    - Boolean
    - String
    - Set<String>

## License

MITライセンスにより配布しています