1

バックグラウンドで長時間実行される画像処理を実行する必要があるAndroidアプリがあります(その多くのチャンクを処理します)

  • WorkManager を使用してタスクを実行しました
  • ユーザー通知を使用して進行状況を通知します

バージョン

  • API レベル 28
  • オレオを実行している電話
  • androidx.work:work-runtime:2.1.0

WorkManager は次のようにセットアップされます (簡略化されたコード)

@NonNull
@Override
public Result doWork() {
    // 1 Create a NotificationChannel with unique ID
    // 2 read params from getInputData
    // 3 create as many instances of a class 
    //     that extends Callable<String> as there are small subtasks
    // 4 add all these tasks to a ThreadPoolExecutor and call
    //     invokeAll() which blocks the main Worker thread as required
    //     by the WorkManager API
    // 5 Everytime a subtask finishes, update the notification progress
}

@Override
public void onStopped(){
    // Call .shutDown() on the ThreadPoolExecutor
}

作品自体は以下のパラメータで提出されます

WorkManager mWorkManager = WorkManager.getInstance(context);
Data input = new Data.Builder()
                 .putString(PARAM_IN_DTO, dto.toString())
                 .build();
OneTimeWorkRequest mRequest = new OneTimeWorkRequest
                 .Builder(ExtractorWorker.class)
                 .setInputData(input)
                 .addTag(dto.mapName)
                 .build();
mWorkManager.enqueueUniqueWork(
                 WORK_NAME,
                 ExistingWorkPolicy.KEEP,
                 mRequest);

上記WORK_NAMEのコードに固有であるため、2 つのタスクが同時に実行されることはないと予想されます (ExistingWorkPolicy.REPLACE同じ問題で試したことに注意してください) 。

ジョブが正しく開始され、通知の進行状況が更新され始めます。しばらくすると、前のタスクがまだ実行されている状態で、タスクが再び開始されたようです。nowこれは、2 つの状態 (通知年齢と前の年齢の間、および 0% と前の進行状況の間の進行状況) の間で切り替わる固有の通知からわかります。同じ通知を更新する 2 つのタスクが明らかになりました。一意の通知 ID ではなくランダムな通知 ID を設定することでこれを確認したところ、2 つの通知が表示され、それぞれが独自の生活を送っています。

私は疑問に思う

  • 前のタスクがまだ実行中で、アプリから何も要求していないのに、WorkManager がこのタスクを再度送信するのはなぜですか?
  • 1つだけを送信した場合、同時に2つのジョブが実行されるのはどうすればよいですかenqueueUniqueWork
4

2 に答える 2

0

私は今、行動を理解していると思います。ジョブを中断したい場合WorkManager(後で再開する場合)onStopped()は、非常に短いタイムアウトで呼び出されます。executor.shutDown()呼び出しがこれを超えると、シャットダウンが正常に実行されない原因と思われる aがTimeoutExceptionスローされます。実行は続行されます。

このタイムアウトが発生した後、doWorkが時間どおりに何も返さなかったため、WorkManager は結果値がretryまたはfailであると想定し、ジョブを内部エグゼキューターに再送信します。

つまり、2 つのジョブが並行して実行されないという保証はありません。が呼び出されたときにジョブを適切かつ迅速に停止できなかった場合でもonStopped、新しいジョブが送信されます。Workmanager は、executor 内のスレッドを直接管理せず、必要なときに適切に停止せず、再起動する可能性のあるジョブを中断しません。

この場合の解決策は、ジョブの内部状態をキャンセルに設定して、開始時にすぐに終了するようにすることでした。Executor が使い果たされると、ロック ファイルが削除されます。新しいプロセス (再開) は、ロック ファイルがなくなるのを待ってから、作業の状態を確認し、そこから再開します。

于 2019-08-10T12:51:04.267 に答える