2013年4月10日水曜日

ウィジェット基本

■実装の基本
(1)AppWidgetProviderクラスを継承した独自クラスを作成する
AppWidgetProviderで用意されているpublic methodは6つあります。
その中から必要なメソッドをオーバーライドして独自クラスを作成します。

・onEnabled(Context context)
一番最初のウィジェットが作成された時に呼ばれます。
ホームスクリーン上に複数ウィジェットを作成した時、一番最初に作成したウィジェットのみ
このメソッドが呼ばれます。

・onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
ウィジェットが作成された時、またはAppWidgetProviderInfoオブジェクトの
android:updatePeriodMillisに指定した時間が経過した時に呼ばれます。

・onDeleted(Context context, int[] appWidgetIds)
ウィジェットが削除された時に呼ばれます(※)

・onDisabled(Context context)
一番最後のウィジェットが削除された時に呼ばれます。
ホームスクリーン上に複数ウィジェットを作成されている時、一番最後に削除した
ウィジェットのみこのメソッドが呼ばれます。

・onAppWidgetOptionsChanged(Context context,
AppWidgetManager appWidgetManager,
int appWidgetId,
Bundle newOptions)
API Level16(Android4.1)から追加されたメソッドで、ウィジェットのサイズが変更された時、
またはウィジェットをホームスクリーンに配置した時に呼ばれます。

・onReceive(Context context, Intent intent)
ブロードキャストされたインテントを受信した時に呼ばれます。
AppWidgetProviderクラスでブロードキャストされたインテントのアクションによって
上記5つのメソッドのどれを呼ぶかハンドリングしているため、通常は使用することのない
メソッドです(※)。

※Android1.5においてonDeleted()メソッドが呼ばれるべき時に呼ばれないバグがあります。
回避手段としてonRecevie()メソッドをオーバーライドして、onDeleted()メソッドを呼んであげる
必要があります。
【参考】
http://developer.android.com/guide/topics/appwidgets/index.html
http://www.atmarkit.co.jp/fsmart/articles/android10/android10_2.html


(2)表示するウィジェットのレイアウトを定義する
/res/layout/配下にXMLファイルで定義します。
ウィジェットのレイアウトはRemoteViewsに基づくため、全てのレイアウトクラスやウィジェットクラスを
サポートしている訳ではありません。
ウィジェットでサポートしているレイアウトクラス、ウィジェットクラスは以下の通りです。

レイアウトクラス
・FrameLayout
・LinearLayout
・RelativeLayout

ウィジェットクラス
・AnalogClock
・Button
・Chronometer
・ImageButton
・ImageView
・ProgressBar
・TextView


(3)AppWidgetProviderInfoオブジェクトの定義
/res/xml/配下にXMLファイルを作成しエレメントを使って定義します。
設定する基本的な項目は以下の通りです。

・android:minWidth
・android:minHeight
ホームスクリーン上に配置するウィジェットの最小領域をdp(dip)で指定します。
Androidのホームスクリーンは、ウィジェットやアイコンを綺麗に配置させるため、
通常であればスマートフォンは4×4、タブレットは8×7のセルに分割されています。
ウィジェットを配置する最小領域は1セルとなりますが、指定する値はdpで指定する
必要があります。
デバイスにより異なりますが、ウィジェットの最小領域(1セル)は74dpとなります。
しかし、ホームスクリーン上に配置する際、dpからpxへの変換が行われるため、
変換の丸め誤差を考慮すると指定するdpの値には、以下の計算式を当てはめます。

(セルの数×74dp)-2dp

例えば1セルの領域に配置したい場合は72dp以下を指定し、2セルの領域に配置したい場合は
146dp以下を指定します(※)。
なお、指定する値は30dpでも1dpでも、72dpを超えなければ1セルに配置されます。
Androidのサンプルソースでは以下のコードとなっていました。
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="60dp"
    android:minHeight="30dp"
    android:updatePeriodMillis="86400000"
    android:initialLayout="@layout/appwidget_provider"
    android:configure="com.example.android.apis.appwidget.ExampleAppWidgetConfigure"
    android:resizeMode="horizontal"
    >
</appwidget-provider>


Android4.0以降は配置するウィジェットの上下左右にマージンが付加される為、
1セルに配置したい場合は64dp以下を指定する必要があり、nexus7の端末は
79dp以下を指定する必要があるようです。
【参考】
http://d1skroid.blogspot.jp/
http://developer.android.com/guide/practices/ui_guidelines/widget_design.html


・android:updatePeriodMillis
ホームスクリーン上に配置したウィジェットを更新する間隔をミリ秒で指定します。
最小値は1800000です(30分)。
端末がスリープ状態でもupdatePeriodMillisで更新が行われる時は、スリープ状態が解除されます。
30分未満の間隔で更新したい場合や、スリープ状態が解除されてしまうのを回避したい場合は、
AlarmManagerを使用するのが一般的です。
なお、0を指定するとウィジェットの更新は行われません。

・android:initialLayout
ホームスクリーン上に配置した際のレイアウトファイルを指定します。


(4)マニフェストの設定
AppWidgetProviderクラスを継承した独自クラスをブロードキャストレシーバとして定義します。
APPWIDGET_UPDATEブロードキャストインテントを受信出来るようにに指定します。
APPWIDGET_UPDATEのみ指定すれば、他のAPPWIDGET_DELETEDや
APPWIDGET_ENABLEDなどのブロードキャストインテントも受信出来るようになります。

<receiver android:name="com.aez.example.appwidget.provider.ExampleAppWidgetProvider">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
    </intent-filter>
    <meta-data android:name="android.appwidget.provider" android:resource="@xml/example_appwidget_info"/>
</receiver>