私のアプリケーションは、Web サービス呼び出しを介してリモート データベースとデータを同期します。バックグラウンドで実行できるように、IntentService でこれらの呼び出しを行います (これを SyncService と呼びます)。
IntentService を起動するコードは次のようになります。
Intent intent = new Intent();
intent.setClass(appContext, SyncService.class);
// place additional values in intent
intent.putExtra("data_type", SyncService.ITEM_TRACKING);
intent.putExtra("user_id", intUserId);
// call SyncService
appContext.startService(intent);
これは、通常、見栄えがします。しかし、私のアプリのユーザーでもある私の友人の 1 人は、データが同期されず、私たちの Web サイトに表示されないとよく言います。彼のデバイスは、私がそばにいる間にたまたま症状を示していました。彼のデバイスを自分のコンピューターに接続したところ、次のような結果が得られました。
- SyncService を起動するコード (つまり、上記のコード) がヒットしました。
- IntentService の onHandleIntent メソッド内にブレークポイントがあり、ヒットすることはありません。
- 彼のデバイスの実行中のサービスのリストを確認したところ、SyncService がそこにあり、実行されていました。興味深いことに、それは約 20 分間実行されていました。私は、処理するインテントがすべてなくなったときに IntentService が自分自身を殺したという印象を受けました。
- (アプリではなく) SyncService を強制停止したところ、突然、onHandleIntent が何度もヒットし始めました。すべてのインテントがデバイスのどこかにキューに入れられ、SyncService でスローされているようでした。
何が問題なのかについて誰か考えがありますか? 私のアプリの問題だと思いますか?アンドロイドで?
繰り返しになりますが、「この IntentService を開始するか、既に実行中の IntentService にメッセージを送信してください」というメッセージを Android に渡しています。その時点で、私はコントロールできません。メッセージが IntentService に到達することはありません。アプリを強制終了すると、メッセージが IntentService に送信され、その仕事が行われます。
更新: このコードは問題ないと思いますが、多くの人が見たいと思うかもしれないので掲載します。
IntentService に着信するすべてのインテントには、自分に対する呼び出しの「タイプ」を示す Extra があります (つまり、このWeb サービスを呼び出すか、そのWeb サービスを呼び出すかなど)。IntentService に Intent が来ると、「type」をチェックし、そのタイプの Intent がキューに既にある場合は、それに「skip」という Extra を追加します。検索を実行します (基本的に、IntentService は多くの Intent を構築することができ、この Web サービスが 20 秒前に呼び出されたときにこの Web サービスを呼び出すことは意味がありません)。基本的に、アプリをウェブサイトへのスパムから保護します。
いずれにせよ (問題が発生し始めると)、このコードはヒットしないことに注意することが重要です。onStartCommand は、アプリが強制終了されるまで呼び出されません
@Override
public int onStartCommand (Intent intent, int flags, int startId) {
// here be dragons
// overriding this method and adding your own code is dangerous. i've wrapped
// my code in a try/catch because it is essential that the super method be called
// every time this method is entered. any errors in my code should not prevent this
// or the app will explode.
try {
if (flags == 0 && intent != null && intent.hasExtra("data_type")) {
Integer intDataType = intent.getExtras().getInt("data_type");
if (!mCurrentTypes.containsKey(intDataType)
|| !mCurrentTypes.get(intDataType)) {
mCurrentTypes.put(intDataType, true); // put this type in the list and move on
}
else {
intent.putExtra("skip", true); // mark this Intent to be skipped
}
}
}
catch (Exception e) {
// Log.e("Error onStartCommand", "error: " + e);
}
return super.onStartCommand(intent, flags, startId);
}
private void processIntent(Intent intent) {
// do stuff if no "skip" Extra
mCurrentTypes.put(intDataType, false);
}