Androidのホーム画面に常駐するアプリを作るには:Androidで動く携帯Javaアプリ作成入門(10)(3/3 ページ)
本連載で、SDKとEclipseを使ってAndroidの携帯端末で動くJavaアプリを作成し、Android Marketでの配布を目指しましょう
AppWidgetを指定した間隔ごとに実行するには
AppWidgetを指定した間隔ごとに実行するには、android:updatePeriodMillisを用いる処理方法があります。サンプルの「SlideShow」というウィジェットがこの方法を用いています。
ソースコードは、以下のようになっています。
public class SlideShow extends AppWidgetProvider { static int index = 0; int[] images = { R.drawable.g0, R.drawable.g1, R.drawable.g2, R.drawable.g3, R.drawable.g4, R.drawable.g5, R.drawable.g6, R.drawable.g7, }; @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.slide_show); remoteViews.setImageViewResource(R.id.ImageView01, images[index]); index = ++index % images.length; ComponentName thisWidget = new ComponentName(context, SlideShow.class); appWidgetManager.updateAppWidget(thisWidget, remoteViews); }
まず、必要なのがAppWidgetProviderクラスを継承して作らなければならないということです。そして、繰り返し呼び出されるonUpdate()メソッドをオーバーライドする必要があります。
やっていることは、onUpdate()メソッドが呼び出されるたびに、リソース内の画像をRemoteViesクラスを経由して順番に設定しています。画像を指定するindexがなぜstaticかというと、onUpdate()メソッドが呼び出されるたびに、このクラスのインスタンスが再生成されるためです。
AppWidgetでサービスを用いるには
通常は、コールバックメソッドではこういった処理は行わずに、サービスを起動して、サービス内で処理を行うようにします。サンプルの「WhatTimeIsItNow」というウィジェットがサービスを用いる最も簡単な例です。
ソースコードは、以下のようになっています。
public class WhatTimeIsItNow extends AppWidgetProvider { @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { Intent intent = new Intent(context, MyService.class); context.startService(intent); } public static class MyService extends Service { @Override public void onStart(Intent intent, int startId) { RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.what_time_is_it_now); remoteViews.setTextViewText(R.id.TextView01, new Date().toLocaleString()); ComponentName thisWidget = new ComponentName(this, WhatTimeIsItNow.class); AppWidgetManager manager = AppWidgetManager.getInstance(this); manager.updateAppWidget(thisWidget, remoteViews); } @Override public IBinder onBind(Intent intent) { return null; } } }
onUpdate()メソッドはサービスを起動するだけ、起動されたサービスは実行後即終了します。処理が軽くても重くても、常にこのようにサービスを起動して処理をするのが望ましいです。このサービスはAndroidManifest.xmlに登録されていなければなりません。サービスの登録方法は、連載第7回の「サービスを使用するための設定」を参照してください。
しかし、問題が多い
さて、WhatTimeIsItNowは、ホームスクリーンに1秒刻みのデジタル時計を表示するウィジェットですが、こんなウィジェットを作るのはお勧めできません。
- 1秒ごとにonUpdate()メソッドが呼び出される
- バックグラウンドでも(ウィジェットが隠れていても)1秒ごとにonUpdate()メソッドが呼び出される
- ほかのアプリの動作まで重くなる
- 電池の消耗が激しい
特に3.と4.は大きな問題です。
グーグルが公開しているサンプルは、1日1回だけインターネットに「今日の言葉」を取りにいってそれを表示するウィジェットです。確かに1日1回ぐらいであれば、まったく問題にならないので、私もandroid:updatePeriodMillisを用いるのであれば、多くても1時間に1回ぐらいの更新頻度に収めるのがよいのではないかと思います。
android:updatePeriodMillis以外の方法としてAlarmManagerを用いる方法もあるので、ここからは、AlarmManagerの使い方を説明します。
AppWidgetを指定した時間に実行するには
android:updatePeriodMillisをAlarmManagerに置き換えるメリットはいくつかあります。
- android:updatePeriodMillisと同じことができる(コーディングは必要)
- android:updatePeriodMillisと異なり期間を調整可能(コーディングだから)
要するに、設定ファイルに期間を指定すると、コーディングは必要ないけど細かい動作は変更できず、AlarmManagerを使用すると、コーディングは必要だけど細かく動作を設定できる、ということです。
サンプルの「AlarmManagerSample」というウィジェットが、AlarmManagerを使用する例です。このウィジェットは1時間に1度、0分0秒ちょうどに表示を更新する時報アプリです。
詳しくはソースファイル全体を見ていただくとして、ここではAlarmManagerを使用している個所にフォーカスして説明します。
private void setAlarm(Context context) { Intent alarmIntent = new Intent(context, AlarmManagerSample.class); alarmIntent.setAction(ACTION_START_MY_ALARM); PendingIntent operation = PendingIntent.getBroadcast(context, 0, alarmIntent, 0); AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); long now = System.currentTimeMillis() + 1; // + 1 は確実に未来時刻になるようにする保険 long oneHourAfter = now + interval - now % (interval); am.set(AlarmManager.RTC, oneHourAfter, operation); }
3行目のACTION_START_MY_ALARMは、自分で勝手に定義したアクションです。自分で送って自分で受け取るアクションなので、パッケージ名やクラス名を内部に含み、ユニークになるようにしています。
作成したIntentから「PendingIntent」を作成し、それをAlarmManagerに時刻とともに設定しています。AlarmManager#set(int, long, PendingIntent)メソッドの第1引数には、この場合はAlarmManager.RTCかAlarmManager.ELAPSED_REALTIMEのどちらかの定数を使用するのが望ましいです。これらを使用すると、デバイスをwake upしません。
このサンプルでは1時間おきにしていますが、例えば真夜中は頻度を減らしたり、逆に真夜中だから頻度を増やしたり、ということが、自分でコーディングしているからこそ可能になります。
なお、自分で自分にIntentを時刻指定で送信しているので、受信時に次の自分のためのIntentの準備を忘れないようにしてください。
今回、この連載で初めて出てきたPendingIntentというものは、Intentを文字通りペンディングするための便利な入れ物です。次に説明するクリックを用いた処理方法でも、このPendingIntentを使用します。
コラム 「タイミングを見計らってIntentを発信するPendingIntentとは」
PendingIntentは、Intentをタイミングを見計らって発信する便利なツールです。以下のような使い方が可能です。
- 時刻を指定してIntentを発信
- イベントハンドラの代わりにIntentを発信
また、PendingIntentの作り方によって、Intentの飛び先をあらかじめ決められます。
メソッド | 説明 |
---|---|
getActivity(…) | Activityを起動するPendingIntentの取得 |
getBroadcast(…) | ブロードキャストを投げるPendingIntentの取得 |
getService(…) | Serviceを起動するPendingIntentの取得 |
表3 PendingIntentのメソッド |
処理対象があらかじめActivityやServiceに絞り込めている場合、これらを使用するのが効果的です。今回のサンプルではsetBroadcast()メソッドとsetService()メソッドを使用しているので、ソースコード参照して使い方を習得してください。
AppWidgetをクリック時に実行するには
サンプルの「ClickSample」というウィジェットが、ウィジェットでクリックイベントを拾う例です。
テキスト部分またはボタンをクリックすると、現在時刻を表示するサンプルです。
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.click_sample); Intent clickIntent = new Intent(); clickIntent.setAction(ACTION_MY_CLICK); PendingIntent pendingIntent = PendingIntent.getService(this, 0, clickIntent, 0); remoteViews.setOnClickPendingIntent(R.id.TextView01, pendingIntent); remoteViews.setOnClickPendingIntent(R.id.Button01, pendingIntent);
上記コードは、RemoteViews経由でGUIコンポーネントにPendingIntentを設定している個所です。
まず、RemoteViewsを作成し、次にIntentを作成します。作成したIntentにはアクションを設定していますが、これはサービスでフィルタするためにユニークな文字列が必要です。パッケージ名やクラス名を組み合わせるのがよいでしょう。この文字列の内容でAndroidManifest.xmlにもフィルタを設定します。
次に、PendingIntentを作成します。作成したPendingIntentを、任意のGUIコンポーネントに設定すれば完了です。
これだけで、設定したGUIコンポーネントをクリックすれば、サービスにIntentが飛んできて、Service#onStart()メソッドが呼び出されます。
AppWidgetを使う際の2つの注意点
AppWidgetは開発者にとって制限があるものの、ホームスクリーンに常駐できるというメリットが開発者にとっても、エンドユーザーにとっても魅力的です。AppWidgetの設定画面をActivityで作成したり、PendingIntentを使用してActivityと連携させたり、サービスを使い捨てないようにしたりすることで、さらにウィジェットがパワフルになると思います。
最後に、本記事執筆中に気が付いた点を紹介して終わりにしようと思います。
ウィジェット起動時に空きスペースがない場合
ホームスクリーンにセルの空きがない状態でウィジェットを起動してしまったら、以下のようなメッセージは出ますが、その後表示がされないまま、ずっと裏で動いていることになります。
この状態になると、エンドユーザーはこの表示されないウィジェットを削除できず、またプログラム的にも表示させるようにすることはできません。このメッセージが出るのは、最初のonUpdate()メソッドが呼び出される前なので、「プログラム的に事前にチェックする」ということもできません。端末を再起動しても表示されない状態で起動したままです。さらに悪いことに、エンドユーザーは表示されていない状態でウィジェットが起動していることに気が付かないでしょう。
Android 1.5時点での、唯一この状態を打開する策は、該当のウィジェットをアンインストールすることだけです。
ほかのウィジェットの不具合の影響を受ける可能性がある
例えば、「Foo」というウィジェットがonUpdate()メソッドでNullPointerExceptionなどの例外などを発生させてしまった場合、「Bar」というウィジェットの動作が不安定になってしまうことがあるようです。
この場合、メッセージが出て、どのウィジェットに問題があるかはエンドユーザーが分かるかもしれないので(メッセージが不親切なので、推測しなければならない)、事態は空きスペースがないときより幾分ましです。
開発時に自分のウィジェットで例外を発生させてしまった場合、やはりその後の開発に支障をきたしてしまうことがあります。そうなった場合は、いったん該当のウィジェットを削除して、エミュレータを再起動すれば修復します。
- グーグルのAPIを使うときに欠かせないGoogle OAuthの作り方と使い方
- 細か過ぎて伝わってないけど開発者が知っておきたいAndroid Mの新機能まとめ
- 腕時計から電話をかけるAndroid Wearアプリの作り方
- Android Wear用アプリの花形、時計アプリ「Watch Face」の基本的な作り方
- Android 5.0発表&スマホと連動する音声認識Android Wearアプリの作り方
- ウェアラブル端末用Android Wearアプリ開発の基礎知識
- 変わらないと生き残れないAndroid Lの新機能まとめ
- Android WearやIoTで注目のAndroidセンサー機能8選
- ウェアラブル時代に見直したいAndroidの加速度/重力センサー、ジャイロスコープ
- あなたの知らないAndroid SDKの便利tools、14選まとめ
- Android 4.4のメモリ使用状況を把握する3つのツールの使い方
- Androidでリアルタイムマルチプレーゲームを開発するには
- 低性能端末でも使えるか? Android 4.4 KitKatの新機能39選
- もはや無料BaaS。ゲーム以外でも使いたくなるGoogle Play Game Servicesのデータ管理機能
- アプリにGoogle+のソーシャルグラフを持ち込めるGoogle Play Game Servicesの基礎知識
- あなたのアプリはクラウドにデータをバックアップできますか?
- Eclipse ADTに代わるIDEとなるか? Android Studioの基礎知識
- ActionBarで、アプリのUIはこんなにスマートになる
- Android 4.x時代のアプリにないと残念なActionBarとは
- 動的クラスローディングでAndroidアプリ“裏”開発
- Android 4.xのAndroidビームをアプリに組み込むには
- AndroidアプリでNFCタグを読み書きするための基礎知識
- 新タブレット時代を見据えるAndroid 4.2の新機能9選
- Androidからイヤフォンやヘルス機器とBluetooth通信するには
- Bluetoothを使ってAndroidアプリ同士で通信するには
- Androidアプリをアプリ内購読に対応してもうける方法
- 開発者が知らないと残念過ぎるAndroid 4.1の新機能36選
- Androidのプロセス間通信を自由自在にするAIDL
- Android 4.0のサービス/プロセス間通信の基本
- Androidアプリでマルチメディアを扱うための基礎知識
- Androidのウィジェットにノーティフィケーションするには
- Android 4.0で注目の顔認識をアプリに組み込むには
- Android 4.0でアプリ開発を始めるための環境構築
- 開発者が知らないと損するAndroid 4.0の新機能44選
- Android Compatibility packageで2.x系でもマルチサイズ対応
- Androidの画面の大きさの違いを解決するFragments
- Android 3.0の新APIで簡単ドラッグ&ドロップ実装
- 開発者が知って得するAndroid 2.3の新機能18選
- アニメーションでAndroidに独創的な画面エフェクトを
- Androidアプリで“アニメーション”するための基礎知識
- XMLレイアウトでAndroidアプリに“設定画面”を追加
- 開発者が知っておきたいAndroid 2.2の新機能12連発
- もはやケータイに必須のカメラをAndroidで制御しよう
- 地図/位置情報/GPSを使うAndroidアプリを作るには
- Android NDKでJNIを使用してアプリを高速化するには
- Android 2.1の新機能「Live Wallpaper」で作る、美しく燃える“待ち受け”
- iPhoneより多彩なAndroidのセンサをアプリで操作
- SurfaceViewならAndroidで高速描画ゲームが作れる
- Android 1.6のジェスチャーとテキスト読み上げを使う
- Androidのホーム画面に常駐するアプリを作るには
- Netbookにも広まるAndroidで、かつてないWeb体験を
- アプリを国際化してAndroid Marketから世界へ発信
- 常駐アプリが作成できるAndroidの“サービス”とは
- AndroidでSQLiteのDB操作をするための基礎知識
- Androidアプリの使いやすさを左右する5つのレイアウト
- 簡単でワクワクするAndroidウィジェット10連発!
- ブラウザや地図、ストリートビューの基、Intentとは?
- Androidアプリ作成の基本“Activity”とは何か?
- Android Market配布を目指しEclipseでHelloWorld!
Copyright © ITmedia, Inc. All Rights Reserved.