【Android】PreferenceActivity/PreferenceFragmentを使った設定画面
(追記) 2018/11/15 書き直しました。
Androidの設定画面について
- AndroidではAPI1から設定画面を生成してくれるPreferenceActivityが用意されている
- Android 3.0で各設定画面をFragmentに分けるためのPreferenceFragmentが追加された
- Android 4.0ではPreferenceActivityが拡張され、PreferenceFragmentと組み合わせることでハンドセットでは1画面、タブレットでは2画面の設定画面を自動的に作成できる
設定項目
クラス | 説明 |
---|---|
CheckBoxPreference | オン/オフの設定項目 |
SwitchPreference | オン/オフの設定項目 API14から |
ListPreference | リストの中から1つ選ぶ設定項目 |
MultiSelectListPreference | リストの中から複数を選ぶ設定項目 |
EditTextPreference | 入力からの設定 |
1画面の設定画面
- 設定画面を2ページに分けない場合は、画面のルートに当たるandroid.R.id.contentに直接PreferenceFragmentを設定する
PreferenceActivity
public class SettingActivity extends PreferenceActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getFragmentManager().beginTransaction() .replace(android.R.id.content, new SettingFragment()) .commit(); } }
PreferenceFragment
- addPreferencesFromResource()で設定画面を定義したXMLを読み込む
- 必要であれば、onActivityCreated()で各設定項目の初期値等を設定する
- XMLで設定したPreferenceを取得するにはandroid:keyを使い、PreferenceFragment#findPreference()で行う
public class SettingFragment extends PreferenceFragment { public SettingFragment() { // Required empty public constructor } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.setting_fragment); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); initView(); } private void initView() { ListPreference listPreference = (ListPreference)findPreference(getString(R.string.key_list_preference)); listPreference.setValueIndex(0); } }
PreferenceFragmentから読み込む設定XML
- PreferenceFragmentから読み込むXMLのトップはPreferenceScreenでなければならない
- 各Preferenceにはandroid:keyを設定しなければならない。これが各Preferenceを特定するIDとなる。
- カテゴリを設定する場合はPreferenceCategoryを使う。android:keyは必須ではない。
- ListPreferenceの場合、選択候補に表示されるリスト(android:entries)と実際の値のリスト(android:entryValues)を設定する必要がある
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > <PreferenceCategory android:title="Category Title" > <ListPreference android:title="Title" android:key="@string/key_list_preference" android:entries="@array/entry_sample" android:entryValues="@array/entry_sample_values"/> </PreferenceCategory> </PreferenceScreen>
その他の属性は以下を参照
http://developer.android.com/reference/android/preference/Preference.html
array.xml
ListPreferenceで使う値を定義する
<resources> <array name="entry_sample"> <item>@string/entry1</item> <item>@string/entry2</item> </array> <string-array name="entry_sample_values"> <item>1</item> <item>0</item> </string-array> </resources>
string.xml
<resources> <string name="entry1">Entry1</string> <string name="entry2">Entry2</string> <string name="key_list_preference">KeyListPreference</string> </resources>
初期値設定
XMLで初期値を設定する場合はandroid:defaultValueに設定する。SharedPreferenceから保存した値を読み込んでそれに応じて初期値を設定する場合など、Javaコードの中で初期値を設定を行う場合はPreferenceによって設定方法が異なる
SwitchPreference
setChecked()で行う
SwitchPreference switchPref = (SwitchPreference)findPreference(getString(R.string.key_internal_browser));
switchPref.setChecked(true);
ListPreference
- ListPreferenceのentryValuesのstring-arrayの各itemが数字だとsetDefaultValue()が動かなかった
- setValueIndex()を使うことで解決
- entryValuesをinterger-arrayにするとNullPointerExceptionで落ちてしまう
参考
- http://developer.android.com/reference/android/preference/PreferenceActivity.html
- http://developer.android.com/reference/android/preference/PreferenceFragment.html
- http://developer.android.com/guide/topics/ui/settings.html
- http://stackoverflow.com/questions/5197228/how-to-set-the-default-value-of-a-listpreference
- http://stachibana.biz/?p=610
【Rasberry Pi】カメラモジュールでmmal: No data received from sensorエラー
Rasberry Pi B+とカメラモジュールを買ってみたので使ってみたところエラーで買い直しになった・・・
$ raspistill -o test.jpg mmal: No data received from sensor. Check all connections, including the Sunny one on the camera board
調査
設定は以下コマンドで行った。
# 最新カーネルにアップデート $ sudo apt-get update $ sudo apt-get upgrade # 8 Advanced Options -> A5 Enable Camera -> Enable $ sudo raspi-config
再起動後、vcgencmdコマンドで接続チェックをしたところ、カメラの接続はできている模様・・・raspistillコマンドを打った際にもカメラのランプ自体は付いている。
$ vcgencmd get_camera supported=1 detected=1
そもそも同じエラーでぐぐってみても87件しかそもそも検索結果がない。
"mmal no data received from sensor" - Google 検索
ソフトウェア側の問題でなんとか解決できないかと思って下記URLなどを参照したが改善される様子はなし・・・
そもそも解決している人が見つからなかった。
https://www.raspberrypi.org/forums/viewtopic.php?f=43&t=105100
Raspberry Piにカメラを接続する | テクニカルタイムアウト
最後に
秋月電子で買ったので、14日以内にちゃんと試しておけば交換してもらえたのかな・・・まあ勉強代と思って今回は諦めました。
【Java】メインスレッドから別スレッドの停止
自分用メモ。
メインスレッドからの停止
- Thread#interrupt()で行う。Thread#stop()メソッドは安全性を壊す可能性があり、非推奨
- Thread#interrupt()自体はインタラプト状態を変更するだけ。
- ただし、スレッドがThread#sleep(), Thread#wait(), Thread#join()を実行して止まっている間にThread#interrupt()を実行するとInterruptedExceptionを投げる。
- これはThread#sleep(), Thread#wait(), Thread#join()側がメソッドの中でスレッドのインタラプト状態を見て、明示的にInterruptedExceptionを投げているため
- Thread#sleep(), Thread#join()を読んだスレッドに対しては、Thread#interrupt()を実行する際にスレッドのロックを取る必要はなく、いつでも呼ぶことができる
- Thread#wait()を呼んだスレッドに対してThread#interrupt()を呼ぶとロックを再び取り直してからInterruptedExceptionを投げる
- Thread#isInterrupted()でインタラプト状態を取得できる
スレッド自身を止めるメソッド
メソッド | 説明 |
---|---|
sleep() | 指定された時間だけ実行を停止 |
wait() | スレッドがウェイトセットに入ってnotify/notifyAllされるのを待つ |
join() | 指定したスレッドが終了するのを待つ |
コード
public class Sample { private Thread thread = null; public void startThread() { thread = new Thread() { @Override public void run() { while(!isInterrupted()) { // 処理 } } }; thread.start(); } public void stopThread() { if (thread == null) { return; } thread.interrupt(); } }
Intel Stick PCを買いました
インテルから発売されたIntel Stick PCを買いました。
Intel Stick PCとは
- インテルから発売されたスティック型のPC
- テレビのHDMIポートに刺して使う
- サイズは37(W)×103(D)×12(H)mmで非常に小さい
- Windows8.1搭載
- 値段はアイ・オー・データのページで税込み22140円
- 冷却ファンを搭載し、安定な動作を実現
スペック
アイ・オー・データのページより抜粋
項目 | 仕様 |
---|---|
OS | Windows 8.1 with Bing 32ビット |
CPU | インテル® Atom™ プロセッサー Z3735F(4コア、1.33GHz) |
メモリ | DDR3L(1.35V、1333 MHz、2GB) |
ストレージ | 32GB eMMC |
解像度 | 1920×1080 |
通信機能 | IEEE802.11b/g/n、Bluetooth4.0 |
インターフェイス | HDMI映像出力×1、USB 2.0ポート×1、microSDXCカードスロット×1 |
ネットワーク | IEEE 802.11 b/g/n、Bluetooth® V4.0 |
外形寸法(本体のみ) | 37(W)×103(D)×12(H)mm ※突起部除く |
質量(本体のみ) | 約54g |
中身
電源アダプターの変換プラグが何種類かついているので海外旅行にも持っていけそう。。。
接続
まず電源アダプターに日本用のプラグをつける。
電源アダプターと本体をUSBケーブルで繋ぐ
テレビのHDMIポートに接続する。
電源アダプターをコンセントに入れると自動で電源がつく
初期設定の注意点として有線マウス・キーボードがないと初期設定ができない。
私は後で気付いて買いに行きました・・・
使用感
4KのYoutubeを再生してみたところ、4K(2160p)、HD(1440p)は再生が厳しかったが、それ以下なら再生できた。
GoPro: Tomorrowland in 4K - YouTube
USB端子が1つしかないのでUSBハブが必須。
キーボードとマウスならだけ電源アダプター付きのUSBハブでなくてもいけたが、これ以上何かつけようと思ったら電源アダプター付きのUSBハブにする必要がある。
旅行に持っていきやすいとは思うが、キーボードとマウスを持っていく必要があるので、それならノートPCでいいような気がする・・・
テレビの裏につけるだけでWindows PCが使えるので、ノートPCを買うまでもない人なら2万程度でPCが増えるのでいいと思う。
Minecraft買って動かせるか試してみたいところ。
モバイルバッテリーでも起動できるかもしれないのでこちらも試してみたい。
DockerでAndroidの環境を構築する
Androidでテストを同時並行に実行したいなーと思っていたので作ってみた。
Javaのインストール
こちらからコードを拝借。ただ、add-aptがデフォルトではUbuntuに入っていないのでatp-getでインストールする
# For add-apt-repositor in order to install Java RUN apt-get install -y software-properties-common # Install Java RUN \ echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && \ add-apt-repository -y ppa:webupd8team/java && \ apt-get update && \ apt-get install -y oracle-java8-installer && \ rm -rf /var/lib/apt/lists/* && \ rm -rf /var/cache/oracle-jdk8-installer # Define commonly used JAVA_HOME variable ENV JAVA_HOME /usr/lib/jvm/java-8-oracle
Android SDKのインストール
Android SDKはGoogleのページにあるので、ダウンロードしてくればよい。問題はtoolsなどのインストールで、インストールの最中度々承認を求められる。今回はexpcetコマンドを使って、特定の文が来たらそれに対してキーを送るようにしてスキップしている。
あとうまくいかなかった点としては、32bit互換性のためにライブラリをインストールすることと、toolsのアップデート中にtmpフォルダへのコピーが失敗してインストールが失敗するということがあった。
前者はapt-getでlib32stdc++6をインストールする。 後者は、toolsを一旦別フォルダに退避し、退避したtoolsのandroidコマンドを使ってtoolsのアップデートを行う。
ADD expect-android-update.sh . RUN chmod +x expect-android-update.sh RUN apt-get install -y wget RUN apt-get update RUN apt-get -y install expect RUN apt-get -y install lib32stdc++6 RUN wget http://dl.google.com/android/android-sdk_r24.2-linux.tgz && \ mv android-sdk_r24.2-linux.tgz /opt && \ cd /opt && \ tar zxvf android-sdk_r24.2-linux.tgz && \ rm android-sdk_r24.2-linux.tgz && \ cd android-sdk-linux && \ cp -a tools copy-tools && \ /expect-android-update.sh platform-tools && \ ./platform-tools/adb kill-server && \ rm -rf temp/ && \ /expect-android-update.sh tools && \ /expect-android-update.sh build-tools-22.0.1,android-18,android-19,android-21,android-22,sys-img-armeabi-v7a-android-22,sys-img-armeabi-v7a-android-21,sys-img-armeabi-v7a-android-19,sys-img-armeabi-v7a-android-18 ENV ANDROID_SDK_HOME /opt/android-sdk-linux ENV ANDROID_HOME /opt/android-sdk-linux ENV PATH $PATH:/opt/android-sdk-linux/platform-tools:/opt/android-sdk-linux/tools
adbで端末のモデル名を取得する
adb shell cat /system/build.prop | grep ro\.product\.model | awk -F"=" 'NR==1 {print $2}' | tr -d ' ' | awk -v RS='\r\n' '{print $1}'
詳細はこちらから
ほとんどの機種は上記記事のコマンドで問題ないのだが、Nexus5のような端末だとro.product.modelが「Nexus 5」のようにスペースが入っている。
そのため、tr -d ' ' を追加した。
Alfredからビルドする
最近、なるべくマウスから手を離したくないなーと思ってなんでもかんでもターミナルでコマンドなりシェルスクリプトでやろうとしている。
ビルドに関してもオプションを受け取れるようにして、シェルスクリプトで切り替えているのだけども、実行するには一回ターミナルを開いて実行して終わったら元の画面に戻って・・・ということになるので、なるべく開きたくない。
これをAlfredでなんとかならないかなと試行錯誤してできるようになったのでメモ。
環境
Alfredとは
AlfredはMac用のランチャーアプリ。バックグラウンドで常駐し、option+spaceでいつでもどこからでも起動できる。
AlfredのUI自体はただの入力欄で、起動するとフォアグラウンドに出てきて、アプリの頭文字を入力することで素早くアプリを起動できる。
Alfredのいいところはいつでもどこからでも起動できるというところで、どんな作業をしていようとアプリを起動できる。
またアプリ起動だけでなく、Google検索やファイル検索といった検索機能もカスタマイズして利用できる。
今回はビルドを行うアプリケーションを作成して、それをAlfredから起動することで、いつでもどこからでもビルドができるようにした。
そのビルドを行うアプリケーションを簡単に作れるのがMacに標準で入っているAutomatorである。
Automatorの設定
Automatorでは開始の通知の表示とビルドスクリプトの実行、 そして終了の通知の表示を行うだけである。
まず、Automatorを開き通知を右の欄にドラッグする。
タイトル等は適当に。
次にシェルスクリプトの実行をドラッグする。 ここでの注意点として、Automatorからシェルスクリプトを実行する際、bash_profileが読み込まれないので、明示的に読み込む必要がある。
最後にもう一度通知を追加して保存する。
保存先は、Alfredの検索対象(/Applicationsなど)となっているフォルダにする。
Alfredから起動できるようになる。
通知は右上に出る。
通知がすぐ消えるのを変えたい場合は、設定から通知を通知パネルに変更すれば、自分で消すまでは残り続ける
おわりに
Alfredからビルドできるようになったけど、ビルド対象やビルドオプションが増えるたびにAutomatorで設定する必要があるのどうにかならないかな。。。