Android 5.0 差分メモ

自分用あとで読むメモ

Android 5.0 概要

Android Lollipop | Android Developers

API 概要

Android 5.0 APIs | Android Developers

API 差分

API Differences between 20 and 21

Support Library 変更点

Support Library | Android Developers

Support Libraryのリビジョンごとの差分は提供されていないようなので、5.0 API差分を元に類推する。

変更点まとめ

重要そうな変更点と関連URL

ActionBar.Tabが非推奨になった

ActionBarのタブが非推奨になった。 今後はcommon navigation patternsに従うようにとなっているが、具体的な実装が見つからない。 非推奨になっていないPagerTabStripを使うか、SlidingTabsを使うと良いかもしれない。

ActionBar.Tab | Android Developers

JobScheduler

端末の状態に応じてバックグラウンドタスクを実行させるJobSchedulerが追加された。 バックポートされてない(今後もされなさそう)ので、使い所が難しそう。

Android 5.0 APIs | Android Developers JobScheduler | Android Developers

Activityの永続化サポート

PersistableBundleというクラスを利用した新しいライフサイクルメソッドが提供された。 これにより、Activityの情報を端末のリブートを超えて保持することができるようになった(と思う)。 同様の機能はSupport LibraryのActionBarActivityにも提供されている。

ActivityのpersistableModepersistAcrossRebootsであればリブート後も設定値を保持するようなのだが、 なぜかattrのページにはalwaysとかtaskOnlyとか書いてあってよくわからない。

R.attr | Android Developers

Activity | Android Developers

Toolbar

ActionBarの新しい実装としてToolbarが追加された。 ActionBarと違い、レイアウトの中に記述できるようになっている。 layout.xmlで定義したものをActionBarActivity#setSupportActionBarに渡して使うらしい。

Toolbar | Android Developers

Material Design

Material Designのサポートはv7-appcompatに追加された。

Support Library Features | Android Developers

Activity遷移アニメーション

新しいActivity遷移アニメーションがActivityOptionsCompatに追加された。 実はActivityOptionsCompatは以前からあったけどあまり使われてなかったようだ。 今回追加されたのはmakeSceneTransitionAnimationだけど他のTransitionも使いたい。

ActivityOptionsCompat | Android Developers

SwitchCompat

Switchのバックポートがv7-appcompatに追加された。

SwitchCompat | Android Developers

DocumentFile

DocumentFileがv4-supportに追加された。 DocumentProviderFileを同じように扱うための仕組みらしい。 ただしオーバヘッドが大きいのでパフォーマンス求めるならDocumentsContractを使えとのこと。 DocumentProviderがバックポートされていないので、おそらくLevel 19以降はDocumentProvider経由、 それ以前ではDocumentFile#fromFile(File)で初期化して以降は同じように扱えるよ、ということかな。

DocumentFile | Android Developers

v7-cardview

CardViewのサポートライブラリが追加された。

Support Library Features | Android Developers

v7-cardview

RecyclerViewのサポートライブラリが追加された。

Support Library Features | Android Developers

v7-palette

画像に合う色を生成できるPaletteのサポートライブラリが追加された。

Support Library Features | Android Developers

v17-leanback

Android TV向けアプリ用のサポートライブラリが追加された。

Support Library Features | Android Developers

【Android】いまさら聞けないdp入門 という記事を更新しました。

Qiitaに書いていた【Android】いまさら聞けないdp入門 - Qiitaという記事を更新しました。 (この記事も元々は同じ内容を記載していましたが、両方メンテすると大変なのでQiitaへのリンクページにしました)

さすがに公開から1年以上経つとAndroid Developersのリンク切れ(というか関係ないページへのリダイレクト)や古くなってしまった記述が多く、「dpとは」以外の部分はだいたい書き直しました。

また、Android Developersの日本語化されたページで用語に訳がついたものはそちらにあわせています。

差分: 「【Android】いまさら聞けないdp入門」の編集履歴 - Qiita

Androidアプリのタブレット対応レイアウトまとめ

はじめに

タブレットスマートフォンの最大の違いは画面の横幅です。 Androidアプリをタブレット対応させる際は、いかにして画面の横幅を埋めるかが重要になります。 この記事では余白を埋める様々なパターンについて解説しています。

Android Developersの以下のページを参考にしてください。 Planning for Multiple Touchscreen Sizes | Android Developers Supporting Tablets and Handsets | Android Developers Multi-pane Layouts | Android Developers

各画面内での対応

画面遷移やActivity構成に影響を与えずにレイアウトを調整する方法です。 タブレットで見やすくはなりますが、使い勝手の向上に関しては限界があります。

コンテンツを拡大する

画面幅いっぱいにコンテンツを表示できるようにレイアウトを調整する方法です。 コンテンツの拡大はLinearLayoutandroid:layout_weightなどで行います。 横方向にコンテンツを並べるレイアウトと相性がよく、とくにGridViewなどコンテンツをタイル状に並べるレイアウト見栄えがよくなります。

Googleカレンダーの月表示はコンテンツ領域を画面全幅に拡大しています。 01.png

コンテンツの最大幅を決める

Webページなどでよく見かける、コンテンツを中央寄せにして左右に余白をもたせる方法です。 画面幅によってandroid:layout_widthで使用するdimenを切り替えることで実装できます。 特にログイン画面やチュートリアル、入力欄が多い画面は崩れにくくなるので向いていますが、画像や動画などが多く含まれるコンテンツでは情報量が増えないためあまり向きません。 また、背景が白や黒だと手抜きに見えやすいので、ある程度工夫が必要です。

Google Keepでは一覧画面を最大幅で表示し、詳細/編集画面をダイアログのように表示しています。 02.png

コンテンツの配置を変える

縦一列にならんでいたコンテンツを複数列に配置する方法です。 詳細画面などで適用すると画面領域に無駄がなくなり効率的です。 スクロール領域の分割や一部コンテンツの拡大など、使い勝手を向上できる可能性があります。 反面、画像や動画といった大きめのコンテンツがないとごちゃごちゃして読みづらい印象になりがちです。

Youtubeアプリの動画再生画面はコンテンツの再配置を行っています。 03.png

グリッド化

リストコンテンツを複数列に配置する方法です。 コンテンツの配置を変える方法に近いのですが、レイアウト差が少ないコンテンツの繰り返しがある場合に適用します。 ListViewなどAdapterViewを継承したクラスで実装している場合、比較的少ない工数で切り替えできる可能性があります。 OnItemClickListener()setAdapter()など、主要な機能はAdapterViewに定義されているので、コーディング時に気をつければ切り替えは容易になります。 最近ではGoogle Keepのようにコンテンツの高さが異なる場合に余白を詰めて互い違い風にしたグリッドもよく見かけるようになりました。

Google+ではストリームのカードを複数列に配置しています。 04.png

複数画面にまたがる対応

いわゆるマルチペイン化のような方法です。 ここで紹介するのはシングルペイン構造の画面をマルチペイン化する方法ですが、Android Developersではすでにマルチペイン化されたコンテンツのタブレット対応について説明しているページがあります。

ぜひ参考にしてください。

Multi-pane Layouts | Android Developers Planning for Multiple Touchscreen Sizes | Android Developers

メニューの展開

NavigationDrawerなどの普段は隠れているメニューを常時表示させる方法です。 NavigationDrawerActionBarと深く結合しているため、常時表示する際はActionBarDrawerToggleMenuItemなどの処理まで手を加えなくてはいけません。 また、NavigationDrawerを常時表示させた場合、後述するMaster/Detailパターンと重複しやすいことも注意が必要です。

GmailNavigationDrawerに相当する部分がトップ画面で表示されるようになっています。 05.png

Master/Detailパターン

一覧→詳細と画面遷移していたものを一画面に並べ、一覧選択時に詳細部分のみ更新されるようにする方法です。 一般的にマルチペイン化という場合、ほとんどがMaster/Detailパターンを指します。 様々なアプリで利用されていることからわかるとおり見栄え、利便性ともにかなり向上しますが、 一覧/詳細画面の実装によって実装の難易度がかなり違ってくるので個々の画面を作る際にも注意が必要となります。 AndroidにはMaster/DetailsパターンのためにSlidingPaneLayoutが容易されており、これを利用すると簡単です。

Gmailアプリの一覧/詳細はMaster/Detailパターンです。 06.png

Android UI/UX アンチパターン

参考資料

Android Developers

画面全般

スプラッシュ画面

必要のないスプラッシュ画面の表示はやめましょう。

なぜダメか

多くのアプリにおいて、スプラッシュ画面では何も処理していません。 このようなアプリでは、ユーザがアプリを起動してからスプラッシュ画面の表示が終わるまでの間、ユーザの時間を単純に浪費してしまいます。 わずかな時間かもしれませんが、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パターンのみです。

  1. ユーザがその処理を実行する前に結果を警告する必要がある場合(決済やリセットなど)
  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による実装を検討してください。

Menus | Android Developers

例外

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から呼ばれることを想定して書かれている場合、そのFragmentActivityは密結合である場合が多いです。 具体的には、以下の様な実装です。

  • ActivityのViewを参照する
  • Activityメソッドを直接呼び出す

なぜダメか

Fragmentの利点のひとつは優れた再利用性にあります。 Fragmentが特定のActivityに依存することで、Fragmentの再利用を妨げます。 現時点でアプリ内で再利用しないという場合でも、将来においてメンテナンスが困難になる可能性があります。

解決法

ActivityのViewを参照している場合、そのViewをFragmentに配置できないか検討してください。 ActionBarのタイトルやMenuItemFragmentでも操作できます。 Fragment内の特定のタイミングでActivityのViewを操作したい場合、後述するコールバックでの処理を検討してください。 どうしてもActivityと密結合になってしまう場合、FragmentではなくCustomViewとして実装したほうが良い場合もあります。

Activityメソッドを直接読んでいる場合、コールバックインターフェイスによる実装を検討してください。

if(getActivity() instanceof MyFragmentCallback){
    ((MyFragmentCallback)getActivity()).callback();
}

Fragmentからの不自然な画面遷移

Fragmentから新しいActivityへ遷移する際、getActivity().startActivity()するような実装は危険です。 特に、getActivity().startActivityForResult()を使用するのは避けてください。

なぜダメか

上記のような実装を行うとActivityからFragmentonActivityResult()を伝達する必要があり、密結合となる場合が多くなります。 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の一部機能はActivityFragmentのライフサイクルと同期させる必要があります。

なぜダメか

ライフサイクルメソッドの呼び出しを怠るとFlashHtml5コンテンツが休止されないため、音が鳴り止まない、バッテリーを浪費するなどの問題があります。

解決法

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<?>にしたり、StringCharSequenceにできないか検討して下さい。

なぜダメか

別にそのままでもダメではないのですが、必要最小限の実装を持つスーパークラスインターフェイスを指定することで将来の拡張に耐えられる場合があります。 特に文字列を引数で受け取り、その引数に対して編集などを行わない場合はCharSequenceにしておくことでTextView#getText()などを直接扱えるようになります。

解決法

より上位のクラスやインターフェイスで対応できないか検討して下さい。 自作のクラスを引数とする場合、インターフェイス化できないか検討してください。 (冗長になってしまう場合もあるので、Utilsクラスのみを対象とする、という形でも良いと思います)

仕様面

厳密にはソースコードレビューとは異なりますが、気にかけておくべき事柄。

画面構成がiOS

指摘してもどうしようもない場合が多いですが、一応…。

なぜダメか

AndroidにはAndroidに適したUIがあるので、なるべく沿うようにしましょう。 http://developer.android.com/design/patterns/pure-android.html

解決法

代替案を提案してみる他ないです。

  • 下タブ
    • NavigationDrawer
    • ActionBarタブ
  • 独自ヘッダー
    • ActionBar
  • 画面遷移要素の「>」マーク
    • 削除

特定のアプリへの依存

TwitterFacebookなどのSNSアプリに対してパッケージを指定した明示的なインテントを発行したり、インストールされていない場合にPlayストアに遷移するような構成は好ましくありません。

なぜダメか

これらは多くの場合、仕様を決める際の考慮漏れです。 本当に必要なのはTwitter,Facebookへの投稿ではなく、Twitter/Facebookを含むSNSなどへの拡散ではないでしょうか。 そうであった場合、MixiやG+など他のSNSへ拡散される機会を損失しています。 また、明示的にTwitterFacebookに投稿する場合であっても、公式アプリ以外のクライアントアプリの存在を考慮する必要があります。 特に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だけ指定すると以下のようにリストの上下端で子要素が途切れてしまう。

pict-Screenshot_2014-08-19-11-28-01.png

これを防ぐためには、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" />

pict-Screenshot_2014-08-19-11-27-37.png

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" >
        ...

…のだが、なぜかうまくいかない。

pict-Screenshot_2014-08-19-11-28-01.png

どうやらthemeではandroid:clipToPaddingの設定が反映されないらしい。 仕方がないのでソースコード側でListView#setClipToPadding(false)を呼び出すと動く。 ListFragmentで標準レイアウトを使う場合、themeで基本レイアウトを指定した後android:clipToPaddingだけソースコードで上書きするしかなさそうだ。

getListView().setClipToPadding(false);

これでうまく表示できた

pict-Screenshot_2014-08-19-11-27-37.png

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