2015年7月25日土曜日

Android開発 LayoutInflaterを利用してListViewをカスタマイズする

Androidのリスト表示をカスタマイズして、クリック、長押しに反応するようにします。
リスト表示の見た目を変えるために、LayoutInflaterを利用します。
http://developer.android.com/intl/ja/reference/android/view/LayoutInflater.html

とくになにもせずAndroidのListViewを表示したときは、単一のテキストまたはボタンなどが行になって表示されます。
色々な要素をリスト表示したいときには、たとえば、Webサイトの場合だとループの中にHTMLを書くだけで済むのですが、Androidの場合は、LayoutInflaterを利用してListViewの中に動的にxmlを差し込んで表示したりする必要があります。
また、リストをスクロールしたとき、リストの要素が再利用されるので、リスト番号が単純に上から順にインクリメントされているわけではなく、クリックでリスト番号を取得するための挙動を制御する必要がありました。
このように、Androidでのリストの扱いは、ひとくせある感じになっています。

目的を実現するにあたって、以下の資料を参考にしました。

androidでRSSを取得して一覧表示 - m_shige1979のささやかな抵抗と欲望の日々
http://m-shige1979.hatenablog.com/entry/2015/07/15/080000
Adapter#getViewの挙動について - hyoromoのブログ
http://hyoromo.hatenablog.com/entry/20090912/1252777077
Android -ListView(イベント処理)- <MitoRoid>
http://mitoroid.com/category/android/android_listview3.php
LayoutInflater - Androyer in Japan
https://sites.google.com/site/androyerjapan/home/layoutinflater
ListView で onItemClick() と onItemLongClick() を両立 - Unmotivated
http://blog.lciel.jp/blog/2013/11/22/onitemclick-vs-onitemlongclick/

以下、コードの解説です。

MainActivity.java

リストの要素を作ります。ArrayAdapterを継承したrowAdapaterをリストビューに渡しています。
クリック・長押しされたときにトーストを表示するようにします。

RowDetail.java

リストの要素を保存する際に使用するクラスです。

RowDetailAdapter.java

リストビュー用のアダプターです。
リストをスクロールして、新しい行が表示されるタイミングでgetViewが実行されます。
レイアウトが初めて作成される場合のみLayoutInflaterを実行します。それ以外は、表示されなくなったViewが引数に渡されてくるので再利用します。

activity_main.xml

ListViewを表示します。

row.xml

ListViewの中身になります。

2015年7月18日土曜日

Android開発 JSONをVolleyで取得して、お天気アプリを作る

JSONデータを返すAPIを叩いて、ビューに表示するだけの簡単なAndroidサンプルアプリです。
APIを叩くときには、Androidの非同期HTTP通信ライブラリである”Volley”を使います。
今回のアプリは、この、Volleyのトレーニング目的で作ってみました。
APIは、livedoor 天気情報のAPIを利用します。(http://weather.livedoor.com/weather_hacks/webservice

さて、このVolleyとはいったい何でしょうか?
こちらの記事が参考になります。

ネットワーク通信用ライブラリVolleyを使いこなす | Tech Booster
http://techbooster.org/android/hacks/16474/
Android SDKでは非同期処理(またはマルチスレッド化)のための機構が用意されています。AsyncTaskやService、それらを拡張したAsyncTaskLoader、IntentServiceが代表的です。さらに汎用的に使えるHandler、ApacheのHttpClient、JavaのExecutorService、Threadなど非同期処理のための仕組みが豊富に存在していますが非同期でのキャンセル処理や取得済みデータのキャッシュ方法など周辺技術と組み合わせて設計しないといけません。
Android SDKの標準APIは応用力が高いのですが、習得するまでの難しさ、エラー処理、各バージョンごとの実装差異が存在しています。これらの課題を解消するためにVolleyライブラリが作られました。
以前、Apache HTTP Client(DefaultHttpClient)を使ったサンプルアプリを作ったことがあるのですが、どうやら、最近のAndroidでは、メインスレッドからネットワーク処理を行うことを許していないそうで。別スレッドを立ち上げてHTTPの処理を実行したり、さらに、これが別スレッドであるがためにViewに情報を渡そうとすると、ハンドラを生成したりと案外面倒だった記憶があります。Volleyは、この複雑だった処理を簡潔に書けるようにします。
Volleyは、ネットワークリクエストとキャッシュをスレッドプールを使って、それぞれの通信処理をリクエストという単位でキューイングして処理を捌きます。そして、コールバックで処理結果がUIスレッドに渡されます。
ネットワーク経由で取得した情報をビューへ渡すための処理をVolleyに任せる感じです。

以下の資料を参考にしました。

Transmitting Network Data Using Volley | Android Developers
https://developer.android.com/training/volley/index.html
Android working with Volley Library
http://www.androidhive.info/2014/05/android-working-with-volley-library-1/
Volleyについて調べる(1) - 未処分利益
http://www.vagrantup.jp/entry/2013/12/07/164310
Volley 基礎 (Android アプリ用ネットワークライブラリ) - ひだまりソケットは壊れない
http://vividcode.hatenablog.com/entry/android-app/volley-basis
Android - Volleyの起動・停止・キャンセル - Qiita
http://qiita.com/ueno-yuhei/items/d81dc638951ce3f6988a
ケーワン・エンタープライズのエンジニアメモ(`・ω・´)ゞビシッ!!: Volleyを使ってみる(JsonArrayRequest、JsonObjectRequest編)
http://k-1-ne-jp.blogspot.jp/2013/09/volleyjsonrequestjsonarrayrequestjsonob.html
【Android】Volleyを使ってネットワーク通信 その2 実装編【ライブラリ】 | 手巻き式IT
http://temakishiki.com/?p=141

Android StudioのプロジェクトにVolleyを導入

コマンドラインから操作します。
プロジェクトのディレクトリに移動。gitでVolleyプロジェクトをサブモジュールとして追加。
$ cd ~/StudioProjects/YourProject/
$ git submodule add https://android.googlesource.com/platform/frameworks/volley modules/volley
settings.gradleファイルを編集、 ,':modules:volley' を追記。
$ emacs settings.gradle
include ':app'
->
include ':app',':modules:volley'
app/build.gradleファイルを編集、compile行を追記。
$ emacs app/build.gradle
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.2.0'
}
->
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.2.0'
    compile project(':modules:volley')
}
この状態で、Android StudioのメニューからBuild -> Make Projectしてみてください。エラーが出なかったらVolleyライブラリ導入成功です。

Volleyを使ったサンプルコード

以下、サンプルコードです。

2015年7月10日金曜日

Android開発 WebViewでウェブページを読み込む


最近、趣味でAndroidアプリを作っていて、初心者レベルなのですが、若干知見が溜まってきたので、サンプルコードをブログにしてみます。

ここでは、Androidでウェブページを読み込む方法を紹介します。
いくつか方法があるのですがここではスタンダードなWebViewを利用します。
Activityは、Blank Activityを使います。

AndroidManifest.xml
まず。AndroidManifest.xmlを設定します。以下の設定を入れることによってインターネットへのアクセスを許可します。
<uses-permission android:name="android.permission.INTERNET" />

MainActivity.java
MainActivity.javaでは、onCreateにWebViewのコードを書いていきます。
古いAndroid端末では、WebViewで開いたページのリンクをタップすると、標準ブラウザが立ち上がってしまうのですが。以下のコードで抑制をしています。
mWebView.setWebViewClient(new WebViewClient());
JavaScriptを有効にします。
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
ユーザエージェントを設定します。このコードでは、標準のWebViewのユーザエージェントに追加で独自の文字列を追加しています。
String ua = mWebView.getSettings().getUserAgentString();
ua = ua + " my-android-app";
mWebView.getSettings().setUserAgentString(ua);
キャッシュと履歴をクリアします。
mWebView.clearCache(true);
mWebView.clearHistory();
指定したURLを開きます。
mWebView.loadUrl(top_url);
あとは、アプリがバックグラウンドになった時や、別のActivityが有効になったときのWebViewの処理を入れていきます。
onResume, onPause, onStop, onDestroyの処理です。
もし、この設定を入れないと、たとえばYoutubeなどを再生していて、アプリをバックグラウンドにした時などに音が再生されっぱなしになってしまったりします。必ず入れましょう。
また、WebViewを使っているActivityはできるだけ破棄しておかないと、アプリのクラッシュが発生することがあります。
「問題が発生したため〇〇を終了します」といったエラーメッセージが出て、アプリが強制終了してしまったときには、このあたりを疑ってみると良さそうです。
別のActivityを開くときには、 finish(); でアクティビティスタックを破棄しておくと安心できます。

以下の資料が参考になりました。

図で理解するActivityのスタック
http://techblog.qoncept.jp/?p=102
恵比寿のベンチャーで働くエンジニアのメモ帳|【Android】Intent発行時にActivityスタックをクリアする方法
http://6rats.blog62.fc2.com/blog-entry-107.html
1. アクティビティ - ソフトウェア技術ドキュメントを勝手に翻訳
http://www.techdoctranslator.com/android/guide/activities
Android - Activity のライフサイクル再確認 - Qiita
http://qiita.com/calciolife/items/39b2696a9a03e8591d40
Fragmentのライフサイクルメモ - Androidはワンツーパンチ 三歩進んで二歩下がる
http://sakura-bird1.hatenablog.com/entry/20111207/1323267262

activity_main.xml
activity_main.xmlでは、WebViewのレイアウトを記述します。layout_widthとlayout_heightの設定をmatch_parentとしています。WebViewを最大の幅で表示するという設定です。

dimens.xml
dimens.xmlでは、activity_horizontal_margin, activity_vertical_marginを0dpに設定しています。これでWebViewを余白なしで画面いっぱいに表示することができます。

以下、サンプルコードです。