SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

AndroidのApp Widgetでユーザー操作を処理する

ユーザーイベントに反応するインタラクティブ機能を備えたApp Widgetを作成

  • X ポスト
  • このエントリーをはてなブックマークに追加

PendingIntentの処理

 PendingIntentは基本的に、IntentとstartActivity()broadcastIntent()などのターゲットアクションを組み合わせたラッパーオブジェクトです。前回の記事では、App Widgetに表示画面の変更を開始させるアラーム通知のために、PendingIntentを使いました。前回説明したとおり、App Widgetのインスタンスは複数存在する可能性があるので(図1では3つあります)、アプリケーションからそれぞれのインスタンスを区別できるようにするには、Intentが固有である必要があります。これを実現するにはUriフィールドにApp Widget IDを指定します。これによって、それぞれのApp Widgetに固有の時間間隔を指定できるようになります。

 以下のコードは、これと同じ方法でconfigIntentを作成し、時間遅延Activityを起動させます。それぞれのappWidgetIdでそれぞれのApp Widgetが起動されます。

  Intent configIntent =
     new Intent(context, ImagesWidgetConfiguration.class);
  configIntent.putExtra(
     AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
  configIntent.setData(Uri.withAppendedPath(Uri.Parse
     (ImagesWidgetProvider.URI_SCHEME + "://widget/id/"),
     String.valueOf(appWidgetId)));

 これで設定ボタンが動作するようになったので、今度は、次の画像へのスキップなどの別のボタンバー機能を追加します。次の画像へスキップするようRemoteViewsコントロールへ通知するには、App Widgetにステートの変更をブロードキャストします。

 一見、ボタンハンドラへ送信されるIntentの一部としてステート情報をエンコードすればいいように思えます。しかし、このApp Widgetは、Alarmから送信されるIntentによって、定期的間隔でも更新を行うことを忘れてはいけません。このIntentは変化せず、新しいステートを認識しません。この問題を解決するために、ACTION_WIDGET_CONTROLという新しいアクションタイプを作成し、IntentのUriにコマンドを追加します。次に、App WidgetのステートをSharedPreferencesに保存します。実際には、一般的なApp Widget実装の構造は単純なので、この処理でユーザーが感知するほどの遅延は発生しません。

 以下のヘルパーメソッドでは、新しいアクションタイプACTION_WIDGET_CONTROLを処理するPendingIntentを作成しています。

  private PendingIntent makeControlPendingIntent
     (Context context, String command, int appWidgetId) {
     Intent active = new Intent();
     active.setAction(ACTION_WIDGET_CONTROL);
     active.putExtra(
        AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
     Uri data = Uri.withAppendedPath(
        Uri.parse(URI_SCHEME + "://widget/id/#"+command),
        String.valueOf(appWidgetId));
     active.setData(data);
     return(PendingIntent.getBroadcast(context,
        0, active, PendingIntent.FLAG_UPDATE_CURRENT));
  }

 このコードブロックは、アクションACTION_WIDGET_CONTROL(単なる文字列)を持つ新しいIntentを作成します。次に、IntentのExtra値をApp Widgetの固有IDに設定します。それから固有のUriを作成し、目的のコマンドを追加します。これでこのIntentは、App WidgetホストからAndroidシステムにブロードキャストできるようになりました。このブロードキャストは、普通のApp Widgetコマンドを処理するのと同じブロードキャスト受信先で処理されます。

 App Widgetは、これらのブロードキャストをonReceive()ハンドラメソッド内で受信できます。

  else if (ACTION_WIDGET_CONTROL.equals(action)) {
     final int appWidgetId = intent.getIntExtra(
        AppWidgetManager.EXTRA_APPWIDGET_ID,
        AppWidgetManager.INVALID_APPWIDGET_ID);
     if (appWidgetId !=
        AppWidgetManager.INVALID_APPWIDGET_ID) {
        this.onHandleAction(
           context, appWidgetId, intent.getData());
  }

 当該アクションの着信ブロードキャストを処理するには、この新しいアクションタイプと比較します。一致した場合、対象App Widgetインスタンスにコマンドを送信します。

ステートの処理

 ユーザー操作に基づいてIntentオブジェクトをApp Widgetに渡す方法、およびそれを検出する方法がわかったので、今度は要求された操作を処理します。これには次のタスクを実行します。

  1. 対象のRemoteViewsインスタンスを取得する
  2. そのステートを取得して変更する
  3. それらの変更をRemoteViewsコントロールに反映する
  4. 対象のApp Widgetに変更を反映するupdateAppWidget()メソッドを呼び出す

 これらの各タスクを処理するコードの例は、この記事のダウンロード可能なソースコードのonHandleAction()メソッドとupdateDisplayState()メソッドにあります。

 RemoteViewsコントロールは、更新されるたびに元のレイアウトから再作成されています。そこで今度はクリックハンドラを使用します。App Widgetの現在のステートに基づき、前に設定Activityアクションを追加したのと同じようにして、必要なクリックハンドラを追加します。これらのハンドラのコードも、ソースコードのupdateDisplayState()メソッドで確認できます。

レイアウトの更新

 App Widgetの下部にボタンバーが描画されるようにするには、2つのFrameLayoutコントロールを使用します。外側のFrameLayout(このApp Widget全体を占めるレイアウト)に、表示するImageViewと、ボタンバー用のもう1つのFrameLayoutを含めます。このもう1つのFrameLayoutは親レイアウトの下部に描画されるようにし、そこに、設定、再生/停止、次の画像、の3つのImageButtonコントロールを配置します。このボタンバー用FrameLayoutは、可視属性をGONEに設定すればビューから非表示にできます。完成したレイアウトファイル(widget.xml)は、この記事で提供するサンプルコードで確認できます。

Androidマニフェストファイルの更新

 最後に、この新しいアクションタイプを処理できるということをシステムに知らせるため、AndroidManifest.xmlファイルを更新して適切なインテントフィルタを追加します。

  <receiver android:name=".ImagesWidgetProvider">
     <intent-filter>
        <action android:name=
           "com.mamlambo.ImagesWidget.WIDGET_CONTROL" />
        <data android:scheme="images_widget" />
     </intent-filter>
  </receiver>

 このインテントフィルタは、アクションタイプがACTION_WIDGET_CONTROLであるブロードキャストIntentをウォッチするようにアプリケーションに指示します。その値が"com.mamlambo.ImagesWidget.WIDGET_CONTROL"です。

まとめ

 App Widgetは、Androidユーザーにまったく新しい体験を提供します。静的なApp Widgetだけでなく、クリックなどのユーザーイベントに反応するインタラクティブ機能を備えたApp Widgetも作成できます。この記事では、AndroidのApp Widgetにユーザー操作処理を追加する方法を紹介しました。これに伴い、PendingIntentを使ってRemoteViewsとやり取りする方法も説明しました。最後に、Intentメカニズムの制約とその回避方法を説明して、ユーザーがホーム画面から離れずに操作できるApp Widgetを作成する方法を解説しました。

 パート1「Androidのホーム画面用App Widgetを作成する原文)」も併せて参照ください。

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Shane Conder(Shane Conder)

 モバイル技術やウェブ技術を得意とするソフトウェア開発者(現在は小さなモバイルソフトウェア会社に勤務)。先日、Androidプログラミングに関する詳しい解説書『Android Wireless Application Development』を、同じく開発者であるLauren Darceyと共同執筆...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/4496 2009/11/11 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング