Android で PreferenceActivity 使ってみた

# PreferenceActivity とは
Android アプリにおいて、アプリの設定をする機能を提供してる。

設定は階層構造になったたくさん項目があったりするが、一個の Activity でそれを表現できる [^1]。ListView を継承していて、設定項目用の xml なども容易に定義できるし、保存された設定項目を `SharedPreferences` でアプリのどこからでも呼び出せるようになる。タブレット端末など大きめな端末を横長に向けたときに、1層目がサイドメニューになり、2層目を右側に表示するというようなことができるようになる。

[^1]: むしろ煩雑になるような気もするけどどうなんでしょう。

（たぶん）

# 使ってみた
Android のバージョンは 7で作業しています。

## 作業してみた順
この分野については詳しくないので、とりあえず新しいアプリを作った。最初に Activity を選ぶところで `Settings Activity` っていうのを選ぶ。<img width="897" alt="スクリーンショット 2018-03-15 20.06.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/117087/7a715acd-8421-66c9-6e32-552b91e9e3f2.png">
これで、設定項目を変更するだけのアプリが作れる。ビルドすればアプリを動かせる。楽しい

既存アプリに追加もしたくてどうするか迷ったが、自動で生成されたコードのうちのどれが必要かイマイチ分からなくて萎えたので、 Android Studio の New -> Activity -> Settings Activity から、こちらも自動生成でずどんと追加してみた。

んで、いろいろいじっていくと。

ここに詳しく書いてある。
https://developer.android.com/guide/topics/ui/settings.html?hl=ja

## 構造

サンプルで作ると、2層構造になる。

```
-+- General
 |  |- Enable social recommendations
 |  |- Display name
 |  `- Add friends to messages
 |
 |
 |- Notifications
 |  |- New message notifications
 |  |- ...
 |
 |
 `- Data Sync
    |- Sync frequency
    |- ...
```

1層目|2層目
----|----
<img width="441" alt="スクリーンショット 2018-03-15 20.39.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/117087/b583a3eb-ac52-bec5-1f4a-45708ad6cf26.png">|<img width="441" alt="スクリーンショット 2018-03-15 20.39.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/117087/89c4fb4b-2ee3-f62e-0285-ed90c7046c32.png">

## 作られたファイル
* res/xml/pref_headers.xml 上記の1層目、 General / Notifications / Data Sync の3つを選ぶ ListView が出てくる。編集の必要あり
* その他の res/xml/pref_*.xml 2層目の各項目に対応。編集の必要あり
* res/drawable/*.xml アイコン。必要なやつだけコミットすればよし
* activity/AppCompatPreferenceActivity.java いろいろ書いてある親クラス (後述)
* activity/SettingsActivity.java 設定を変更したときの動きなどを記述する。編集の必要あり

Activity が一個というのが面白いと思った。

## 実装したメモ

### Activity で要らなかったやつ
AppCompatPreferenceActivity を継承して SettingsActivity を作ったが、 `AppCompatPreferenceActivity` にあった実装のうち動かすのに必要だったのは

```java
public class SettingsActivity extends PreferenceActivity {
    private AppCompatDelegate mDelegate;

    private AppCompatDelegate getDelegate() {
        if (mDelegate == null) {
            mDelegate = AppCompatDelegate.create(this, null);
        }
        return mDelegate;
    }

    public ActionBar getSupportActionBar() {
        return getDelegate().getSupportActionBar();
    }
```
これだけだった。

もう一個親クラスの PreferenceActivity を読んでみると override しろってたくさん書いてあるから、削除するともしかしたら落ちるかもしれない。けど、意味のわからない 300行のコードを「自動生成されたから」というだけでコミットしてしまうのはちょっと気が引けたので、削ってしまった。

### headers から、他のアクティビティに飛ばす
設定画面を本格的に作るより前に、一つだけ既に画面があったので、項目のうちの一つはそこに飛ばしたかった

```xml:pref_headers.xml
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
    <header
        android:title="@string/foo_bar">
        <intent
            android:action="android.intent.action.MAIN"
            android:targetPackage="com.example.project"
            android:targetClass="com.example.project.activity.FooBarActivity" >
        </intent>
```

こうやって書くと FooBarActivity が開ける。値を渡したり戻り値をとったりすることもできるっぽいが、特に必要がなくてやっていない。

### headers の画面の左上矢印から、他のアクティビティに戻る
サンプルコードでは `Fragment` に `onOptionsItemSelected` が実装されているが、これは2層目の矢印の挙動を定めている。1層目の headers の画面での矢印に対して動作をさせるためには、 **Activity に** `onOptionsItemSelected` を足す。

```java
public class SettingsActivity extends PreferenceActivity {
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == android.R.id.home) {
            finish();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
```

こちらに教わりました。 http://rikisha-android.hatenablog.com/entry/2014/04/04/202207

### 保存した設定値を呼び出す
使いたいところで

```java
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
        sharedPref.getBoolean("foo_bar_boolean_setting", false)
```

こう書いちゃう。楽チン。

アプリ内のデータ保存って... sqlite？ どうやってアクセスするんだっけ？みたいなレベルの自分には非常に嬉しい。

### 現在の設定内容をテキストで表示する
ことができる。これから挑戦。

### 変更後、データをサーバに保存する
これから挑戦。きっと Fragment に何かを書くんだ。

# 困ったこと
## 不明点1: 1層目 preference-headers の各行の高さを変えたりラインを入れたりできない
ちょっと見づらいのだがどうすりゃいいのか分からなかった....諦め気味。


1層目|2層目
----|----
<img width="441" alt="スクリーンショット 2018-03-15 20.39.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/117087/b583a3eb-ac52-bec5-1f4a-45708ad6cf26.png">|<img width="441" alt="スクリーンショット 2018-03-15 20.39.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/117087/89c4fb4b-2ee3-f62e-0285-ed90c7046c32.png">

2層目はきれいなのに。


## 不明点2: 1層目で選択時にダイアログを表示したい
ログアウトっていう項目を作ろうと思ったが、特に2層目はないので、「ログアウトしますか？」ってダイアログを表示したい。

こちらは調査中