android.net.conn.CONNECTIVITY_CHANGE
接続が回復したときに appwidget を更新できるように、リッスンしているレシーバーがあります。これは、次の方法で受信機を有効または無効にしたときに奇妙な動作が発生することを除いて、正常に機能します。
ComponentName receiver = new ComponentName(this, NetworkStateReceiver.class);
PackageManager pm = getPackageManager();
pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
状態が変更android.appwidget.action.APPWIDGET_UPDATE
されると、appwidget のレシーバーへのブロードキャストも受信し、接続が失われたことを検出した後に appwidget が再度更新され、接続が返されたときに 2 回 (1 回は NetworkStateReceiver から意図的に、次に再びブロードキャストからAPPWIDGET_UPDATE
) 更新されます。
また、これは 4.04 デバイスでのみ発生し、2.1 デバイスでは発生しないようです。
NetworkStateReceiver と AppWidgetProvider のマニフェスト
<receiver
android:name=".AppWidgetProvider"
android:label="@string/widget_name" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/appwidget" />
</receiver>
<receiver
android:name=".NetworkStateReceiver"
android:enabled="false">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
これを回避するためにいくつかの方法を試しましたが、どれもあまり良い解決策ではありません。
APPWIDGET_UPDATE
ブロードキャストからの更新は無視できます。appwidget のすべての更新は、最初に作成されたときにアラーム マネージャーまたは構成アクティビティを介してサービスを介して行われるため、実際には既にこれを行っています。ただし、いくつかの理由で (そしておそらく何が起こっているかを示しています)、APPWIDGET_UPDATE
ブロードキャストにより、リモートビューが初めて追加されたときのような XML 状態に戻ります。ビットマップを含む余分な状態を保存することで、おそらくそれも回避できます。理想的ではありません。
NetworkStateReceiver を有効/無効にする代わりに常にリッスンすることもできますが、これは Android の推奨事項に反し、不要なブロードキャストを意味するという正当な理由があります。
他のアイデア?
編集:私の現在の回避策の詳細な説明。
APPWIDGET_UPDATE
アラームを使用して更新をトリガーしているにもかかわらず、ブロードキャストを無視することはできません。これはAPPWIDGET_UPDATE
、初めてホーム画面に追加されたように、ウィジェットも初期状態にリセットされるためです。接続がある場合は、すべての情報を再入力できるため、二重の更新を行うことができます。バグはデバイス固有のようで、影響を受けていないデバイスにはまだ更新が必要なため、私も独自の更新を行う必要があります。
接続できない場合は、以前に保存した状態からウィジェットを復元します。これは、更新が成功するたびに、すべてを SharedPreferences にも保存することを意味します。これにより、データを適切に再入力するためにインターネットが利用できない場合に、これらの「強制更新」のいずれかで復元できます。
私のAppWidgetProvider
中では(簡略化):
Intent intent = new Intent(context, WidgetUpdateService.class);
intent.putExtra("loadFromSaved", true); // this will be false when coming from AlarmManager
context.startService(intent);
WidgetUpdateService.onStartCommand() (これも簡略化):
if (intent.getExtras().getBoolean("loadFromSaved") {
widgetLoader.loadFromSavedData();
} else {
widgetLoader.load()
}