2015年1月30日金曜日

AppWidgetProviderのonDeletedのバグ

AppWidgetProviderクラスのonDeletedには概知のバグがありonDeletedが呼ばれるタイミングで呼び出されないというバグがあるそうです。
この現象はonReceiveメソッドをオーバーライドすることで回避可能なのでドキュメントにもその実装のコードが記されています。
しかしながら、本格的に対応を行うとどうしても実行時のAPI実装Levelを元にして処理を分岐させる必要があり、そのためにバージョンチェックを行おうとして前回の記事に至りました。



最終的にはAndroid1.5以前を考えるとバージョンチェックですら厳しいものがありました。


Build.VERSION.SDK_INT API Level 4

AppWidgetProvider API Level 3

非推奨となっているBuild.VERSION.SDKを利用するか、ターゲット環境としてAndroid1.5以前のものを除外するしかありません。
そしてAndroid1.5を除外するとonDeleteのバグは存在しなくなるので、対応するコードも必要もありません。

私が今回作っているウィジェットはonDeleteの必要が無いので問題ありませんでしたが、onDeleteを必要とする処理の場合は対応方法を悩むことになりそうです。

ためしに実装したコードはこんな感じになりました。

public class DispSSIDWidgetProvider extends AppWidgetProvider {
    private String TAG = "DispSSIDWidgetProvider";

    :
    :


    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "onReceive");
        final String action = intent.getAction();
        //if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {
        //Build.VERSION.SDK_INT は API Level4からなので.SDKを使用する。
        if(Build.VERSION.SDK.equals("3") && AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {
            Log.d(TAG, "onReceive for 1.5 bug fix code.");
            //final int appWidgetId = extras.getInt
            final int appWidgetId = intent.getIntExtra(
                    AppWidgetManager.EXTRA_APPWIDGET_ID,
                    AppWidgetManager.INVALID_APPWIDGET_ID);
            if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
                this.onDeleted(context, new int[] { appWidgetId });
            }
        } else {
            super.onReceive(context, intent);
        }
    }

    @Override
    public void onDeleted (Context context, int[] appWidgetIds){
        Log.d(TAG, "onDeleted");
        if(appWidgetIds == null) {
            Log.d(TAG, "appWidgetIds is NULL");
        }else{
            String ids = "";
            for( int i: appWidgetIds){
                ids = ids + i;
            }
            Log.d(TAG, "appWidgetIds [" + ids + "]");
        }
        super.onDeleted(context, appWidgetIds);
    }

    :
    :
}

バージョンチェックを行わない場合はonDeleteが2度呼ばれるようになったりするはずなのでonReceiveかonDeletedでの追加判定処理か、複数回onDeleted されても大丈夫なように設計する必要があります。


そもそも実装にonDeleteの処理が必要な形にするウィジェットを作るようにすることが一番賢明なのかもしれません。
今回作成したクラスは、この対応を行うために実装を始めてみましたが、最終的にはonDeletedは不要だったので、全く不要になってしまいました。

0 件のコメント:

コメントを投稿