Android UI/UX アンチパターン
参考資料
画面全般
スプラッシュ画面
必要のないスプラッシュ画面の表示はやめましょう。
なぜダメか
多くのアプリにおいて、スプラッシュ画面では何も処理していません。 このようなアプリでは、ユーザがアプリを起動してからスプラッシュ画面の表示が終わるまでの間、ユーザの時間を単純に浪費してしまいます。 わずかな時間かもしれませんが、Androidではアプリの起動/終了が頻繁に繰り返される場合があるため、デスクトップアプリと比べて表示される頻度が多くなることを意識する必要があります。
解決法
スプラッシュ画面を削除する。 余談ですが、iOSのLaunchImagesは体感上の起動時間を短縮するためにアプリ起動後の画面と似たものを使用することが推奨されています。 Androidアプリにおいて、体感上の起動時間を短縮するためにできることはスプラッシュ画面を削除することです。
iOS Human Interface Guidelines: Launch Images
例外
起動時に重い処理をする必要があるアプリ、特にゲームアプリなどはスプラッシュ画面を設けるべきです。 このようなアプリでは起動から実際に動作が可能になるまでタイムラグが生じるため、可能な限り迅速に何らかの画面を表示する必要があります。
Keeping Your App Responsive | Android Developers
時代遅れのUI
以下の要素はUIを時代遅れと感じさせます。
- ナビゲーションバーのメニューボタン
- Gingerbread時代のtheme/style
- ActionBarを使用していない
なぜダメか
ナビゲーションバーのメニューボタンは古い端末におけるメニューボタンを模したもので、「Menu Button of Shame」とも呼ばれています。 Menu Button of Shameの機能は最近のUIではActionBarのMenuItem、またはオーバーフローメニューに集約されています。
Gingerbread時代のtheme/styleはアプリ全体を古臭くみせてしまいます。 アプリ全体がHoloベースになっていても一部部品が古いままだったりと見栄えが悪いので、細部にも気を配りましょう。
ActionBarを使用せず、TitleBarが表示されてしまうのもアプリを古臭く見せる要因です。 Support Libraryにv7-appcompatが追加されてから1年以上経過しており、ActionBarはすでに一般的な実装になっています。
解決法
- targetSdkVersionを最新にする
- ThemeをHoloやAppCompatにする
- ActionBarを導入する
他のプラットフォームの模倣
以下のような実装は他プラットフォームの模倣です。
- 下タブバー
- リスト項目の右向き矢印
- 非標準ナビゲーション(独自のActionBar、メニューボタン)
Pure Android | Android Developers
なぜダメか
他のプラットフォームを模倣したデザインはAndroidプラットフォームデザインの一貫性を損ないます。
iOSにおいて下タブバーが標準的なUIであるように、Androidでは画面上部のタブバーやNavigationDrawer
が一般的です。
リスト項目の右向き矢印に関しては、Androidでは不要です。 直感的だと言われていますが、画面遷移アニメーションが矢印にあわせて実装されていることはほとんどありません。
非標準ナビゲーションはプラットフォームの一貫性を損なうだけでなく、多くの場合拡張性も犠牲になっています。
解決法
まず、Androidプラットフォームの標準的な実装を心がけるべきです。 下タブバーはActionBarのタブ機能を使うか、NavigationDrawerを利用してください。 FragmentTabHostやPagerTitleStripも利用できます。
リスト項目の右向き矢印は削除してください。
非標準ナビゲーションはActionBarに置き換えてください。 ActionBarはある程度カスタムUIを含めることができ、多機能で、拡張性に優れます。
縦向き固定・電話限定
アプリ画面の縦向き固定・スマートフォンのみ対応は賢明ではありません。
なぜダメか
縦向き固定のアプリは純粋に使い勝手が悪いです。 スマートフォンでしか使えないアプリはタブレットユーザに対する機会損失です。 Androidタブレットの普及率は高く、無視するには惜しいレベルです。
タブレットの国内出荷台数は713万台、iOSとAndroidのシェアは1%の僅差 - ケータイ Watch
解決法
Androidではさまざまな解像度に対応するための仕組みが用意されています。 dpで設計し、拡縮範囲、スクロール範囲を意識していれば横画面でも崩れないレイアウトを作るのは難しくありません。 タブレット対応は難しく感じますが、最初から完全なマルチペインが必須なわけでもありません。 表示崩れを防ぎ、タブレットでも十分に操作できるというレベルにするのは他画面対応できていれば思ったよりも簡単です。
Supporting Multiple Screens | Android Developers
Designing for Multiple Screens | Android Developers
ダイアログ
確認ダイアログの多用
あるアクションに対しそれを続行するかどうかを選択させるダイアログのことを確認ダイアログといいます。 確認ダイアログを多用しないでください。
なぜダメか
Androidにおいて、確認ダイアログを利用すべきシチュエーションは2パターンのみです。
- ユーザがその処理を実行する前に結果を警告する必要がある場合(決済やリセットなど)
- ユーザが誤って実行した場合に不利益となり、かつ技術的に元に戻せない場合(データ削除など)
これ以外のシチュエーションにおいて、ユーザに確認ダイアログを表示する処理は非推奨となります。
Confirming & Acknowledging | Android Developers
解決法
Confirming & Acknowledgingの内容に従って実装する必要があります。 その上で誤操作が頻繁に起きるような場合、UI上の混乱が原因となっている場合が多いので、UIの見直しを検討してください。 ActionBarのメニューにする、アイコンをわかりやすいものに変更するなど確認ダイアログに頼らない方法があるかもしれません。 事前に防ぐだけではなく、アクション後に取り消せるような動線を用意するのも良いと思います。
読み込み中ダイアログの多用
読み込み中ダイアログ(プログレスダイアログ)とは、非同期処理の実行中に表示するダイアログを指します。
なぜダメか
読み込み中ダイアログは、多くの場合、キャンセルが無効(setCancelable(false)
)にされています。
この場合では非同期処理であってもユーザが画面を操作できないため、ユーザ体験を損ないます。
キャンセル可能なダイアログであっても頻繁に表示されたり、時間のかかる処理が誤タッチで中断してしまうと悪印象になる恐れがあります。
また、実装上の問題として読み込み中ダイアログをDialogFragment
で実装する場合に処理が複雑になりがちです。
解決法
SwipeRefreshLayout
などを利用し、画面操作を必要以上に阻害しない形で読み込み中表示を行います。
SwipeRefreshLayout#setEnabled(false)
で、スワイプ更新機能を無効にしてプログレス表示機能のみを利用することができます。
ListFragment
は標準でsetAdapter
されるまで読み込み中表示を行う機能があるため、これを利用することも検討してください。
例外
仕様上、どうしてもキャンセルさせたくない処理というものも存在します。
IntentService
を利用する方法もありますが、画面と密に連動している場合などやはり読み込み中ダイアログを利用したほうが良い場面もあります。
読み込み中ダイアログをすべて無くそうとするよりも、必要な箇所だけに限定できないか検討してください。
ダイアログの独自アクションボタン
Androidでは通常、ダイアログ下部に「OK」「キャンセル」といったアクションボタンを表示します。 これらとは別に、カスタムレイアウトを利用してダイアログ内に独自のアクションボタンを配置することがあります。
なぜダメか
Androidのダイアログアクションボタンの配置はOSのバージョンによって異なります。 古い端末では左側が肯定ボタンでしたが、ICSからは右側が肯定ボタンになっています。 独自にこれらのボタンを実装する場合、バージョンごとにレイアウトファイルを用意しない限り、OS標準から外れることになります。
解決法
標準のダイアログアクションボタンを使用します。
AlertDialog.Builder#setPositiveButton
などを利用することで、OSバージョンによって適切な表示を行ってくれます。
例外
凝ったカスタムダイアログを表示したい場合など、OS標準のアクションボタンではダメな場合があります。 その場合でもなるべくシステム内の一貫したユーザ体験を損なわないように注意してください。
操作に関して
タッチ領域が小さすぎる
ボタンなど、タッチ可能なView要素の表示領域は一定以上必要です。
なぜダメか
うまくタッチできないView要素はユーザ体験を損ないます。 以前は縦横共に48dp以上必要となっていましたが、Material Designガイドラインでは一部違う例もあります。
Metrics and Grids | Android Developers
解決法
基本的には表示サイズを一定以上にする必要があります。
どうしても表示サイズを拡大できない場合、TouchDelegate
を利用してタッチ領域を広げる方法を検討してください。
Managing Touch Events in a ViewGroup | Android Developers
タッチ時のフィードバックがない
タッチ可能なView要素では、タッチフィードバック(タッチした際のView要素の状態変化)の実装が必要です。
なぜダメか
タッチパネルではマウスと違い明確なタッチポイントがわかりません。 ユーザにどのView要素がタッチされたかを通知するために、タッチフィードバックの実装が必須となります。 特に画面遷移を行うような場合では間違えてタッチしても画面遷移が終わるまでユーザにわからないため、悪印象となります。
解決法
Viewの状態(states)によって見た目が変わるように設定します。
Touch Feedback | Android Developers
AndroidTVやChromebookなど、将来的にタッチパネルでない端末も増えることが予想されるので、pressed
だけでなく、focused
も実装しましょう。
Material Designガイドラインではstates
による描画の切り替えだけではなくアニメーションによるフィードバックも行うようになります。
Responsive Interaction - Animation - Google design guidelines
ジェスチャの間違った利用
Viewの長押しで独自のアクションを実行する、リストアイテムをスワイプして削除ボタンを表示させるというような動作は推奨されません。
なぜダメか
Androidにおいて、ジェスチャの種類とそれぞれのジェスチャがどのような動作をすべきかは決められています。
Gestures | Android Developers これらのジェスチャを異なる意味に用いるとユーザが混乱する場合があります。
解決法
たとえばメニューアイテムの削除であれば、削除(Long Press)によってContextual Action
を呼び出し、複数選択して削除できるような実装にするのが自然です。
単独でアクションさせる場合はfloating context menu
によって操作を選ばせる方法もありますが、ジェスチャページではContextual Menu
のために長押し操作を利用するなと書いてあるため、なるべくContextual Action
による実装を検討してください。
例外
GmailのSwipe-to-Dismiss(スワイプすると削除)のように、標準ジェスチャと異なる実装であっても問題ない場合もあります。
その場合はViewPager
など既存のジェスチャと競合しないこと、他のアンチパターンに抵触しないことに気をつけてください。
例えばSwipe-to-Dismissの場合、削除時に確認ダイアログを出すとテンポが悪くなります。
共有機能の独自実装
SNSごとに共有ボタンを置くような実装は推奨されません。
なぜダメか
これらは多くの場合、仕様を決める際の考慮漏れです。 本当に必要なのはTwitter,Facebookなど特定のSNSへの投稿ではなく、Twitter/Facebookを含むSNSなどへの拡散ではないでしょうか。 そうであった場合、MixiやG+など他のSNSへ拡散される機会を損失しています。 このような仕様は避けるべきです。
Pure Android | Android Developers
解決法
単純に他アプリへ共有したい場合、暗黙的Intentを発行すれば良くなります。 ユーザの利便性を考慮し、ShareActionProviderを利用することもできます。 どうしても明示的にTwitter/Facebookに投稿させたい場合、アプリがSDKを使用して直接投稿すべきです。
Adding an Easy Share Action | Android Developers
何らかの理由で特定アプリのみ挙動を変えたい場合、Intent.createChooser
で対応できる場合があります。
Y.A.M の 雑記帳: Facebookとそれ以外でACTION_SENDで渡すテキストを変える
例外
最終的には連携先のアプリによってしまうので、どうしても解決できない場合もあります。
Androidソースコードレビューで指摘する事が多い項目まとめ
業務でソースコードレビューを行う機会が増えたので、複数回指摘した項目や気になった実装などをまとめてみました。 こういう観点をできる人と共有できるといいなあ…。
2014/09/29 23:00 一部修正しました。
業務上ソースコードレビューの名目で仕様・デザインまで見ることになっていたためこれらを先頭に書いていましたが、わかりづらかったため最後にまとめました。
Fragment関連
FragmentとActivityの密結合
Fragment
が特定のActivity
から呼ばれることを想定して書かれている場合、そのFragment
とActivity
は密結合である場合が多いです。
具体的には、以下の様な実装です。
Activity
のViewを参照するActivity
のメソッドを直接呼び出す
なぜダメか
Fragment
の利点のひとつは優れた再利用性にあります。
Fragment
が特定のActivity
に依存することで、Fragment
の再利用を妨げます。
現時点でアプリ内で再利用しないという場合でも、将来においてメンテナンスが困難になる可能性があります。
解決法
Activity
のViewを参照している場合、そのViewをFragment
に配置できないか検討してください。
ActionBar
のタイトルやMenuItem
はFragment
でも操作できます。
Fragment
内の特定のタイミングでActivity
のViewを操作したい場合、後述するコールバックでの処理を検討してください。
どうしてもActivity
と密結合になってしまう場合、Fragment
ではなくCustomView
として実装したほうが良い場合もあります。
Activity
のメソッドを直接読んでいる場合、コールバックインターフェイスによる実装を検討してください。
if(getActivity() instanceof MyFragmentCallback){ ((MyFragmentCallback)getActivity()).callback(); }
Fragmentからの不自然な画面遷移
Fragment
から新しいActivity
へ遷移する際、getActivity().startActivity()
するような実装は危険です。
特に、getActivity().startActivityForResult()
を使用するのは避けてください。
なぜダメか
上記のような実装を行うとActivity
からFragment
にonActivityResult()
を伝達する必要があり、密結合となる場合が多くなります。
Fragment
の再利用性が下がるだけでなく、Activity#onActivityResult()
のメンテナンスも困難になります。
解決法
Fragment#startActivity()
、Fragment#startActivityForResult()
、Fragment#onActivityResult()
を利用してください。
これらが利用できない(Activityを経由する必要がある)場合、そもそも密結合である可能性高いので、コールバックインターフェイスなどを利用して疎結合にできないか検討してください。
DB関連
Columnsの定義方法が間違っている
Columns
クラスはBaseColumns
を継承し、BaseColumns._id
を主キーフィールドとして使用します。
この値を文字列として再定義しないでください。
なぜダメか
Androidの一部機能(CursorAdapter
など)は主キーフィールド名がBaseColumns._id
と同一であることを期待しています。
おそらく将来にわたって変わることはありませんが、わざわざアプリ内で再定義して管理する必要もありません。
解決法
Columns
クラスはBaseColumns
を継承し、BaseColumns._id
を主キーフィールドとして使用します。
http://developer.android.com/training/basics/data-storage/databases.html
WebView関連
WebViewのライフサイクルを考慮していない
WebView
の一部機能はActivity
やFragment
のライフサイクルと同期させる必要があります。
なぜダメか
ライフサイクルメソッドの呼び出しを怠るとFlashやHtml5コンテンツが休止されないため、音が鳴り止まない、バッテリーを浪費するなどの問題があります。
解決法
WebView
のライフサイクルメソッドを必要に応じて呼び出してください。
API level 11以降であればWebViewFragment
が利用できます。
@Override public void onPause(){ super.onPause(); webview.onPause(); } @Override public void onResume(){ super.onResume(); webview.onResume(); } @Override public void onDestroy(){ super.onDestroy(); webview.destroy(); }
http://developer.android.com/reference/android/webkit/WebView.html
その他
ソースコードによるレイアウトの共通化
あまり多くありませんが、<include />
を使わず、BaseActivity
内でヘッダやフッタの追加を行っている場合があります。
なぜダメか
この処理の問題はメンテナンスコストが上がることです。
あとからヘッダやフッタを編集する際、本当にBaseActivity
だけ編集すれば良いのかどうか判断できません。
ヘッダやフッタが必要でない画面や特殊なヘッダを用いる画面では特殊な処理をオーバーライドしている可能性があるためです。
Androidにはレイアウト(の一部)を流用するための仕組みがあるので、ソースコードで共通化の処理を行う必要はありません。
解決法
レイアウトxml内で<include />
を使用してください。
あるいは、Activity
同士の継承ではなくFragment
による画面の一部遷移という形式にできる可能性もあります。
引数における型指定
メソッド引数の型指定をより良くできる場合があります。
ArrayList<?>
で指定している部分をList<?>
にしたり、String
をCharSequence
にできないか検討して下さい。
なぜダメか
別にそのままでもダメではないのですが、必要最小限の実装を持つスーパークラスやインターフェイスを指定することで将来の拡張に耐えられる場合があります。
特に文字列を引数で受け取り、その引数に対して編集などを行わない場合はCharSequence
にしておくことでTextView#getText()
などを直接扱えるようになります。
解決法
より上位のクラスやインターフェイスで対応できないか検討して下さい。
自作のクラスを引数とする場合、インターフェイス化できないか検討してください。
(冗長になってしまう場合もあるので、Utils
クラスのみを対象とする、という形でも良いと思います)
仕様面
厳密にはソースコードレビューとは異なりますが、気にかけておくべき事柄。
画面構成がiOS風
指摘してもどうしようもない場合が多いですが、一応…。
なぜダメか
AndroidにはAndroidに適したUIがあるので、なるべく沿うようにしましょう。 http://developer.android.com/design/patterns/pure-android.html
解決法
代替案を提案してみる他ないです。
- 下タブ
- NavigationDrawer
- ActionBarタブ
- 独自ヘッダー
- ActionBar
- 画面遷移要素の「>」マーク
- 削除
特定のアプリへの依存
TwitterやFacebookなどのSNSアプリに対してパッケージを指定した明示的なインテントを発行したり、インストールされていない場合にPlayストアに遷移するような構成は好ましくありません。
なぜダメか
これらは多くの場合、仕様を決める際の考慮漏れです。 本当に必要なのはTwitter,Facebookへの投稿ではなく、Twitter/Facebookを含むSNSなどへの拡散ではないでしょうか。 そうであった場合、MixiやG+など他のSNSへ拡散される機会を損失しています。 また、明示的にTwitterやFacebookに投稿する場合であっても、公式アプリ以外のクライアントアプリの存在を考慮する必要があります。 特にTwitterは非公式のクライアントが多く、そのユーザも少なくありません。 公式アプリの有無で挙動を変えることは、それらのアプリユーザから見れば不自然な挙動となります。 さらに、非公式アプリを無視できるとしても、公式アプリが挙動を変更した場合に正しく動作しなくなる可能性があります。 このような仕様は避けるべきです。 http://developer.android.com/design/patterns/pure-android.html
解決法
単純にSNSへ拡散したい場合、暗黙的Intent
を発行すれば良くなります。
ユーザの利便性を考慮し、ShareActionProvider
を利用することもできます。
http://developer.android.com/training/sharing/shareaction.html
どうしても明示的にTwitter/Facebookに投稿させたい場合、アプリがSDKを使用して直接投稿すべきです。
ListViewのpadding設定
ListViewにpaddingを設定する
ListViewで子要素の配置を調整する場合、通常はandroid:padding
で描画領域を、android:dividerHeight
で子要素同士の間隔を設定する。
この時、単純にandroid:padding
だけ指定すると以下のようにリストの上下端で子要素が途切れてしまう。
これを防ぐためには、android:clipToPadding
属性でpadding領域であっても子要素を描画するように設定する。
<ListView android:id="@android:id/list" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/darker_gray" android:clipToPadding="false" android:divider="@null" android:dividerHeight="16dp" android:padding="16dp" />
styleで定義する
いちいちListView
に全部の設定を書くのは面倒なので、上記設定をstyle
でやろうとするとこうなる。
<style name="ListView"> <item name="android:padding">16dp</item> <item name="android:clipToPadding">false</item> <item name="android:divider">@null</item> <item name="android:dividerHeight">16dp</item> <item name="android:background">@android:color/darker_gray</item> </style>
<ListView android:id="@android:id/list" style="@style/ListView" android:layout_width="wrap_content" android:layout_height="wrap_content" />
themeで定義する
いちいちListView
にstyleを書くのは面倒なので、上記設定をthemeでやろうとするとこうなる。
<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar"> <item name="android:listViewStyle">@style/ListView</item> </style>
<application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > ...
…のだが、なぜかうまくいかない。
どうやらthemeではandroid:clipToPadding
の設定が反映されないらしい。
仕方がないのでソースコード側でListView#setClipToPadding(false)
を呼び出すと動く。
ListFragment
で標準レイアウトを使う場合、themeで基本レイアウトを指定した後android:clipToPadding
だけソースコードで上書きするしかなさそうだ。
getListView().setClipToPadding(false);
これでうまく表示できた
3行未満のAndroid Tips集
記事にするまでもない3行未満で書けるレベルのTipsとリンク集。 常識レベルのものも含む。
URLのパスの結合にはUri.withAppendedPathを使う
スラッシュの重複を省いてくれて便利。 http://developer.android.com/reference/android/net/Uri.html
DBのColumnsはandroid.provider.BaseColumnsを継承する
中に_ID
ってフィールドがあるからそれ使う。
http://developer.android.com/reference/android/provider/BaseColumns.html
StringBufferとStringBuilder
StringBuilder
のほうが圧倒的に軽い。
でもスレッドセーフじゃないから複数のスレッドからは呼べない。
Integer.toHexString
数値を16進文字列にする場合、Formatterより速い。
0xf
以下の値を渡すと1桁しか出力しないので注意。
Deep Linkの提供
App-indexing以外にもGoogle+とGoogleAdsから提供できる http://developer.android.com/distribute/engage/deep-linking.html
Playストアへのリンクの貼り方
details?id=以外もある。 http://developer.android.com/distribute/tools/promote/linking.html
Playストアへのリンクボタン生成ページ
ランディングページとかに貼るやつ。 http://developer.android.com/distribute/tools/promote/badges.html
スクリーンショットに端末画像の枠つける
Nexus端末じゃないとダメ。 http://developer.android.com/distribute/tools/promote/device-art.html
便利な新機能の探し方
Android Developersを「Compat」で検索する→左側のメニューで「Reference」を選択する。 元のクラスとの差分が含まれたXXXCompat系がいっぱい表示されるので片っ端から見る。 Compatに含まれるくらいなんだから便利な新機能にきまっている。 http://developer.android.com/reference/android/support/v13/app/FragmentCompat.html#q=Compat
よく使うシステムブロードキャストの一覧
AndroidDevelopersのIntent#Standard Broadcast Actionsに書いてある http://developer.android.com/reference/android/content/Intent.html
買ってよかったAndroid関連電子書籍まとめ
Androidの技術書、どうせ買うなら電子書籍がいいよね!と電子書籍をあちこちで買ったり買い直したりしてるので知見を共有します。
どこで買うべきか
電子書籍で技術書を購入する際、なるべく制限の少ないものを探すことが重要です。 何も考えずに買ってしまうと、以下の様な制限に引っかかってしまいます。
技術書に限っては閲覧制限のかかっていないPDFを入手できることが最善だと思います。
達人出版会
閲覧制限のないPDFを入手することができます。 ここで購入できる書籍はなるべくここで購入しています。 領収書が発行されないので、必要な人は注意してください。 http://tatsu-zine.com/
技術評論社
閲覧制限のないPDFを入手することができます。 Android本もそこそこあって良いです。 AdobeReaderでコピーすると文字化けするPDFがあるので注意。 https://gihyo.jp/dp
O'Reilly Japan Ebook Store
閲覧制限のないPDFを入手することができます。 ただし、Android本があまりありません…。 1年以内に発売されたAndroid本が「実践 Android Developer Tools」しかない…。 http://www.oreilly.co.jp/ebook/
Impress Japan
あまり使ったことがないですが、書籍によって提供されるフォーマットがまちまちです。 PDFもコピペ制限があったりなかったりで、大抵の場合買うまでわかりません。 http://www.impressjapan.jp/
Google Play ブックス
PCでもブラウザで読めますが、文字列コピーと印刷ができません。 ソースコードを検索した際の精度もいまいち良くない気がします。 https://play.google.com/store/books
Amazon Kindle
Kindle(jp)はPCで読めないという致命的な欠点があるので、技術書の購入には向きません。 http://www.amazon.co.jp/
買ってよかった電子書籍
Smashing Android UI レスポンシブUIとデザインパターン
Androidのデザインについて深く考察した上で書かれた良著。 特に「第21章 UIデザインのアンチパターン」は「なぜ」Androidではそのデザインがだめなのか?ということを解決策付きで解説しており、Androidデザインの基本を理解するのに最適です。 サンプルアプリの一部挙動が若干分かり難いのが難点。 達人出版会で閲覧制限のないPDFが買えます。 http://tatsu-zine.com/books/smashing-android-ui
良いAndroidアプリを作る139の鉄則
タイトルの通り、良いAndroidアプリを作るためのノウハウがまとめられた本。 内容もデザインからテスト、リリースと多岐にわたっているので自分が苦手な部分への取っ掛かりをつかむには最適です。 また、コラムの内容も充実していて非常に参考になりました。 コンテンツ数が多い文、個々の内容が若干物足りない感じもしますが、そこは自分で調べればいいかな…。 技術評論社のPDFはAdobeReaderでコピーすると文字化けしますが、Chromeでコピーするとなぜか文字化けしません。 技術評論社で閲覧制限のないPDFが買えます。 https://gihyo.jp/dp/ebook/2014/978-4-7741-6607-0
Effective Android
デザインからNDKまで幅広く取り扱っているので、知識の幅を広げるのに非常に良い本。 Androidマスターしたわ!と思ったらこの本でボッコボコにされるといいと思います。 あまり細かい解説がなかったりするので、初級者向けではないです。 達人出版会で閲覧制限のないPDFが買えます。 http://tatsu-zine.com/books/effective-android
Master of Fragment (Android Professional Developerシリーズ)
Fragmentなんとなく使えるけどこれでいいんだっけ…くらいのときに読むと良い本。 よくある疑問点がまとめられていて非常に助かりました。 達人出版会で閲覧制限のないPDFが買えます。 http://tatsu-zine.com/books/master-of-fragments
Android Pattern Cookbook マーケットで埋もれないための差別化戦略
Kiatkat準拠のデザイン本。 解説が細かく、サンプルソースも読みやすいです。 Impress Japan版はコピペ制限がかかっていたので、達人出版会で買い直しました。 達人出版会で閲覧制限のないPDFが買えます。 http://tatsu-zine.com/books/android-pattern-cookbook
Android Security 安全なアプリケーションを作成するために
Androidアプリのセキュリティについて書かれた稀有な本。 2年以上前の本なので、後述の「Android アプリのセキュア設計・セキュアコーディングガイド」と読み合わせると良い感じ。 達人出版会で閲覧制限のないPDFが買えます。 http://tatsu-zine.com/books/androidsec
Androidアプリのセキュア設計・セキュアコーディングガイド
Androidアプリのセキュリティについて書かれた資料。しかも無料。 AccountManagerとSyncAdapterを学習する上で滅茶苦茶お世話なりました。しかも無料。 ソースコード内にわかりやすくポイントが書いてあり、読みやすいです。しかも無料。 無料でPDFが公開されています http://www.jssec.org/report/securecoding.html
まとめ
達人出版会の宣伝みたいになっていますが、汎用性を考えるとPDF最強になってしまうので仕方ないですね。 技術評論社もかなり充実してきたので今後が楽しみです! O'Reillyはもっと電子書籍化がんばってほしい…。
設定画面のインテントアクションまとめ
はじめに
Androidでは、アプリが必要な権限を持っていれば、アプリから端末の設定(一部)を変更することができます。 この仕組はアプリが必要とする機能を確実に使用するためには有用ですが、インストール時に設定変更権限が必要な旨がダイアログ表示されてしまい、ユーザから敬遠される恐れもあります。 また、端末設定の変更ロジックに問題があった場合、影響範囲がアプリだけに収まらなくなります。
Androidでは上記のようなアプリから直接設定を変更する方法の他に、設定アプリの各画面へ簡単にアクセスする方法も提供されています。
android.provider.Settings
クラスにはAndroidの各機能設定画面を呼び出すIntent
のAction
が定義されており、遷移先の設定画面でユーザ自身に必要な設定を行わせることができます。
この場合には自アプリには権限が必要ないため、インストール時の敬遠リスクは下がり、設定変更ロジックも書かなくて良いため実装コストは軽くなります。
この記事では、android.provider.Settings
クラスのアクション一覧を簡単な解説つきで列挙します。
キャプチャはAPI level 19未満で表示できるものはGalaxy Nexus@Android 4.3、API level 19以降が必要なものについてはNexus5@Android L Developer Previewを使用しています。
参考URL: http://developer.android.com/reference/android/provider/Settings.html
注意点
生成したIntent
で呼び出される画面は端末の種類(メーカー)、OSのバージョンなどによって変わります。
同じ画面構成であっても見た目が同じとは限らないので、ヘルプなどを書く際には注意が必要です。
また、基本的にAction
を指定した暗黙的インテントになるため、環境によっては複数のActivity
の<intent-filter>
に引っかかる場合があります。
逆に、<uses-feature>
の設定などによっては対象Activity
が見つからないことも考えられます。
どの設定画面への遷移を利用する場合でも、Intent
の対象となるアクティビティが存在するかどうかを確認後、遷移するようにしてください。
ACTION_ACCESSIBILITY_SETTINGS
API level 5から追加。 ユーザ補助設定画面のアクション。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_ACCESSIBILITY_SETTINGS);
startActivity(intent);
ACTION_ADD_ACCOUNT
API level 8から追加。
アカウントの追加画面(アカウントの種別選択画面)のアクション。
Settings.EXTRA_ACCOUNT_TYPES
にaccount_type
を指定(String[]
形式)することで追加対象のアカウントをフィルタリング可能。
Settings.EXTRA_AUTHORITIES
にsyncable="true"
なContentProvider
のauthorities
を指定(String[]
形式)することで追加対象のアカウントをフィルタリング可能。
フィルタリングの結果、追加対象のアカウントが特定された場合は選択画面を経由せず、直接対象アカウントの追加画面を表示する。
Intent intent = new Intent(); intent.setAction(Settings.ACTION_ADD_ACCOUNT); // 対象をGoogleアカウントに限定 intent.putExtra(Settings.EXTRA_ACCOUNT_TYPES,new String[]{"com.google"}); startActivity(intent);
ACTION_AIRPLANE_MODE_SETTINGS
API level 3から追加。 機内モードの設定が可能な画面のアクション。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_AIRPLANE_MODE_SETTINGS);
startActivity(intent);
ACTION_APN_SETTINGS
API level 1から追加。 APNの設定画面のアクション。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APN_SETTINGS);
startActivity(intent);
ACTION_APPLICATION_DETAILS_SETTINGS
API level9から追加。
指定したアプリケーションの詳細設定画面のアクション。
アプリケーションの指定はパッケージURI形式(package:com.my.app
)でsetData()
する。
Intent intent = new Intent(); intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); intent.setData(Uri.parse("package:com.android.settings")); startActivity(intent);
ACTION_APPLICATION_DEVELOPMENT_SETTINGS
API level 3から追加。 開発者向けオプション画面のアクション。 開発者向けオプションを有効にしていない場合にどうなるかは不明。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
startActivity(intent);
ACTION_APPLICATION_SETTINGS
API level 1から追加。 アプリケーションに関する設定画面のアクション。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_SETTINGS);
startActivity(intent);
ACTION_BLUETOOTH_SETTINGS
API level 1から追加。 Bluetooth設定画面のアクション。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_BLUETOOTH_SETTINGS);
startActivity(intent);
ACTION_CAPTIONING_SETTINGS
API level 19から追加。 Kitkatから追加されたユーザ補助設定のうち、ビデオキャプション設定画面のアクション。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_CAPTIONING_SETTINGS);
startActivity(intent);
ACTION_DATA_ROAMING_SETTINGS
API level 3から追加。 データローミング設定画面のアクション。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_DATA_ROAMING_SETTINGS);
startActivity(intent);
ACTION_DATE_SETTINGS
API level 1から追加。 日付と時刻設定画面のアクション
Intent intent = new Intent();
intent.setAction(Settings.ACTION_DATE_SETTINGS);
startActivity(intent);
ACTION_DEVICE_INFO_SETTINGS
API level 8から追加。 端末の状態画面のアクション。 Android L Developer Previewではなぜかクラッシュする。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_DEVICE_INFO_SETTINGS);
startActivity(intent);
ACTION_DISPLAY_SETTINGS
API level 1から追加。 ディスプレイ設定画面のアクション。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_DISPLAY_SETTINGS);
startActivity(intent);
ACTION_DREAM_SETTINGS
API level 18から追加。 JELLY_BEAN_MR1で追加されたDaydream(スクリーンセーバー)設定画面のアクション。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_DREAM_SETTINGS);
startActivity(intent);
ACTION_INPUT_METHOD_SETTINGS
API level 3から追加。 言語と入力設定画面のアクション。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_INPUT_METHOD_SETTINGS);
startActivity(intent);
ACTION_INPUT_METHOD_SUBTYPE_SETTINGS
API level 11から追加。
インプットメソッド(文字入力アプリ)のサブタイプ設定画面のアクション。
Settings.EXTRA_INPUT_METHOD_ID
にInputMethodInfo#getId()
で取得したidを指定することでサブタイプを指定できるらしいが未検証。
Nexus5では、Settings.EXTRA_INPUT_METHOD_ID
に何も設定しないとgoogleキーボードの入力言語設定が表示される。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
startActivity(intent);
ACTION_INTERNAL_STORAGE_SETTINGS
API level 3から追加。 内部ストレージ設定画面のアクション。 このアクションは端末ごとの差異が激しいかもしれない。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_INTERNAL_STORAGE_SETTINGS);
startActivity(intent);
ACTION_LOCALE_SETTINGS
API level 1から追加。 端末の言語設定画面のアクション。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_LOCALE_SETTINGS);
startActivity(intent);
ACTION_LOCATION_SOURCE_SETTINGS
API level 1から追加。 位置情報アクセス設定画面のアクション。 位置情報の取得モードを切り替えさせるのに使うっぽい。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS
API level 9から追加。 すべてのアプリケーション情報画面のアクション。 アプリ設定画面の「すべて」タブのこと。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS);
startActivity(intent);
ACTION_MANAGE_APPLICATIONS_SETTINGS
API level 3から追加。
アプリ管理画面のアクション。
ACTION_APPLICATION_SETTINGS
と同じ画面が表示された。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS);
startActivity(intent);
ACTION_MEMORY_CARD_SETTINGS
API level 3から追加。 外部ストレージ設定画面のアクション。 このアクションは端末ごとの差異が激しいかもしれない。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_MEMORY_CARD_SETTINGS);
startActivity(intent);
ACTION_NETWORK_OPERATOR_SETTINGS
API level 3から追加。 利用可能なネットワーク設定画面のアクション。 表示と同時に利用可能なネットワークの検索が始まる。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_NETWORK_OPERATOR_SETTINGS);
startActivity(intent);
ACTION_NFCSHARING_SETTINGS
API level 14から追加。
ICE_CREAM_SANDWICH
から追加されたAndroidビーム設定画面のアクション。
Androidビームの有効/無効はNfcAdapter#isNdefPushEnabled()
で確認できる。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_NFCSHARING_SETTINGS);
startActivity(intent);
ACTION_NFC_PAYMENT_SETTINGS
API level 19から追加。
KITKAT
から追加されたタップ&ペイ設定画面のアクション。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_NFC_PAYMENT_SETTINGS);
startActivity(intent);
ACTION_NFC_SETTINGS
API level 16から追加。 NFC設定画面のアクション。 Nexusなどでは無線とネットワーク画面内のチェックボックス。 NFCが追加されたのはAPI level 14からだが、この定数はAPI level 16からなので注意。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_NFC_SETTINGS);
startActivity(intent);
ACTION_PRINT_SETTINGS
API level 19から追加。
KITKAT
で追加された印刷サービス設定画面のアクション。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_PRINT_SETTINGS);
startActivity(intent);
ACTION_PRIVACY_SETTINGS
API level 5から追加。 プライバシー設定画面のアクション。 Nexusではバックアップとリセット画面が相当。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_PRIVACY_SETTINGS);
startActivity(intent);
ACTION_QUICK_LAUNCH_SETTINGS
API level 3から追加。 Searchキーと他キーの同時押しで起動するアプリ設定画面のアクション。 この機能自体を知らなかった。ハードウェアキーボードが存在する端末向きだろうか? Android L Developer Previewではクラッシュする。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_QUICK_LAUNCH_SETTINGS);
startActivity(intent);
ACTION_SEARCH_SETTINGS
API level 8から追加。 検索設定画面のアクション。 NexusではGoogle検索アプリの設定画面が表示される。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_SEARCH_SETTINGS);
startActivity(intent);
ACTION_SECURITY_SETTINGS
API level 1から追加。 端末のセキュリティ設定画面のアクション。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_SECURITY_SETTINGS);
startActivity(intent);
ACTION_SETTINGS
API level 1から追加。 設定アプリのアクション(設定アプリの起動)。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_SETTINGS);
startActivity(intent);
ACTION_SOUND_SETTINGS
API level 1から追加。 端末の音関連設定のアクション。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_SOUND_SETTINGS);
startActivity(intent);
ACTION_SYNC_SETTINGS
API level 3から追加。
アカウントの同期設定のアクション。
Settings.EXTRA_AUTHORITIES
でSyncAdapter
のauthorities
を指定することで直接その同期設定が開けるようだが未検証。
Settings.EXTRA_AUTHORITIES
未設定の場合は設定済み同期一覧が表示される。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_SYNC_SETTINGS);
startActivity(intent);
ACTION_USER_DICTIONARY_SETTINGS
API level 3から追加。 ユーザー辞書設定画面のアクション。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_USER_DICTIONARY_SETTINGS);
startActivity(intent);
ACTION_WIFI_IP_SETTINGS
API level 3から追加。 Wi-Fi接続時のIP設定画面のアクション。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_WIFI_IP_SETTINGS);
startActivity(intent);
ACTION_WIFI_SETTINGS
API level 1から追加。 Wi-Fi設定画面のアクション。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_WIFI_SETTINGS);
startActivity(intent);
ACTION_WIRELESS_SETTING
API level 1から追加。 無線とネットワーク設定のアクション。
Intent intent = new Intent();
intent.setAction(Settings.ACTION_WIRELESS_SETTING);
startActivity(intent);