Software/Android/アプリケーション開発テキスト

Chapter 6 : ウィジェットの作成

 この章ではサービスを利用して簡易RSSリーダーを拡張していきます。サービスはAndroidが提供するアプリケーションコンポーネントの一つで、アクティビティのように画面表示を持たずバックグラウンドで動作します。

 Chapter 4で作成した簡易RSSリーダーでは取得ボタンのタップでRSSフィードを取得していましたが、サービスを利用することでバックグラウンドで定期的にRSSフィードを取得することが出来ます。

6-1. サービスクラスの作成

6-2. サービスクラスの作成

6-3. サービスクラスの作成

 まずはRSSReaderプロジェクトにバックグラウンドでRSSフィードを取得するサービスを追加します。

 android.app.ServiceをベースクラスとしたFeedServiceを生成し、スレッドの処理をこのクラスで行うためRunnableのimplementsといくつかの定数、メンバ変数を追加します(リスト5-1)。

 定数SERVICE_ACTIONはこのサービスで取り扱うアクションを定義しています。実際にサービスがこのアクションを取り扱い出来るようにするためにはマニフェストファイルに記述する必要があります(後述)。定数BROADCAST_MSGはこのサービスが発行するブロードキャストインテントのアクションを定義しています。

 バックグラウンドでのフィード取得中に外部からリストを参照する可能性があるため、FeedListを二つ用意し、これを切り替える際の保護用にmWorkingというフラグも追加しています。

 続いてonStartメソッドを追加します(リスト5-2)。

 onStartはサービスが開始されると呼び出されるメソッドで、今回作成するサービスではこのタイミングでスレッドを作成し、このクラスをRunnableとして実行しています。

 アクティビティなどのコンポーネントから直接サービスの機能を呼び出して利用するには、サービスをバインドする必要があります。サービスをバインドするとonBindメソッドが呼ばれます(リスト5-3)。

 IBinder型のメンバ変数mIFeedServiceBinderを返すことで、このサービスへの直接アクセスを提供しています。mIFeedServiceBinderは後ほど実装します。

 前述の通り、このクラスにRunnableインターフェースを実装してスレッドを処理するためrunメソッドを追加します(リスト5-4)。

 runメソッドではまず、RSSReaderApplicationクラスのインスタンスを取得し、バックグラウンド用のFeedListに引渡してRSSフィードの取得を行います。フィードの取得に成功したらフォアグラウンド用FeedListを置き換えますが、他のコンポーネントがサービスバインダーを利用してRSSフィードの取得を行う際、参照中にリストが置き換わることのないよう、lock/unlockで排他制御を行なっています。

 置き換えが終わったら定数BROADCAST_MSGをアクションに設定したインテントを生成し、sendBroadcastメソッドでブロードキャストを発行します。

 続いて定数SERVICE_ACTIONをアクションとして設定したインテントを基にペンディングインテント(PendingIntent)を生成しています。ペンディングインテントとは、通常のインテントのように即時ではなく、指定したタイミングで発行するためのインテントです。
 ペンディングインテントの発行先としてこのサービスを指定し、現時刻から60秒後に発行されるよう、アラームマネージャ(AlarmManager)にセットします。

 これによりこのサービスが60秒毎に呼び出され、定期的なRSSフィードの受信を実現しています。

 サービスバインダーを追加します(リスト5-5)。IFeedServiceはこのサービスが外部コンポーネントに提供するメソッドインターフェースで、後ほど作成するAIDLファイルで定義したメソッドの実装をこれに含めます。

 lockList/unlockListはRSSフィードリストを参照する際に排他制御を行うために使用します。getFeedCountはフォラグラウンドになっているRSSフィードリストに含まれるフィード数を返し、その他の各種getメソッドで指定されたインデックスのフィード情報を外部コンポーネントから取得出来るようにしています。

 最後に排他制御に使用するlock/unlockメソッドを追加します(リスト5-6)。lockではmWorkingがtrueの間waitループを行い、他スレッドで参照している間は以後の処理を行わないようブロックします。

 以上でサービスクラスの作成は完了です。引き続きAIDLファイルの作成とマニフェスト修正を行います。AIDLはAndroid Interface Definition Language(Androidインターフェース定義言語)の略で、プロセス間通信に使用するインターフェースを定義するものです。

 Package ExplorerでRSSReaderのsrc/com.beatcraft.rssreaderを右クリックし、メニューから「New > File」を選択して下さい。"New File"ダイアログが表示されたら、File nameに「IFeedService.aidl」と入力して「Finish」ボタンをクリックします。

 作成されたIFeedService.aidlファイルを開き、リスト5-7のように編集します。先ほど追加したmIFeedServiceBinderで実装しているメソッドの宣言をここで行なっています。

 最後にRSSReaderのマニフェストファイル(AndroidManifest.xml)を開いて、application要素の子要素として今回作成したサービスを追加します(リスト5-8)。

 インテントフィルタとして、サービスクラス内で定義した定数SERVICE_ACTIONと同じ内容を保つアクションがリストされていることに注目して下さい。このフィルタを追加することで、AlarmMangerを利用して時間指定をしたペンディングインテントをこのサービスが受け取ることが可能になります。

5-2. ブロードキャストレシーバの作成

 続いて、サービスが発行したブロードキャストを受信するブロードキャストレシーバを作成していきます。

 android.content.BroadcastReceiverをベースクラスとしてFeedReceiverを生成し、メンバ変数とコンストラクタ、onReceiveメソッドを追加します(リスト5-9)。

 IFeedReceiverは受信したブロードキャストを実際に処理するためのインターフェースクラスで、コンストラクタで受け取ったIFeedReceiverのfeedReceivedメソッドをonReceiveで呼び出すようにしています。

 続いてIFeedReceiverを作成するため、Package ExplorerでRSSReaderのsrc/com.beatcraft.rssreaderを右クリックし、メニューから「New > Interface」を選択して下さい。"New Java Interface"ダイアログが表示されたら、Nameに「IFeedReceiver」と入力して「Finish」ボタンをクリックします。

 作成されたIFeedReceiver.javaを開き、feedReceivedメソッドの宣言を追加します(リスト5-10)。

 以上でブロードキャストレシーバは完成です。

5-3. サービスを利用する

 サービスとブロードキャストレシーバが完成したので、ここからはRSSReaderActivityをサービスを利用する形に修正していきます。

 IFeedReceiverのimplementsを追加し、ブロードキャスト受信用のアクション文字列定数BROADCAST_MSG、インテントフィルタとサービスバインダー、サービスコネクションをメンバ変数に追加しています。サービスコネクションはサービスとの接続を管理する際に使用され、接続時にインターフェースバインダーを取得しメンバ変数に設定しています。
 引き続きITaskEntityがimplementsされていますが、これは従来のHttpAccessTaskではなく、今回新規に作成するListGenerateTaskで使用します。ListGenerateTaskについては後ほど解説します。

 ボタンによるフィードの手動取得を廃止するため、onCreateでボタンにリスナーを設定している箇所(リスト5-12)、onClickで取得ボタンを処理している箇所(リスト5-13)を削除します。これにあわせ、レイアウトファイルmain.xmlの「取得」ボタン、strings.xmlの文字列リソースget_feedも削除して下さい。

 続いてonCreateメソッドの最後に、ブロードキャストレシーバの生成と登録、サービスの開始とバインド処理を追加します(リスト5-14)。

 先ほど実装したFeedReceiverを生成し、文字列定数BROADCAST_MSGをアクションとして設定したインテントフィルタとともにregistarReceiverメソッドでブロードキャストレシーバとして登録します。BROADCAST_MSGアクションはサービスがブロードキャストを発行する際にも使用していたことを思い出してください。これにより、このブロードキャストレシーバがFeedServiceの発行するブロードキャストを受け取ることが可能になります。

 FeedServiceを明示的に指定したインテントを生成し、startServiceメソッドでサービスの開始を行い、bindServiceでこのアクティビティとサービスをバインドしています。

 インターフェースIFeedReceiver唯一のメソッドであるfeedReceivedを追加します。

 サービスがRSSフィードの取得を完了し、ブロードキャストを発行するとブロードキャストレシーバを通じてこのメソッドが呼び出されます。サービスが取得したRSSフィードを読み取ってリスト化するため、ListGenerateTaskを実行します。

 ListGenerateTaskは後ほど作成しますが、HttpAccessTask同様にバックグラウンド処理としてbackgroundProc、後処理としてpostProcメソッドを呼び出します。HttpAccessTaskから呼び出される両メソッドを置き換える形で、ListGenerateTask用に修正を加えていきます。

 修正後のbackgroundProcメソッドがリスト5-16になります。

 空のFeedListを生成したら、サービスバインダーのlockListによりサービスが保持するRSSフィードリストをロックします。これにより、リストの取得中にリストの差し替えがおきることを防いでいます。
 ロックに成功したらフィードの数を取得し、フィード数分のフィード情報をサービスから取得してFeedItemを生成、先程作成したFeedListに追加します。全てのフィードを追加し終えたら、unlockListでサービスのRSSフィードリストをアンロックします。

 postProc(リスト5-17)ではバックグラウンドで生成したリストをチェックし、フィード数が0でなければFeedAdapterを生成し、アクティビティのリストに設定します。これによりサービスがバックグラウンドで取得したRSSフィードがリストに表示されます。

 最後にListGenerateTaskを作成します。ベースクラスをAsyncTask、テンプレートをITaskEntity, Integer, VoidとしてListGenerateTaskを生成し、リスト5-18のように修正します。

 実際の処理はアクティビティに実装されたbackgroundProc/postProcが行うため、HttpAccessTaskとの違いはプログレスダイアログの有無のみとなっています。

 以上で全ての実装は完了です。実行して動作を確認してみて下さい。

6-4. ウィジェット対応版RSSReader全ソースコード/AIDLファイル/XMLファイル


内藤

BC::labsへの質問は、bc9-dev @ googlegroups.com までお願い致します。
トップ   新規 一覧 単語検索 最終更新   最終更新のRSS