8

私のウィジェットは、2つのボタンとデータを表示するリストビューで構成されています。ほとんどの場合、ウィジェットプロバイダーのonUpdateメソッドが呼び出されると、すべてが正常に読み込まれ、全員が満足します。

ただし、updateメソッドが呼び出された後、ウィジェットがデータの読み込みに完全に失敗することがあります。リストビューは空で、すべてのボタンが応答しません。レイアウトをウィジェットに初期化したかのようですが、保留中のインテントもリストのアダプターも設定されていません。

私はすべてを記録しましたが、そうではないことがわかりました。保留中のインテントは、リストアダプターと同様に、失敗したときのランダムな時間を含め、毎回作成されます。長い間、リストデータがアダプターに入力される方法に関係していると思っていましたが、ボタンインテントも機能しないという事実と相まって、毎回機能することを確認すると、メソッドupdateAppWidgetを信じることになります。 (ComponentName、RemoteViews)が失敗しています。ただし、これを確認するのに役立つエラースタックはありません。

AppWidgetProviderのonUpdateメソッドによって呼び出される別のサービスで実行されるコードは次のとおりです。

@SuppressWarnings("deprecation")
private void updateWidget(int[] ids) {

    AppWidgetManager widgetManager = AppWidgetManager.getInstance(this);
    int[] widgetIds = widgetManager.getAppWidgetIds(new ComponentName(this, WidgetReceiver.class));

    for (int currentWidgetId : widgetIds) {

        RemoteViews widget = new RemoteViews(this.getPackageName(), R.layout.widget_layout);

        Intent intent = new Intent(this, WidgetService.class);
        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, currentWidgetId);
        intent.putExtra("random", randomNumber);
        randomNumber++;
        intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));

        widget.setRemoteAdapter(currentWidgetId, android.R.id.list, intent);

        Intent clickIntent = new Intent(this, DetailsActivity.class);
        PendingIntent pending = PendingIntent.getActivity(this, 0, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        widget.setPendingIntentTemplate(android.R.id.list, pending);

        Intent settingsIntent = new Intent(this, WidgetSettingsActivity.class);
        settingsIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        PendingIntent settingsPending = PendingIntent.getActivity(this, 0, settingsIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        widget.setOnClickPendingIntent(R.id.widget_settings, settingsPending);

        Intent mainIntent = new Intent(this, MainActivity.class);
        PendingIntent mainPending = PendingIntent.getActivity(this, 0, mainIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        widget.setOnClickPendingIntent(R.id.widget_logo, mainPending);

        ComponentName widgetCompName = new ComponentName(this, WidgetReceiver.class);
        widgetManager.updateAppWidget(widgetCompName, widget);
    }
}

このバグで最もイライラするのは、確実に再現できないことです。時々私は(不)幸運になり、それは醜い頭を示します、他の時には(ほとんどの場合)それは完全に機能します。

私が面白いと思ったもう1つのことは、Facebookのウィジェットでまったく同じ問題が発生したことです。NDAが原因で、失敗したときにアプリの画面を表示できませんが、Facebookと同じ問題の画面を表示できます。

Facebookは失敗する

Facebookのウィジェットがこのように見えるとき、それは私のものとまったく同じ問題を抱えています。データがロードされておらず、すべてのボタンが応答していません。

Facebookと私のウィジェットの両方で、その後の更新間隔により、通常、問題は解消されます。

これに遭遇しているのは私だけではないことを感謝していますが、これを修正するまでリリースしたくありません。ここで誰かがこれに遭遇し、それでも解決策、あるいは問題の原因さえ見つけたことがありますか?助けてくれてありがとう。

編集:何か面白いもの。更新間隔を30分ごとではなく1日に設定する実験を実行しました。私の仮説は、おそらく更新メソッドが原因ではなく、ウィジェットが空白になり応答しなくなった原因であるというものでした。

案の定、約2時間後、更新メソッドが呼び出されていないにもかかわらず、電話をチェックしたところ、ウィジェットが機能していませんでした。widgetManager.updateAppWidget(widgetCompName, widget);これは、私が以前考えていたように、何か他のものがこの問題を引き起こしていると私に信じさせるでしょう。

構成を変更するとウィジェットが再構築される可能性があるため、失敗する可能性があることを私は知っています。ただし、必要に応じて、ServiceクラスのonConfigurationChangedメソッドを使用してウィジェットをリロードしています。ウィジェットがそれ自体を破壊して再作成する原因となる構成変更のような別のケースはありますか?

4

1 に答える 1

5

たくさんの血、汗、涙の後、私は解決策を見つけました。エラーが再発しないように、この回答の確認を数日間延期しますが、多くの観察の結果、解決されたと思います。

だから私は元の質問の編集されたコメントに正しかった。問題を引き起こしたのはAppWidgetManagerの更新メソッドではなく、アプリウィジェットがそれ自体を再作成する原因となった他のAndroidプロセスでした。残念ながら、そのトリガーを分離することはできませんでしたが、解決策を見つけました。

私のRemoteViewsFactoryクラス(基本的にはデータセットをロードするために使用されるラッパー)には、次のようなコードのブロックがありました。

RemoteViews views = new RemoteViews(mContext.getPackageName(), R.layout.widget_layout);
if(mItems.size() == 0)
    views.setViewVisibility(R.id.widget_empty, View.VISIBLE);
else
    views.setViewVisibility(R.id.widget_empty, View.GONE);

AppWidgetManager manager = AppWidgetManager.getInstance(mContext);
ComponentName widgetCompName = new ComponentName(mContext, WidgetReceiver.class);
manager.updateAppWidget(widgetCompName, views);

基本的に、リストが空の場合は、リストビューが配置されている領域全体を占める読み込みメッセージを表示しました。リストが空でない場合は、そのメッセージを非表示にします。

つまり、これが起こっていたのです。ファクトリが(おそらくメモリの目的で)破壊されたとき、ウィジェット自体は破壊されていませんでした。そのため、データなどのインテントを設定するすべてのコードが実行されませんでした。ただし、ファクトリが再作成され、新しいリモートビューオブジェクトでアプリウィジェットを更新するコードのブロックが実行されました。このリモートビューオブジェクトは、最初に投稿したonUpdate()メソッドに表示されるメソッドを実行しなかったため、すべての機能が機能しませんでした。

話の教訓:updateAppWidgetRemoteViewsFactoryクラスでは使用しないでください!これで、必要なすべての行を実行すれば機能する可能性がありますが、確認できません。

于 2012-11-16T00:33:33.887 に答える