【Android】AdapterとかListViewとかLayoutInflaterとか
Adapterって何? ImageSwitcher を使おうとしたら、Adapter なるものが出て来た。 初めて見るのでいろいろ調べていたが、どうにも分からん。 というか、イメージが掴めない。 いろいろ調べたり考えたりした結果、自分なりに Adapter とはみたいなイメージができたので、メモっとく。 橋渡し?箱?媒介? 「android Adapter 」でググってみると、確かにいろんなサイトが出る。 が、多くのサイトが、Adapter とはデータと View の橋渡しをするもの、という説明をしている。 この橋渡しがよう分からんから調べとるというのに。 あるいは、Adapter は箱のようなもので、そこにデータを詰めます、View はそこ(=Adapter)からデータを取得します、みたいな説明をしているサイトもある。 橋渡しと箱って、随分違くね? 結局 Adapter って何? よく使うっていう割に、何でこんな分かりにくいの? ImageSwitcher の API demo のソース見たら getView() とかあるしもう???が取れないんですけど。 みたいな状態になって自分なりにいろいろ考えた末に行き着いた結論。 Adapter は、媒介である。 経路と言ってもいい。 これを、がんばって説明してみようと思う。 Androidから離れて考えてみる 昔、化学か物理の参考書をいろいろ探していた時に、次のようなフレーズを目にした。 「いかに早く、正確なイメージを抱けるかが勝負です。」 当時探していた参考書が何だったか覚えていないが、これは15年以上経って覚えているフレーズなのだから、よほど印象深かったのだろう。 それ以来、分からないことがあったら、理解するためにイメージを抱くということをとても重視してきた。 大学院時代の数式しかり、今回の Adapter しかり。 イメージするには、具体的に想像しやすい例の方がいい。 ここでは、日常生活を例に考えてみる。 後でまた戻ってくるので、一旦 Adapter のことは忘れておく。 やり取りに必要な3要素 -日常生活編- 情報は、1) データ、2) 経路・媒介、3) 表示・知覚 の3つあれば、相手に伝えることができる。 例として、電子レンジでご飯を1分温めることを考える。 電子レンジは複数のメーカーが出しているが、 時間を1分に設定 →1分に設定されたことを確認 →スタート という大枠は変わらないと思う。 ここで、データは1分という値、経路・媒介は電子レンジの回路、 表示・知覚は電子レンジの液晶になる。 別の例として、声で何か伝えることを考える。 ここで、データは実際に言ったセリフ、経路・媒介は音声を伝える空気、表示・知覚は耳となる。 媒介が空気というのがわかりにくいかもしれないが、空気がないところでは、 どれだけ大声で発声しても、それを「声」として知覚することはできない。 だから、宇宙空間に風は吹いていないし、宇宙ではそこらじゅうで破片がぶつかっているが、 その衝撃を音として聞くことはできない。 波紋は水があるところにしかできないのと同様に、空気があるところでしか声は聞こえないのである。 そして最後に、耳という音声の受信器官がなければ、音声としてセリフを認識することはできない。 また別の例として、ノートに落書きを描くことを考える。 ここで、データは描いた落書きそのもの、経路・媒介は描いたノート、 表示・知覚は言葉にしにくいが、描画という作業になるだろうか。 この経路・媒介のことを、Androidの用語で Adapter といい、表示・知覚のことを View という。 やり取りに必要な3要素 -Android編- 情報は、1) データ、2) 経路・媒介、3) 表示・知覚 の3つあれば、相手に伝えることができる。 これをAndroidの用語に置き換えると、 情報は、1) データ、2) Adapter、3) View の3つあれば、相手に伝えることができる。 と言える。 オレは、何をどうやって表示するのか、ということに気が周りがちである。 文字をTextViewで出すのか、EditTextにするのか、 背景色は色で指定するのか、画像で用意するのか、 一覧表示にListViewか、ExpandableListか、Spinnerか、どれを使うべきか、 ユーザへの告知はノーティフィケーションか、だいあろぐか、トーストか、どれを使うべきか。 しかし、電気回路がなければ液晶に何分に設定したのか分からず、 空気がなければ音は聞こえず、ノートがなければ絵は描けない。 Androidでも同じように、一覧として表示したいデータと、 一覧表示をするためのものという見た目の間を媒介するものが必要になるらしい。 この媒介するものが、Adapterである。 絵を描くのに、ノートやキャンバスなどがあるように、Adapterにも種類がある。 Mapのデータを表示するのか、データベースから取得したデータを表示するのかなど、 どんなデータを表示するかによって、種類があるらしい。 電子レンジの例で言うと、1分というボタンなりダイヤルと表示する液晶だけあっても、 間に回路がなければ、ただの鉄の箱である。 声の例で言うと、伝えたい言葉と相手の耳があっても、間に空気がないような 真空空間では声は伝わらない。 絵の例で言うと、描きたい絵と描くスキルはあっても、描くノートがなければ絵は描けない。 このように考えると、AdapterはデータとViewの橋渡しをしているというのも、 少しはイメージできるかもしれない。 Linuxユーザなら、LinuxのデータにアクセスするためのシェルがAndroidでいうAdapterだ、 といえば早いかもしれない。 Adapterの役割 ここまでの話で、Adapterとは何なのか、ある程度イメージができれば、 具体的な使い方を覚えていくだけである。 といっても、オレ自身まだ初歩の初歩しか使えないが、今分かってる範囲で説明してみようと思う。 というのも、Adapterは回路だ、経路だ、媒介だ、橋渡しだ、といってもあくまでも イメージなので、実際に何をやるのか知ることで、マスターへの道を目指す。 ネット上にはいろいろなページがあるが、ここはAndroidの本家サイトを訳しながら、 できることをざっと見てみる。 Androidの本家サイト「Adapter」 http://developer.android.com/reference/android/widget/Adapter.html "An Adapter object acts as a bridge between an AdapterView and the underlying data for that view. " 「Adapterは、AdapterViewとそれに紐づくデータの橋渡しをするものである。」 といった感じだろうか。 ネットでよく見る「橋渡し」という説明は、ここの"bridge"から来てる気がする。 データとViewの橋渡しといっても、全てのViewを対象にした話ではなく、 AdapterViewや、AdapterViewを継承したクラスと、そこにセットするデータの橋渡しをするらしい。 underlyingがちょっと悩んだが、
このイメージから、紐づいている、と訳した。 全てのViewが対象じゃないよ、というのが新情報かな。 "The Adapter provides access to the data items. " 「Adapterは、(開発者に)データへのアクセスを提供する。」 「(開発者は、)データには、Adapterを通してアクセスする。」 「(開発者は、)Adapterを使って、データにアクセスする。」 といった感じだろうか。 ユーザが押した「1分」というデータは、回路から取得して液晶に出す。 ということに該当するかな。 「提供する」という書き方だと、あるけど使わなくていいよ。 という意味に取れる。 実際、直接データにアクセスすることはできるが、直接データを変更してしまうと、 Viewは変更されたことを知らないので、開発者がViewに、データが変更されたことを 明示的に教えてあげる必要がある。 このあたりは、下記ページの最下部「コレクションの更新」に書いてある。 http://android.keicode.com/basics/ui-listview.php コレクションをデータと置き換えると、分かりやすいかも。 プログラム開発していると、「このViewにはこのデータを表示する」というように、 Viewにどんなデータを表示するのか分かっているのでいきなりアクセスしそうである。 少なくともオレは。 でも、まだ直接データをいじる必要があるところまでいってないので、 今は、「データの更新はAdapterを使って行う」と覚えておく。 "The Adapter is also responsible for making a View for each item in the data set." 「Adapterは、また、データセットの中にある各アイテムのために、Viewを作る責任がある。」 ここがやりたかった。 もうちょっと読み解いて行く。 実は、Adapterで取り扱うデータは、TextViewで表示する文字列のように、 単独で使用するデータではない。 Adapterは、一覧を表示するリスト(ListView)のように、「中身が同じ構成のもので埋まるデータ」 を専門に取り扱う仕組みなのである。 参考:http://andante.in/i/android%E3%82%A2%E3%83%97%E3%83%AAtips/adapter%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%92%E4%BD%BF%E3%81%86%E6%99%82/ 従って、Adapterにセットするデータは、intやString単独ではなく、それらの配列、リスト、 またはそれらをメンバー変数に持つクラスの配列やリストなのである。 上記本家サイトの配列 "data set" とは、この配列やリストのことを差している。 また、"each item" とは、その配列やリストの各要素である、データそのものを差している。 これらを踏まえて上記の直訳をもう少し意訳すると、 「Adapterは、各データのViewを作成する。」 「(開発者は、)各データのViewをAdapterから取得する。」 といった感じだろうか。 オレは最初これを見た時、媒介がViewも作んのかー、と思った。 例えば、絵を描く例を考えてみると、「何に何を使って」絵を描くかで、 できる絵は全然違うものになる。 ノートに鉛筆で描く、ポスターにクレヨンで描く、キャンバスに油絵の具で描く、 壁にスプレーで描く、これらの絵は、全く異なる性質を持つ。 Viewは、「実際に描く」ことしかできない。 従って、「これでここに描いて」という指定は、誰かがしないといけない。 データは描く絵そのものなので、媒介役のAdapterが指定しないといけない。 と考えて、納得した。 そう、どんなViewにするのかは、Adapterが指定しないといけないのである。 これが、Adapterを自作する時に getView() メソッドをオーバーライドする理由である。 getView() メソッドのオーバーライドについては、後述する。 本家サイトの概要説明は以上で終わり。 理解を深めるために、どんなメソッドがあるのか、概観する。 ここで詳細に入り込むことはせず、使う時に都度触れることとする。 だいたい、データについてやりたいことは、Adapterが全部やってくれるらしい。 getCount
How many items are in the data set represented by this Adapter. データ(=配列やリスト)に含まれる要素数を取得する Object getItem
Get the data item associated with the specified position in the data set. position番目のデータを取得する。 (正確には、positionは配列やリストのインデックスである。)
View getView
Get a View that displays the data at the specified position in the data set. position番目のViewを取得する。 このメソッドは、開発者が明示的に呼ぶものではなく、position番目のデータがスクロールなどで 表示される時に、アプリに自動的に呼び出される。 Adapterの使い方 いよいよ、Adapterの使い方を覚えていく。 と言いたいが、Adapterの使い方を覚えるのにとてもよくまとまったサイトを見つけた。 ■ ListViewの利用方法 http://android.keicode.com/basics/ui-listview-top.php Adapterを使う代表格であるListViewの使い方を、簡単な例から丁寧に説明してくれてる。 どこがポイントなのかも示されているので、どこを重点的に見ればいいか分かりやすい。 後は、上記のサイトを基に書いたコードを、以下のgithubにアップした。 https://github.com/kei-naka/android_sample_ListView FAQ ■ ArrayAdapter で、TextView以外を使いたい。 下のソース実行したら、強制終了しちゃうんだけど、何で? # res/layout/view_imageView.xml レイアウトXMLで、 - TextView を ImageView に置き換えたやつを view_imageView.xml とかの名前で用意して、 - データを drawable に用意して、 - Integer[] data = {R.drawable.data1, ...}; みたいにデータも用意して、 - ArrayAdapter<Integer> adapter = new ArrayAdapter(this, R.layout.view_imageView, data); みたいにアダプター用意して ダメらしい。 Google 本家 ArrayAdapter http://developer.android.com/reference/android/widget/ArrayAdapter.html 「To use something other than TextViews for the array display, for instance, ImageViews, or to have some of data besides toString() results fill the views, override getView(int, View, ViewGroup) to return the type of view you want.」 ↓和訳概要 TextView 以外を配列に使いたいときは、その欲しい View を戻すように、getView() をオーバーライドする必要がある。 getView() のオーバーライド方法を習得するしかないらしい。 参考にしたサイト ■ Adapterの高速化 http://labs.techfirm.co.jp/android/cho/2161 Adapter では、getView() メソッドで View が呼ばれるのだが、この getView() メソッドは頻繁に呼ばれるので、できるだけ高速に処理できることが望ましいとされている。 高速に処理するよう、修正前後のソースがそれぞれあり、各ソースにコメントも書いてあるので、追いやすい。 ■ adapterクラスを使う時 http://andante.in/i/android%E3%82%A2%E3%83%97%E3%83%AAtips/adapter%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%92%E4%BD%BF%E3%81%86%E6%99%82/ Adapterとは何か、どういう種類があるのか、どういう時に使うのかなど、 Adapter について知りたい項目が一通りまとめられている。 また、どういう時にどういう Adapter を使えばいいのか、端的にまとめられていて分かりやすい。 ソースも書いてあり、引数の説明や、オーバーライドしてるけどそれ何?みたいな心の声にもちゃんと答えてくれており、ついて行こうという気になる。 ■ ArrayAdapterクラス http://www.javadrive.jp/android/arrayadapter/ android で調べてると、よく行き着く伊倉さんのサイト。 残念ながら、Adapter 関連の解説は ArrayAdapter しかなかったが、最も基本的な ArrayAdapter の使い方を学べる。 特に、「Stringクラスの配列を使ったArrayAdapter」では、Adapter にセットする View を自分で作るやり方がさらっと書いてある。 上記のページ以外にも、Gellery を使うところで Adapter の使用例を見ることができる。 というより、もともとやりたかったのはこっち。 http://www.javadrive.jp/android/gallery/index2.html ■ Adapter http://developer.android.com/reference/android/widget/Adapter.html androidドキュメント本家。 "An Adapter object acts as a bridge between an AdapterView and the underlying data for that view. The Adapter provides access to the data items. The Adapter is also responsible for making a View for each item in the data set." 冒頭の、この3文に Adapter の全てが込められている気がするが、いきなりこれだけ読んでも謎が増えるだけだった。 多くのサイトにあった、「橋渡し」という単語は、上記の「bridge」から来ているのではなかろうか。 確かに、橋渡しなんだけど、いきなりそれ言われて「あぁ」と分かるほど、自分は頭よくなかったらしい。 とはいえ、本家なので、メソッドなどが全て載っている。 一通り理解してから見ると、理解がより進むと思う。 ■ ListViewの利用方法 http://android.keicode.com/basics/ui-listview-top.php Adapterを使う代表格であるListViewの使い方を、簡単な例から丁寧に説明してくれてる。 どこがポイントなのかも示されているので、どこを重点的に見ればいいか分かりやすい。 1. 静的な文字列のリスト表示 2. ボタンクリックに応じて動的に文字列のリスト表示変える http://android.keicode.com/basics/ui-listview.php 3. ボタンクリックに応じて動的に文字列で構成される構造体(=オブジェクト)をリストに表示する http://android.keicode.com/basics/ui-listview-pojo.php 4. getView()オーバーライドしないでカスタマイズする方法 http://android.keicode.com/basics/ui-listview-simple-customize.php 5. getView()オーバーライドしてオリジナルのAdapter作る方法 http://android.keicode.com/basics/ui-listview-customize.php ■ListViewとListActivity(3) -応用編- http://ichitcltk.hustle.ne.jp/gudon/modules/pico_rd/index.php?content_id=70 BaseAdapterとArrayAdapterの継承例が書いてある。 Eclipseで枠は作ってくれるけど、実際にどういうコードを書けばいいか分からんという時に、 まず見るといいと思う。 ■Adapter #getView の挙動について http://d.hatena.ne.jp/hyoromo/20090912/1252777077 getView() はどのタイミングで呼ばれるの?という疑問に、図付きで解説してあってイメージしやすい。 そりゃgetView() の中で都度インスタンス作ってたらすぐメモリなくなるよな、という気になる。 ■アイコン付きのリストを作ってみる http://xfutures.jp/2010/02/14/197/ ArrayAdapter<独自クラス> を継承して、独自Adapterを作る実装例が紹介されている。 ソースにコメントも記載されており、地味に役立つ。 zipでソースコードも公開されている。 ■リストビュー(ListView)を使う http://techbooster.org/android/ui/9039/ ListViewでよく使うメソッドがまとめられてる。 リストの項目がクリックされた時、フォーカスされた時、長押しされた時など。 LayoutInflater関係 LayoutInflaterとは、レイアウトXMLをコンパイルして指定されたビューに紐づけてくれる仲介人。 LayoutInflaterでインフレート(実際に紐づける処理)をすると、レイアウトが設定される。 メニューのレイアウトをコンパイルしたり、ListView の行レイアウトをコンパイルする時に使う。 ということを理解するために漁ったサイト。 ■LayoutInflater http://developer.android.com/reference/android/view/LayoutInflater.html#inflate%28int,%20android.view.ViewGroup,%20boolean%29 android本家。 Instantiates a layout XML file into its corresponding View objects. という冒頭の一文に全て詰まっている気がする。 ■LayoutInflaterについて勉強する http://androyer.blogspot.jp/2011/09/layoutinflater.html だいたいインフレーターって何だよというような、初めて触れた時の???を代弁してくれてる。 悩んでるのはオレだけじゃない!という安心感が出るw ■LayoutInflater https://sites.google.com/site/androyerjapan/home/layoutinflater View = inflater.inflater(R.layout.row, null); の、第2引数って何?が説明されている。 いつも null 入れてるけど、本来何を入れるの? null 以外を入れたらどうなるの?という説明がされている。 初めて読むと???なので、最初は null を入れるものとしておいて、ListViewとかAdapterとかに慣れて疑問がわいたら見るといい。 ■LayoutInflaterを使ってみる http://team-pag.interprism.co.jp/member/okazawa/blog/?p=138 activityで使われてるけど、実際の使用例が載ってる。













